Browse code

Merge pull request #37358 from kolyshkin/go111

Bump golang to 1.11.0

Sebastiaan van Stijn authored on 2018/09/07 17:35:33
Showing 76 changed files
... ...
@@ -24,10 +24,7 @@
24 24
 # the case. Therefore, you don't have to disable it anymore.
25 25
 #
26 26
 
27
-FROM golang:1.10.4 AS base
28
-# FIXME(vdemeester) this is kept for other script depending on it to not fail right away
29
-# Remove this once the other scripts uses something else to detect the version
30
-ENV GO_VERSION 1.10.4
27
+FROM golang:1.11.0 AS base
31 28
 # allow replacing httpredir or deb mirror
32 29
 ARG APT_MIRROR=deb.debian.org
33 30
 RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
... ...
@@ -1,5 +1,5 @@
1 1
 ## Step 1: Build tests
2
-FROM golang:1.10.4-alpine3.7 as builder
2
+FROM golang:1.11.0-alpine3.7 as builder
3 3
 
4 4
 RUN apk add --update \
5 5
     bash \
... ...
@@ -5,7 +5,7 @@
5 5
 
6 6
 # This represents the bare minimum required to build and test Docker.
7 7
 
8
-FROM debian:stretch
8
+FROM golang:1.11.0-stretch
9 9
 
10 10
 # allow replacing httpredir or deb mirror
11 11
 ARG APT_MIRROR=deb.debian.org
... ...
@@ -37,18 +37,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
37 37
 		vim-common \
38 38
 	&& rm -rf /var/lib/apt/lists/*
39 39
 
40
-# Install Go
41
-# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines
42
-#            will need updating, to avoid errors. Ping #docker-maintainers on IRC
43
-#            with a heads-up.
44
-# IMPORTANT: When updating this please note that stdlib archive/tar pkg is vendored
45
-ENV GO_VERSION 1.10.4
46
-RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
47
-	| tar -xzC /usr/local
48
-ENV PATH /go/bin:/usr/local/go/bin:$PATH
49
-ENV GOPATH /go
50
-ENV CGO_LDFLAGS -L/lib
51
-
52 40
 # Install runc, containerd, tini and docker-proxy
53 41
 # Please edit hack/dockerfile/install/<name>.installer to update them.
54 42
 COPY hack/dockerfile/install hack/dockerfile/install
... ...
@@ -161,7 +161,7 @@ SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPref
161 161
 # Environment variable notes:
162 162
 #  - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
163 163
 #  - FROM_DOCKERFILE is used for detection of building within a container.
164
-ENV GO_VERSION=1.10.4 `
164
+ENV GO_VERSION=1.11 `
165 165
     GIT_VERSION=2.11.1 `
166 166
     GOPATH=C:\go `
167 167
     FROM_DOCKERFILE=1
... ...
@@ -29,8 +29,8 @@ func TestStrSliceMarshalJSON(t *testing.T) {
29 29
 
30 30
 func TestStrSliceUnmarshalJSON(t *testing.T) {
31 31
 	parts := map[string][]string{
32
-		"":   {"default", "values"},
33
-		"[]": {},
32
+		"":                        {"default", "values"},
33
+		"[]":                      {},
34 34
 		`["/bin/sh","-c","echo"]`: {"/bin/sh", "-c", "echo"},
35 35
 	}
36 36
 	for json, expectedParts := range parts {
... ...
@@ -788,7 +788,7 @@ func NewDaemon(ctx context.Context, config *config.Config, pluginStore *plugin.S
788 788
 
789 789
 	for operatingSystem, gd := range d.graphDrivers {
790 790
 		layerStores[operatingSystem], err = layer.NewStoreFromOptions(layer.StoreOptions{
791
-			Root: config.Root,
791
+			Root:                      config.Root,
792 792
 			MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),
793 793
 			GraphDriver:               gd,
794 794
 			GraphDriverOptions:        config.GraphOptions,
... ...
@@ -156,7 +156,7 @@ func TestNewGELFTCPWriter(t *testing.T) {
156 156
 			"gelf-address":             url,
157 157
 			"gelf-tcp-max-reconnect":   "0",
158 158
 			"gelf-tcp-reconnect-delay": "0",
159
-			"tag": "{{.ID}}",
159
+			"tag":                      "{{.ID}}",
160 160
 		},
161 161
 		ContainerID: "12345678901234567890",
162 162
 	}
... ...
@@ -30,10 +30,10 @@ func TestValidateLogOpt(t *testing.T) {
30 30
 		splunkVerifyConnectionKey:     "true",
31 31
 		splunkGzipCompressionKey:      "true",
32 32
 		splunkGzipCompressionLevelKey: "1",
33
-		envKey:      "a",
34
-		envRegexKey: "^foo",
35
-		labelsKey:   "b",
36
-		tagKey:      "c",
33
+		envKey:                        "a",
34
+		envRegexKey:                   "^foo",
35
+		labelsKey:                     "b",
36
+		tagKey:                        "c",
37 37
 	})
38 38
 	if err != nil {
39 39
 		t.Fatal(err)
... ...
@@ -251,9 +251,9 @@ func TestInlineFormatWithNonDefaultOptions(t *testing.T) {
251 251
 			splunkIndexKey:           "myindex",
252 252
 			splunkFormatKey:          splunkFormatInline,
253 253
 			splunkGzipCompressionKey: "true",
254
-			tagKey:      "{{.ImageName}}/{{.Name}}",
255
-			labelsKey:   "a",
256
-			envRegexKey: "^foo",
254
+			tagKey:                   "{{.ImageName}}/{{.Name}}",
255
+			labelsKey:                "a",
256
+			envRegexKey:              "^foo",
257 257
 		},
258 258
 		ContainerID:        "containeriid",
259 259
 		ContainerName:      "/container_name",
... ...
@@ -1,6 +1,6 @@
1 1
 #!/bin/sh
2 2
 
3
-VNDR_COMMIT=a6e196d8b4b0cbbdc29aebdb20c59ac6926bb384
3
+VNDR_COMMIT=81cb8916aad3c8d06193f008dba3e16f82851f52
4 4
 
5 5
 install_vndr() {
6 6
 	echo "Install vndr version $VNDR_COMMIT"
... ...
@@ -130,7 +130,7 @@ Function Check-InContainer() {
130 130
 # outside of a container where it may be out of date with master.
131 131
 Function Verify-GoVersion() {
132 132
     Try {
133
-        $goVersionDockerfile=(Select-String -Path ".\Dockerfile" -Pattern "^FROM golang:").ToString().Split(" ")[1].SubString(7)
133
+        $goVersionDockerfile=(Select-String -Path ".\Dockerfile" -Pattern "^FROM golang:").ToString().Split(" ")[1].SubString(7) -replace '\.0$',''
134 134
         $goVersionInstalled=(go version).ToString().Split(" ")[2].SubString(2)
135 135
     }
136 136
     Catch [Exception] {
... ...
@@ -9,11 +9,7 @@ validate_vendor_diff(){
9 9
 	unset IFS
10 10
 
11 11
 	if [ ${#files[@]} -gt 0 ]; then
12
-		# Remove vendor/ first so  that anything not included in vendor.conf will
13
-		# cause the validation to fail. archive/tar is a special case, see vendor.conf
14
-		# for details.
15
-		ls -d vendor/* | grep -v vendor/archive | xargs rm -rf
16
-		# run vndr to recreate vendor/
12
+		# recreate vendor/
17 13
 		vndr
18 14
 		# check if any files have changed
19 15
 		diffs="$(git status --porcelain -- vendor 2>/dev/null)"
... ...
@@ -656,7 +656,7 @@ func (s *DockerSuite) TestBuildCopyWildcard(c *check.C) {
656 656
 			"file2.txt":                     "test2",
657 657
 			"dir/nested_file":               "nested file",
658 658
 			"dir/nested_dir/nest_nest_file": "2 times nested",
659
-			"dirt": "dirty",
659
+			"dirt":                          "dirty",
660 660
 		}))
661 661
 	defer ctx.Close()
662 662
 
... ...
@@ -37,8 +37,8 @@ func TestBuildWithRemoveAndForceRemove(t *testing.T) {
37 37
 			RUN exit 0
38 38
 			RUN exit 0`,
39 39
 			numberOfIntermediateContainers: 2,
40
-			rm:      false,
41
-			forceRm: false,
40
+			rm:                             false,
41
+			forceRm:                        false,
42 42
 		},
43 43
 		{
44 44
 			name: "successful build with remove",
... ...
@@ -46,8 +46,8 @@ func TestBuildWithRemoveAndForceRemove(t *testing.T) {
46 46
 			RUN exit 0
47 47
 			RUN exit 0`,
48 48
 			numberOfIntermediateContainers: 0,
49
-			rm:      true,
50
-			forceRm: false,
49
+			rm:                             true,
50
+			forceRm:                        false,
51 51
 		},
52 52
 		{
53 53
 			name: "successful build with remove and force remove",
... ...
@@ -55,8 +55,8 @@ func TestBuildWithRemoveAndForceRemove(t *testing.T) {
55 55
 			RUN exit 0
56 56
 			RUN exit 0`,
57 57
 			numberOfIntermediateContainers: 0,
58
-			rm:      true,
59
-			forceRm: true,
58
+			rm:                             true,
59
+			forceRm:                        true,
60 60
 		},
61 61
 		{
62 62
 			name: "failed build with no removal",
... ...
@@ -64,8 +64,8 @@ func TestBuildWithRemoveAndForceRemove(t *testing.T) {
64 64
 			RUN exit 0
65 65
 			RUN exit 1`,
66 66
 			numberOfIntermediateContainers: 2,
67
-			rm:      false,
68
-			forceRm: false,
67
+			rm:                             false,
68
+			forceRm:                        false,
69 69
 		},
70 70
 		{
71 71
 			name: "failed build with remove",
... ...
@@ -73,8 +73,8 @@ func TestBuildWithRemoveAndForceRemove(t *testing.T) {
73 73
 			RUN exit 0
74 74
 			RUN exit 1`,
75 75
 			numberOfIntermediateContainers: 1,
76
-			rm:      true,
77
-			forceRm: false,
76
+			rm:                             true,
77
+			forceRm:                        false,
78 78
 		},
79 79
 		{
80 80
 			name: "failed build with remove and force remove",
... ...
@@ -82,8 +82,8 @@ func TestBuildWithRemoveAndForceRemove(t *testing.T) {
82 82
 			RUN exit 0
83 83
 			RUN exit 1`,
84 84
 			numberOfIntermediateContainers: 0,
85
-			rm:      true,
86
-			forceRm: true,
85
+			rm:                             true,
86
+			forceRm:                        true,
87 87
 		},
88 88
 	}
89 89
 
... ...
@@ -168,9 +168,9 @@ func (c *client) Create(_ context.Context, id string, spec *specs.Spec, runtimeO
168 168
 func (c *client) createWindows(id string, spec *specs.Spec, runtimeOptions interface{}) error {
169 169
 	logger := c.logger.WithField("container", id)
170 170
 	configuration := &hcsshim.ContainerConfig{
171
-		SystemType: "Container",
172
-		Name:       id,
173
-		Owner:      defaultOwner,
171
+		SystemType:              "Container",
172
+		Name:                    id,
173
+		Owner:                   defaultOwner,
174 174
 		IgnoreFlushesDuringBoot: spec.Windows.IgnoreFlushesDuringBoot,
175 175
 		HostName:                spec.Hostname,
176 176
 		HvPartition:             false,
... ...
@@ -377,11 +377,11 @@ func (c *client) createLinux(id string, spec *specs.Spec, runtimeOptions interfa
377 377
 	}
378 378
 
379 379
 	configuration := &hcsshim.ContainerConfig{
380
-		HvPartition:   true,
381
-		Name:          id,
382
-		SystemType:    "container",
383
-		ContainerType: "linux",
384
-		Owner:         defaultOwner,
380
+		HvPartition:                 true,
381
+		Name:                        id,
382
+		SystemType:                  "container",
383
+		ContainerType:               "linux",
384
+		Owner:                       defaultOwner,
385 385
 		TerminateOnLastHandleClosed: true,
386 386
 	}
387 387
 
... ...
@@ -40,9 +40,9 @@ func TestMigrateRefs(t *testing.T) {
40 40
 	}
41 41
 
42 42
 	expected := map[string]string{
43
-		"docker.io/library/busybox:latest":                                                                  "sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9",
43
+		"docker.io/library/busybox:latest": "sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9",
44 44
 		"docker.io/library/busybox@sha256:16a2a52884c2a9481ed267c2d46483eac7693b813a63132368ab098a71303f8a": "sha256:fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9",
45
-		"docker.io/library/registry:2":                                                                      "sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
45
+		"docker.io/library/registry:2": "sha256:2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae",
46 46
 	}
47 47
 
48 48
 	if !reflect.DeepEqual(expected, ta.refs) {
... ...
@@ -69,18 +69,18 @@ func TestParseDockerDaemonHost(t *testing.T) {
69 69
 		"[::1]:5555/path":             "tcp://[::1]:5555/path",
70 70
 		"[0:0:0:0:0:0:0:1]:":          "tcp://[0:0:0:0:0:0:0:1]:2375",
71 71
 		"[0:0:0:0:0:0:0:1]:5555/path": "tcp://[0:0:0:0:0:0:0:1]:5555/path",
72
-		":6666":                   fmt.Sprintf("tcp://%s:6666", DefaultHTTPHost),
73
-		":6666/path":              fmt.Sprintf("tcp://%s:6666/path", DefaultHTTPHost),
74
-		"tcp://":                  DefaultTCPHost,
75
-		"tcp://:7777":             fmt.Sprintf("tcp://%s:7777", DefaultHTTPHost),
76
-		"tcp://:7777/path":        fmt.Sprintf("tcp://%s:7777/path", DefaultHTTPHost),
77
-		"unix:///run/docker.sock": "unix:///run/docker.sock",
78
-		"unix://":                 "unix://" + DefaultUnixSocket,
79
-		"fd://":                   "fd://",
80
-		"fd://something":          "fd://something",
81
-		"localhost:":              "tcp://localhost:2375",
82
-		"localhost:5555":          "tcp://localhost:5555",
83
-		"localhost:5555/path":     "tcp://localhost:5555/path",
72
+		":6666":                       fmt.Sprintf("tcp://%s:6666", DefaultHTTPHost),
73
+		":6666/path":                  fmt.Sprintf("tcp://%s:6666/path", DefaultHTTPHost),
74
+		"tcp://":                      DefaultTCPHost,
75
+		"tcp://:7777":                 fmt.Sprintf("tcp://%s:7777", DefaultHTTPHost),
76
+		"tcp://:7777/path":            fmt.Sprintf("tcp://%s:7777/path", DefaultHTTPHost),
77
+		"unix:///run/docker.sock":     "unix:///run/docker.sock",
78
+		"unix://":                     "unix://" + DefaultUnixSocket,
79
+		"fd://":                       "fd://",
80
+		"fd://something":              "fd://something",
81
+		"localhost:":                  "tcp://localhost:2375",
82
+		"localhost:5555":              "tcp://localhost:5555",
83
+		"localhost:5555/path":         "tcp://localhost:5555/path",
84 84
 	}
85 85
 	for invalidAddr, expectedError := range invalids {
86 86
 		if addr, err := parseDaemonHost(invalidAddr); err == nil || err.Error() != expectedError {
... ...
@@ -17,7 +17,7 @@ import (
17 17
 
18 18
 func TestPeerCertificateMarshalJSON(t *testing.T) {
19 19
 	template := &x509.Certificate{
20
-		IsCA: true,
20
+		IsCA:                  true,
21 21
 		BasicConstraintsValid: true,
22 22
 		SubjectKeyId:          []byte{1, 2, 3},
23 23
 		SerialNumber:          big.NewInt(1234),
... ...
@@ -144,7 +144,7 @@ func TestDrainBody(t *testing.T) {
144 144
 		length             int // length is the message length send to drainBody
145 145
 		expectedBodyLength int // expectedBodyLength is the expected body length after drainBody is called
146 146
 	}{
147
-		{10, 10}, // Small message size
147
+		{10, 10},                           // Small message size
148 148
 		{maxBodySize - 1, maxBodySize - 1}, // Max message size
149 149
 		{maxBodySize * 2, 0},               // Large message size (skip copying body)
150 150
 
... ...
@@ -16,11 +16,11 @@ import (
16 16
 
17 17
 var (
18 18
 	saveLoadTestCases = map[string]digest.Digest{
19
-		"registry:5000/foobar:HEAD":                                                        "sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6",
20
-		"registry:5000/foobar:alternate":                                                   "sha256:ae300ebc4a4f00693702cfb0a5e0b7bc527b353828dc86ad09fb95c8a681b793",
21
-		"registry:5000/foobar:latest":                                                      "sha256:6153498b9ac00968d71b66cca4eac37e990b5f9eb50c26877eb8799c8847451b",
22
-		"registry:5000/foobar:master":                                                      "sha256:6c9917af4c4e05001b346421959d7ea81b6dc9d25718466a37a6add865dfd7fc",
23
-		"jess/hollywood:latest":                                                            "sha256:ae7a5519a0a55a2d4ef20ddcbd5d0ca0888a1f7ab806acc8e2a27baf46f529fe",
19
+		"registry:5000/foobar:HEAD":      "sha256:470022b8af682154f57a2163d030eb369549549cba00edc69e1b99b46bb924d6",
20
+		"registry:5000/foobar:alternate": "sha256:ae300ebc4a4f00693702cfb0a5e0b7bc527b353828dc86ad09fb95c8a681b793",
21
+		"registry:5000/foobar:latest":    "sha256:6153498b9ac00968d71b66cca4eac37e990b5f9eb50c26877eb8799c8847451b",
22
+		"registry:5000/foobar:master":    "sha256:6c9917af4c4e05001b346421959d7ea81b6dc9d25718466a37a6add865dfd7fc",
23
+		"jess/hollywood:latest":          "sha256:ae7a5519a0a55a2d4ef20ddcbd5d0ca0888a1f7ab806acc8e2a27baf46f529fe",
24 24
 		"registry@sha256:367eb40fd0330a7e464777121e39d2f5b3e8e23a1e159342e53ab05c9e4d94e6": "sha256:24126a56805beb9711be5f4590cc2eb55ab8d4a85ebd618eed72bb19fc50631c",
25 25
 		"busybox:latest": "sha256:91e54dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c",
26 26
 	}
... ...
@@ -57,7 +57,7 @@ func (s *DefaultService) lookupV2Endpoints(hostname string) (endpoints []APIEndp
57 57
 				Scheme: "https",
58 58
 				Host:   hostname,
59 59
 			},
60
-			Version: APIVersion2,
60
+			Version:                        APIVersion2,
61 61
 			AllowNondistributableArtifacts: ana,
62 62
 			TrimHostname:                   true,
63 63
 			TLSConfig:                      tlsConfig,
... ...
@@ -70,7 +70,7 @@ func (s *DefaultService) lookupV2Endpoints(hostname string) (endpoints []APIEndp
70 70
 				Scheme: "http",
71 71
 				Host:   hostname,
72 72
 			},
73
-			Version: APIVersion2,
73
+			Version:                        APIVersion2,
74 74
 			AllowNondistributableArtifacts: ana,
75 75
 			TrimHostname:                   true,
76 76
 			// used to check if supposed to be secure via InsecureSkipVerify
... ...
@@ -22,20 +22,20 @@ func TestNetworkModeTest(t *testing.T) {
22 22
 		"something:weird":          {true, false, false, false, false, false},
23 23
 		"bridge":                   {true, true, false, false, false, false},
24 24
 		DefaultDaemonNetworkMode(): {true, true, false, false, false, false},
25
-		"host":           {false, false, true, false, false, false},
26
-		"container:name": {false, false, false, true, false, false},
27
-		"none":           {true, false, false, false, true, false},
28
-		"default":        {true, false, false, false, false, true},
25
+		"host":                     {false, false, true, false, false, false},
26
+		"container:name":           {false, false, false, true, false, false},
27
+		"none":                     {true, false, false, false, true, false},
28
+		"default":                  {true, false, false, false, false, true},
29 29
 	}
30 30
 	networkModeNames := map[container.NetworkMode]string{
31 31
 		"":                         "",
32 32
 		"something:weird":          "something:weird",
33 33
 		"bridge":                   "bridge",
34 34
 		DefaultDaemonNetworkMode(): "bridge",
35
-		"host":           "host",
36
-		"container:name": "container",
37
-		"none":           "none",
38
-		"default":        "default",
35
+		"host":                     "host",
36
+		"container:name":           "container",
37
+		"none":                     "none",
38
+		"default":                  "default",
39 39
 	}
40 40
 	for networkMode, state := range networkModes {
41 41
 		if networkMode.IsPrivate() != state[0] {
... ...
@@ -57,7 +57,8 @@ github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
57 57
 github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
58 58
 github.com/coreos/etcd v3.2.1
59 59
 github.com/coreos/go-semver v0.2.0
60
-github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
60
+# fix for go vet (https://github.com/kolyshkin/ugorji-go/commit/1cf431c13dec46596)
61
+github.com/ugorji/go go111 https://github.com/kolyshkin/ugorji-go
61 62
 github.com/hashicorp/consul v0.5.2
62 63
 github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
63 64
 github.com/miekg/dns v1.0.7
... ...
@@ -116,7 +117,7 @@ google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
116 116
 # containerd
117 117
 github.com/containerd/containerd v1.2.0-beta.2
118 118
 github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
119
-github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b
119
+github.com/containerd/continuity c7c5070e6f6e090ab93b0a61eb921f2196fc3383
120 120
 github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
121 121
 github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
122 122
 github.com/containerd/go-runc edcf3de1f4971445c42d61f20d506b30612aa031
... ...
@@ -156,9 +157,3 @@ github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.
156 156
 github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
157 157
 
158 158
 github.com/opencontainers/selinux b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd
159
-
160
-
161
-# archive/tar (for Go 1.10, see https://github.com/golang/go/issues/24787)
162
-# mkdir -p ./vendor/archive
163
-# git clone -b go-1.10 --depth=1 git@github.com:kolyshkin/go-tar.git ./vendor/archive/tar
164
-# vndr # to clean up test files
165 159
deleted file mode 100644
... ...
@@ -1,27 +0,0 @@
1
-Copyright (c) 2009 The Go Authors. All rights reserved.
2
-
3
-Redistribution and use in source and binary forms, with or without
4
-modification, are permitted provided that the following conditions are
5
-met:
6
-
7
-   * Redistributions of source code must retain the above copyright
8
-notice, this list of conditions and the following disclaimer.
9
-   * Redistributions in binary form must reproduce the above
10
-copyright notice, this list of conditions and the following disclaimer
11
-in the documentation and/or other materials provided with the
12
-distribution.
13
-   * Neither the name of Google Inc. nor the names of its
14
-contributors may be used to endorse or promote products derived from
15
-this software without specific prior written permission.
16
-
17
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 1
deleted file mode 100644
... ...
@@ -1,27 +0,0 @@
1
-This is a fork of Go 1.10 `archive/tar` package from the official
2
-[repo](https://github.com/golang/go/tree/release-branch.go1.10/src/archive/tar),
3
-with a partial [revert](https://github.com/kolyshkin/go-tar/commit/d651d6e45972363e9bb62b8e9d876df440b31628)
4
-of upstream [commit 0564e304a6ea](https://github.com/golang/go/commit/0564e304a6ea394a42929060c588469dbd6f32af).
5
-It is suggested as a replacement to the original package included with Go 1.10
6
-in case you want to build a static Linux/glibc binary that works, and
7
-can't afford to use `CGO_ENABLED=0`.
8
-
9
-## Details
10
-
11
-Using Go 1.10 [archive/tar](https://golang.org/pkg/archive/tar/) from a static binary
12
-compiled with glibc on Linux can result in a panic upon calling
13
-[`tar.FileInfoHeader()`](https://golang.org/pkg/archive/tar/#FileInfoHeader).
14
-This is a major regression in Go 1.10, filed as
15
-[Go issue #24787](https://github.com/golang/go/issues/24787).
16
-
17
-The above issue is caused by an unfortunate combination of:
18
-1. glibc way of dynamic loading of nss libraries even for a static build;
19
-2. Go `os/user` package hard-coded reliance on libc to resolve user/group IDs to names (unless CGO is disabled).
20
-
21
-While glibc can probably not be fixed and is not considered a bug per se,
22
-the `os/user` issue is documented (see [Go issue #23265](https://github.com/golang/go/issues/23265))
23
-and already fixed by [Go commit 62f0127d81](https://github.com/golang/go/commit/62f0127d8104d8266d9a3fb5a87e2f09ec8b6f5b).
24
-The fix is expected to make its way to Go 1.11, and requires `osusergo` build tag
25
-to be used for a static build.
26
-
27
-This repository serves as a temporary workaround until the above fix is available.
28 1
deleted file mode 100644
... ...
@@ -1,720 +0,0 @@
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 implements access to tar archives.
6
-//
7
-// Tape archives (tar) are a file format for storing a sequence of files that
8
-// can be read and written in a streaming manner.
9
-// This package aims to cover most variations of the format,
10
-// including those produced by GNU and BSD tar tools.
11
-package tar
12
-
13
-import (
14
-	"errors"
15
-	"fmt"
16
-	"math"
17
-	"os"
18
-	"path"
19
-	"reflect"
20
-	"strconv"
21
-	"strings"
22
-	"time"
23
-)
24
-
25
-// BUG: Use of the Uid and Gid fields in Header could overflow on 32-bit
26
-// architectures. If a large value is encountered when decoding, the result
27
-// stored in Header will be the truncated version.
28
-
29
-var (
30
-	ErrHeader          = errors.New("archive/tar: invalid tar header")
31
-	ErrWriteTooLong    = errors.New("archive/tar: write too long")
32
-	ErrFieldTooLong    = errors.New("archive/tar: header field too long")
33
-	ErrWriteAfterClose = errors.New("archive/tar: write after close")
34
-	errMissData        = errors.New("archive/tar: sparse file references non-existent data")
35
-	errUnrefData       = errors.New("archive/tar: sparse file contains unreferenced data")
36
-	errWriteHole       = errors.New("archive/tar: write non-NUL byte in sparse hole")
37
-)
38
-
39
-type headerError []string
40
-
41
-func (he headerError) Error() string {
42
-	const prefix = "archive/tar: cannot encode header"
43
-	var ss []string
44
-	for _, s := range he {
45
-		if s != "" {
46
-			ss = append(ss, s)
47
-		}
48
-	}
49
-	if len(ss) == 0 {
50
-		return prefix
51
-	}
52
-	return fmt.Sprintf("%s: %v", prefix, strings.Join(ss, "; and "))
53
-}
54
-
55
-// Type flags for Header.Typeflag.
56
-const (
57
-	// Type '0' indicates a regular file.
58
-	TypeReg  = '0'
59
-	TypeRegA = '\x00' // For legacy support; use TypeReg instead
60
-
61
-	// Type '1' to '6' are header-only flags and may not have a data body.
62
-	TypeLink    = '1' // Hard link
63
-	TypeSymlink = '2' // Symbolic link
64
-	TypeChar    = '3' // Character device node
65
-	TypeBlock   = '4' // Block device node
66
-	TypeDir     = '5' // Directory
67
-	TypeFifo    = '6' // FIFO node
68
-
69
-	// Type '7' is reserved.
70
-	TypeCont = '7'
71
-
72
-	// Type 'x' is used by the PAX format to store key-value records that
73
-	// are only relevant to the next file.
74
-	// This package transparently handles these types.
75
-	TypeXHeader = 'x'
76
-
77
-	// Type 'g' is used by the PAX format to store key-value records that
78
-	// are relevant to all subsequent files.
79
-	// This package only supports parsing and composing such headers,
80
-	// but does not currently support persisting the global state across files.
81
-	TypeXGlobalHeader = 'g'
82
-
83
-	// Type 'S' indicates a sparse file in the GNU format.
84
-	TypeGNUSparse = 'S'
85
-
86
-	// Types 'L' and 'K' are used by the GNU format for a meta file
87
-	// used to store the path or link name for the next file.
88
-	// This package transparently handles these types.
89
-	TypeGNULongName = 'L'
90
-	TypeGNULongLink = 'K'
91
-)
92
-
93
-// Keywords for PAX extended header records.
94
-const (
95
-	paxNone     = "" // Indicates that no PAX key is suitable
96
-	paxPath     = "path"
97
-	paxLinkpath = "linkpath"
98
-	paxSize     = "size"
99
-	paxUid      = "uid"
100
-	paxGid      = "gid"
101
-	paxUname    = "uname"
102
-	paxGname    = "gname"
103
-	paxMtime    = "mtime"
104
-	paxAtime    = "atime"
105
-	paxCtime    = "ctime"   // Removed from later revision of PAX spec, but was valid
106
-	paxCharset  = "charset" // Currently unused
107
-	paxComment  = "comment" // Currently unused
108
-
109
-	paxSchilyXattr = "SCHILY.xattr."
110
-
111
-	// Keywords for GNU sparse files in a PAX extended header.
112
-	paxGNUSparse          = "GNU.sparse."
113
-	paxGNUSparseNumBlocks = "GNU.sparse.numblocks"
114
-	paxGNUSparseOffset    = "GNU.sparse.offset"
115
-	paxGNUSparseNumBytes  = "GNU.sparse.numbytes"
116
-	paxGNUSparseMap       = "GNU.sparse.map"
117
-	paxGNUSparseName      = "GNU.sparse.name"
118
-	paxGNUSparseMajor     = "GNU.sparse.major"
119
-	paxGNUSparseMinor     = "GNU.sparse.minor"
120
-	paxGNUSparseSize      = "GNU.sparse.size"
121
-	paxGNUSparseRealSize  = "GNU.sparse.realsize"
122
-)
123
-
124
-// basicKeys is a set of the PAX keys for which we have built-in support.
125
-// This does not contain "charset" or "comment", which are both PAX-specific,
126
-// so adding them as first-class features of Header is unlikely.
127
-// Users can use the PAXRecords field to set it themselves.
128
-var basicKeys = map[string]bool{
129
-	paxPath: true, paxLinkpath: true, paxSize: true, paxUid: true, paxGid: true,
130
-	paxUname: true, paxGname: true, paxMtime: true, paxAtime: true, paxCtime: true,
131
-}
132
-
133
-// A Header represents a single header in a tar archive.
134
-// Some fields may not be populated.
135
-//
136
-// For forward compatibility, users that retrieve a Header from Reader.Next,
137
-// mutate it in some ways, and then pass it back to Writer.WriteHeader
138
-// should do so by creating a new Header and copying the fields
139
-// that they are interested in preserving.
140
-type Header struct {
141
-	Typeflag byte // Type of header entry (should be TypeReg for most files)
142
-
143
-	Name     string // Name of file entry
144
-	Linkname string // Target name of link (valid for TypeLink or TypeSymlink)
145
-
146
-	Size  int64  // Logical file size in bytes
147
-	Mode  int64  // Permission and mode bits
148
-	Uid   int    // User ID of owner
149
-	Gid   int    // Group ID of owner
150
-	Uname string // User name of owner
151
-	Gname string // Group name of owner
152
-
153
-	// If the Format is unspecified, then Writer.WriteHeader rounds ModTime
154
-	// to the nearest second and ignores the AccessTime and ChangeTime fields.
155
-	//
156
-	// To use AccessTime or ChangeTime, specify the Format as PAX or GNU.
157
-	// To use sub-second resolution, specify the Format as PAX.
158
-	ModTime    time.Time // Modification time
159
-	AccessTime time.Time // Access time (requires either PAX or GNU support)
160
-	ChangeTime time.Time // Change time (requires either PAX or GNU support)
161
-
162
-	Devmajor int64 // Major device number (valid for TypeChar or TypeBlock)
163
-	Devminor int64 // Minor device number (valid for TypeChar or TypeBlock)
164
-
165
-	// Xattrs stores extended attributes as PAX records under the
166
-	// "SCHILY.xattr." namespace.
167
-	//
168
-	// The following are semantically equivalent:
169
-	//  h.Xattrs[key] = value
170
-	//  h.PAXRecords["SCHILY.xattr."+key] = value
171
-	//
172
-	// When Writer.WriteHeader is called, the contents of Xattrs will take
173
-	// precedence over those in PAXRecords.
174
-	//
175
-	// Deprecated: Use PAXRecords instead.
176
-	Xattrs map[string]string
177
-
178
-	// PAXRecords is a map of PAX extended header records.
179
-	//
180
-	// User-defined records should have keys of the following form:
181
-	//	VENDOR.keyword
182
-	// Where VENDOR is some namespace in all uppercase, and keyword may
183
-	// not contain the '=' character (e.g., "GOLANG.pkg.version").
184
-	// The key and value should be non-empty UTF-8 strings.
185
-	//
186
-	// When Writer.WriteHeader is called, PAX records derived from the
187
-	// the other fields in Header take precedence over PAXRecords.
188
-	PAXRecords map[string]string
189
-
190
-	// Format specifies the format of the tar header.
191
-	//
192
-	// This is set by Reader.Next as a best-effort guess at the format.
193
-	// Since the Reader liberally reads some non-compliant files,
194
-	// it is possible for this to be FormatUnknown.
195
-	//
196
-	// If the format is unspecified when Writer.WriteHeader is called,
197
-	// then it uses the first format (in the order of USTAR, PAX, GNU)
198
-	// capable of encoding this Header (see Format).
199
-	Format Format
200
-}
201
-
202
-// sparseEntry represents a Length-sized fragment at Offset in the file.
203
-type sparseEntry struct{ Offset, Length int64 }
204
-
205
-func (s sparseEntry) endOffset() int64 { return s.Offset + s.Length }
206
-
207
-// A sparse file can be represented as either a sparseDatas or a sparseHoles.
208
-// As long as the total size is known, they are equivalent and one can be
209
-// converted to the other form and back. The various tar formats with sparse
210
-// file support represent sparse files in the sparseDatas form. That is, they
211
-// specify the fragments in the file that has data, and treat everything else as
212
-// having zero bytes. As such, the encoding and decoding logic in this package
213
-// deals with sparseDatas.
214
-//
215
-// However, the external API uses sparseHoles instead of sparseDatas because the
216
-// zero value of sparseHoles logically represents a normal file (i.e., there are
217
-// no holes in it). On the other hand, the zero value of sparseDatas implies
218
-// that the file has no data in it, which is rather odd.
219
-//
220
-// As an example, if the underlying raw file contains the 10-byte data:
221
-//	var compactFile = "abcdefgh"
222
-//
223
-// And the sparse map has the following entries:
224
-//	var spd sparseDatas = []sparseEntry{
225
-//		{Offset: 2,  Length: 5},  // Data fragment for 2..6
226
-//		{Offset: 18, Length: 3},  // Data fragment for 18..20
227
-//	}
228
-//	var sph sparseHoles = []sparseEntry{
229
-//		{Offset: 0,  Length: 2},  // Hole fragment for 0..1
230
-//		{Offset: 7,  Length: 11}, // Hole fragment for 7..17
231
-//		{Offset: 21, Length: 4},  // Hole fragment for 21..24
232
-//	}
233
-//
234
-// Then the content of the resulting sparse file with a Header.Size of 25 is:
235
-//	var sparseFile = "\x00"*2 + "abcde" + "\x00"*11 + "fgh" + "\x00"*4
236
-type (
237
-	sparseDatas []sparseEntry
238
-	sparseHoles []sparseEntry
239
-)
240
-
241
-// validateSparseEntries reports whether sp is a valid sparse map.
242
-// It does not matter whether sp represents data fragments or hole fragments.
243
-func validateSparseEntries(sp []sparseEntry, size int64) bool {
244
-	// Validate all sparse entries. These are the same checks as performed by
245
-	// the BSD tar utility.
246
-	if size < 0 {
247
-		return false
248
-	}
249
-	var pre sparseEntry
250
-	for _, cur := range sp {
251
-		switch {
252
-		case cur.Offset < 0 || cur.Length < 0:
253
-			return false // Negative values are never okay
254
-		case cur.Offset > math.MaxInt64-cur.Length:
255
-			return false // Integer overflow with large length
256
-		case cur.endOffset() > size:
257
-			return false // Region extends beyond the actual size
258
-		case pre.endOffset() > cur.Offset:
259
-			return false // Regions cannot overlap and must be in order
260
-		}
261
-		pre = cur
262
-	}
263
-	return true
264
-}
265
-
266
-// alignSparseEntries mutates src and returns dst where each fragment's
267
-// starting offset is aligned up to the nearest block edge, and each
268
-// ending offset is aligned down to the nearest block edge.
269
-//
270
-// Even though the Go tar Reader and the BSD tar utility can handle entries
271
-// with arbitrary offsets and lengths, the GNU tar utility can only handle
272
-// offsets and lengths that are multiples of blockSize.
273
-func alignSparseEntries(src []sparseEntry, size int64) []sparseEntry {
274
-	dst := src[:0]
275
-	for _, s := range src {
276
-		pos, end := s.Offset, s.endOffset()
277
-		pos += blockPadding(+pos) // Round-up to nearest blockSize
278
-		if end != size {
279
-			end -= blockPadding(-end) // Round-down to nearest blockSize
280
-		}
281
-		if pos < end {
282
-			dst = append(dst, sparseEntry{Offset: pos, Length: end - pos})
283
-		}
284
-	}
285
-	return dst
286
-}
287
-
288
-// invertSparseEntries converts a sparse map from one form to the other.
289
-// If the input is sparseHoles, then it will output sparseDatas and vice-versa.
290
-// The input must have been already validated.
291
-//
292
-// This function mutates src and returns a normalized map where:
293
-//	* adjacent fragments are coalesced together
294
-//	* only the last fragment may be empty
295
-//	* the endOffset of the last fragment is the total size
296
-func invertSparseEntries(src []sparseEntry, size int64) []sparseEntry {
297
-	dst := src[:0]
298
-	var pre sparseEntry
299
-	for _, cur := range src {
300
-		if cur.Length == 0 {
301
-			continue // Skip empty fragments
302
-		}
303
-		pre.Length = cur.Offset - pre.Offset
304
-		if pre.Length > 0 {
305
-			dst = append(dst, pre) // Only add non-empty fragments
306
-		}
307
-		pre.Offset = cur.endOffset()
308
-	}
309
-	pre.Length = size - pre.Offset // Possibly the only empty fragment
310
-	return append(dst, pre)
311
-}
312
-
313
-// fileState tracks the number of logical (includes sparse holes) and physical
314
-// (actual in tar archive) bytes remaining for the current file.
315
-//
316
-// Invariant: LogicalRemaining >= PhysicalRemaining
317
-type fileState interface {
318
-	LogicalRemaining() int64
319
-	PhysicalRemaining() int64
320
-}
321
-
322
-// allowedFormats determines which formats can be used.
323
-// The value returned is the logical OR of multiple possible formats.
324
-// If the value is FormatUnknown, then the input Header cannot be encoded
325
-// and an error is returned explaining why.
326
-//
327
-// As a by-product of checking the fields, this function returns paxHdrs, which
328
-// contain all fields that could not be directly encoded.
329
-// A value receiver ensures that this method does not mutate the source Header.
330
-func (h Header) allowedFormats() (format Format, paxHdrs map[string]string, err error) {
331
-	format = FormatUSTAR | FormatPAX | FormatGNU
332
-	paxHdrs = make(map[string]string)
333
-
334
-	var whyNoUSTAR, whyNoPAX, whyNoGNU string
335
-	var preferPAX bool // Prefer PAX over USTAR
336
-	verifyString := func(s string, size int, name, paxKey string) {
337
-		// NUL-terminator is optional for path and linkpath.
338
-		// Technically, it is required for uname and gname,
339
-		// but neither GNU nor BSD tar checks for it.
340
-		tooLong := len(s) > size
341
-		allowLongGNU := paxKey == paxPath || paxKey == paxLinkpath
342
-		if hasNUL(s) || (tooLong && !allowLongGNU) {
343
-			whyNoGNU = fmt.Sprintf("GNU cannot encode %s=%q", name, s)
344
-			format.mustNotBe(FormatGNU)
345
-		}
346
-		if !isASCII(s) || tooLong {
347
-			canSplitUSTAR := paxKey == paxPath
348
-			if _, _, ok := splitUSTARPath(s); !canSplitUSTAR || !ok {
349
-				whyNoUSTAR = fmt.Sprintf("USTAR cannot encode %s=%q", name, s)
350
-				format.mustNotBe(FormatUSTAR)
351
-			}
352
-			if paxKey == paxNone {
353
-				whyNoPAX = fmt.Sprintf("PAX cannot encode %s=%q", name, s)
354
-				format.mustNotBe(FormatPAX)
355
-			} else {
356
-				paxHdrs[paxKey] = s
357
-			}
358
-		}
359
-		if v, ok := h.PAXRecords[paxKey]; ok && v == s {
360
-			paxHdrs[paxKey] = v
361
-		}
362
-	}
363
-	verifyNumeric := func(n int64, size int, name, paxKey string) {
364
-		if !fitsInBase256(size, n) {
365
-			whyNoGNU = fmt.Sprintf("GNU cannot encode %s=%d", name, n)
366
-			format.mustNotBe(FormatGNU)
367
-		}
368
-		if !fitsInOctal(size, n) {
369
-			whyNoUSTAR = fmt.Sprintf("USTAR cannot encode %s=%d", name, n)
370
-			format.mustNotBe(FormatUSTAR)
371
-			if paxKey == paxNone {
372
-				whyNoPAX = fmt.Sprintf("PAX cannot encode %s=%d", name, n)
373
-				format.mustNotBe(FormatPAX)
374
-			} else {
375
-				paxHdrs[paxKey] = strconv.FormatInt(n, 10)
376
-			}
377
-		}
378
-		if v, ok := h.PAXRecords[paxKey]; ok && v == strconv.FormatInt(n, 10) {
379
-			paxHdrs[paxKey] = v
380
-		}
381
-	}
382
-	verifyTime := func(ts time.Time, size int, name, paxKey string) {
383
-		if ts.IsZero() {
384
-			return // Always okay
385
-		}
386
-		if !fitsInBase256(size, ts.Unix()) {
387
-			whyNoGNU = fmt.Sprintf("GNU cannot encode %s=%v", name, ts)
388
-			format.mustNotBe(FormatGNU)
389
-		}
390
-		isMtime := paxKey == paxMtime
391
-		fitsOctal := fitsInOctal(size, ts.Unix())
392
-		if (isMtime && !fitsOctal) || !isMtime {
393
-			whyNoUSTAR = fmt.Sprintf("USTAR cannot encode %s=%v", name, ts)
394
-			format.mustNotBe(FormatUSTAR)
395
-		}
396
-		needsNano := ts.Nanosecond() != 0
397
-		if !isMtime || !fitsOctal || needsNano {
398
-			preferPAX = true // USTAR may truncate sub-second measurements
399
-			if paxKey == paxNone {
400
-				whyNoPAX = fmt.Sprintf("PAX cannot encode %s=%v", name, ts)
401
-				format.mustNotBe(FormatPAX)
402
-			} else {
403
-				paxHdrs[paxKey] = formatPAXTime(ts)
404
-			}
405
-		}
406
-		if v, ok := h.PAXRecords[paxKey]; ok && v == formatPAXTime(ts) {
407
-			paxHdrs[paxKey] = v
408
-		}
409
-	}
410
-
411
-	// Check basic fields.
412
-	var blk block
413
-	v7 := blk.V7()
414
-	ustar := blk.USTAR()
415
-	gnu := blk.GNU()
416
-	verifyString(h.Name, len(v7.Name()), "Name", paxPath)
417
-	verifyString(h.Linkname, len(v7.LinkName()), "Linkname", paxLinkpath)
418
-	verifyString(h.Uname, len(ustar.UserName()), "Uname", paxUname)
419
-	verifyString(h.Gname, len(ustar.GroupName()), "Gname", paxGname)
420
-	verifyNumeric(h.Mode, len(v7.Mode()), "Mode", paxNone)
421
-	verifyNumeric(int64(h.Uid), len(v7.UID()), "Uid", paxUid)
422
-	verifyNumeric(int64(h.Gid), len(v7.GID()), "Gid", paxGid)
423
-	verifyNumeric(h.Size, len(v7.Size()), "Size", paxSize)
424
-	verifyNumeric(h.Devmajor, len(ustar.DevMajor()), "Devmajor", paxNone)
425
-	verifyNumeric(h.Devminor, len(ustar.DevMinor()), "Devminor", paxNone)
426
-	verifyTime(h.ModTime, len(v7.ModTime()), "ModTime", paxMtime)
427
-	verifyTime(h.AccessTime, len(gnu.AccessTime()), "AccessTime", paxAtime)
428
-	verifyTime(h.ChangeTime, len(gnu.ChangeTime()), "ChangeTime", paxCtime)
429
-
430
-	// Check for header-only types.
431
-	var whyOnlyPAX, whyOnlyGNU string
432
-	switch h.Typeflag {
433
-	case TypeReg, TypeChar, TypeBlock, TypeFifo, TypeGNUSparse:
434
-		// Exclude TypeLink and TypeSymlink, since they may reference directories.
435
-		if strings.HasSuffix(h.Name, "/") {
436
-			return FormatUnknown, nil, headerError{"filename may not have trailing slash"}
437
-		}
438
-	case TypeXHeader, TypeGNULongName, TypeGNULongLink:
439
-		return FormatUnknown, nil, headerError{"cannot manually encode TypeXHeader, TypeGNULongName, or TypeGNULongLink headers"}
440
-	case TypeXGlobalHeader:
441
-		h2 := Header{Name: h.Name, Typeflag: h.Typeflag, Xattrs: h.Xattrs, PAXRecords: h.PAXRecords, Format: h.Format}
442
-		if !reflect.DeepEqual(h, h2) {
443
-			return FormatUnknown, nil, headerError{"only PAXRecords should be set for TypeXGlobalHeader"}
444
-		}
445
-		whyOnlyPAX = "only PAX supports TypeXGlobalHeader"
446
-		format.mayOnlyBe(FormatPAX)
447
-	}
448
-	if !isHeaderOnlyType(h.Typeflag) && h.Size < 0 {
449
-		return FormatUnknown, nil, headerError{"negative size on header-only type"}
450
-	}
451
-
452
-	// Check PAX records.
453
-	if len(h.Xattrs) > 0 {
454
-		for k, v := range h.Xattrs {
455
-			paxHdrs[paxSchilyXattr+k] = v
456
-		}
457
-		whyOnlyPAX = "only PAX supports Xattrs"
458
-		format.mayOnlyBe(FormatPAX)
459
-	}
460
-	if len(h.PAXRecords) > 0 {
461
-		for k, v := range h.PAXRecords {
462
-			switch _, exists := paxHdrs[k]; {
463
-			case exists:
464
-				continue // Do not overwrite existing records
465
-			case h.Typeflag == TypeXGlobalHeader:
466
-				paxHdrs[k] = v // Copy all records
467
-			case !basicKeys[k] && !strings.HasPrefix(k, paxGNUSparse):
468
-				paxHdrs[k] = v // Ignore local records that may conflict
469
-			}
470
-		}
471
-		whyOnlyPAX = "only PAX supports PAXRecords"
472
-		format.mayOnlyBe(FormatPAX)
473
-	}
474
-	for k, v := range paxHdrs {
475
-		if !validPAXRecord(k, v) {
476
-			return FormatUnknown, nil, headerError{fmt.Sprintf("invalid PAX record: %q", k+" = "+v)}
477
-		}
478
-	}
479
-
480
-	// TODO(dsnet): Re-enable this when adding sparse support.
481
-	// See https://golang.org/issue/22735
482
-	/*
483
-		// Check sparse files.
484
-		if len(h.SparseHoles) > 0 || h.Typeflag == TypeGNUSparse {
485
-			if isHeaderOnlyType(h.Typeflag) {
486
-				return FormatUnknown, nil, headerError{"header-only type cannot be sparse"}
487
-			}
488
-			if !validateSparseEntries(h.SparseHoles, h.Size) {
489
-				return FormatUnknown, nil, headerError{"invalid sparse holes"}
490
-			}
491
-			if h.Typeflag == TypeGNUSparse {
492
-				whyOnlyGNU = "only GNU supports TypeGNUSparse"
493
-				format.mayOnlyBe(FormatGNU)
494
-			} else {
495
-				whyNoGNU = "GNU supports sparse files only with TypeGNUSparse"
496
-				format.mustNotBe(FormatGNU)
497
-			}
498
-			whyNoUSTAR = "USTAR does not support sparse files"
499
-			format.mustNotBe(FormatUSTAR)
500
-		}
501
-	*/
502
-
503
-	// Check desired format.
504
-	if wantFormat := h.Format; wantFormat != FormatUnknown {
505
-		if wantFormat.has(FormatPAX) && !preferPAX {
506
-			wantFormat.mayBe(FormatUSTAR) // PAX implies USTAR allowed too
507
-		}
508
-		format.mayOnlyBe(wantFormat) // Set union of formats allowed and format wanted
509
-	}
510
-	if format == FormatUnknown {
511
-		switch h.Format {
512
-		case FormatUSTAR:
513
-			err = headerError{"Format specifies USTAR", whyNoUSTAR, whyOnlyPAX, whyOnlyGNU}
514
-		case FormatPAX:
515
-			err = headerError{"Format specifies PAX", whyNoPAX, whyOnlyGNU}
516
-		case FormatGNU:
517
-			err = headerError{"Format specifies GNU", whyNoGNU, whyOnlyPAX}
518
-		default:
519
-			err = headerError{whyNoUSTAR, whyNoPAX, whyNoGNU, whyOnlyPAX, whyOnlyGNU}
520
-		}
521
-	}
522
-	return format, paxHdrs, err
523
-}
524
-
525
-// FileInfo returns an os.FileInfo for the Header.
526
-func (h *Header) FileInfo() os.FileInfo {
527
-	return headerFileInfo{h}
528
-}
529
-
530
-// headerFileInfo implements os.FileInfo.
531
-type headerFileInfo struct {
532
-	h *Header
533
-}
534
-
535
-func (fi headerFileInfo) Size() int64        { return fi.h.Size }
536
-func (fi headerFileInfo) IsDir() bool        { return fi.Mode().IsDir() }
537
-func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
538
-func (fi headerFileInfo) Sys() interface{}   { return fi.h }
539
-
540
-// Name returns the base name of the file.
541
-func (fi headerFileInfo) Name() string {
542
-	if fi.IsDir() {
543
-		return path.Base(path.Clean(fi.h.Name))
544
-	}
545
-	return path.Base(fi.h.Name)
546
-}
547
-
548
-// Mode returns the permission and mode bits for the headerFileInfo.
549
-func (fi headerFileInfo) Mode() (mode os.FileMode) {
550
-	// Set file permission bits.
551
-	mode = os.FileMode(fi.h.Mode).Perm()
552
-
553
-	// Set setuid, setgid and sticky bits.
554
-	if fi.h.Mode&c_ISUID != 0 {
555
-		mode |= os.ModeSetuid
556
-	}
557
-	if fi.h.Mode&c_ISGID != 0 {
558
-		mode |= os.ModeSetgid
559
-	}
560
-	if fi.h.Mode&c_ISVTX != 0 {
561
-		mode |= os.ModeSticky
562
-	}
563
-
564
-	// Set file mode bits; clear perm, setuid, setgid, and sticky bits.
565
-	switch m := os.FileMode(fi.h.Mode) &^ 07777; m {
566
-	case c_ISDIR:
567
-		mode |= os.ModeDir
568
-	case c_ISFIFO:
569
-		mode |= os.ModeNamedPipe
570
-	case c_ISLNK:
571
-		mode |= os.ModeSymlink
572
-	case c_ISBLK:
573
-		mode |= os.ModeDevice
574
-	case c_ISCHR:
575
-		mode |= os.ModeDevice
576
-		mode |= os.ModeCharDevice
577
-	case c_ISSOCK:
578
-		mode |= os.ModeSocket
579
-	}
580
-
581
-	switch fi.h.Typeflag {
582
-	case TypeSymlink:
583
-		mode |= os.ModeSymlink
584
-	case TypeChar:
585
-		mode |= os.ModeDevice
586
-		mode |= os.ModeCharDevice
587
-	case TypeBlock:
588
-		mode |= os.ModeDevice
589
-	case TypeDir:
590
-		mode |= os.ModeDir
591
-	case TypeFifo:
592
-		mode |= os.ModeNamedPipe
593
-	}
594
-
595
-	return mode
596
-}
597
-
598
-// sysStat, if non-nil, populates h from system-dependent fields of fi.
599
-var sysStat func(fi os.FileInfo, h *Header) error
600
-
601
-const (
602
-	// Mode constants from the USTAR spec:
603
-	// See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_06
604
-	c_ISUID = 04000 // Set uid
605
-	c_ISGID = 02000 // Set gid
606
-	c_ISVTX = 01000 // Save text (sticky bit)
607
-
608
-	// Common Unix mode constants; these are not defined in any common tar standard.
609
-	// Header.FileInfo understands these, but FileInfoHeader will never produce these.
610
-	c_ISDIR  = 040000  // Directory
611
-	c_ISFIFO = 010000  // FIFO
612
-	c_ISREG  = 0100000 // Regular file
613
-	c_ISLNK  = 0120000 // Symbolic link
614
-	c_ISBLK  = 060000  // Block special file
615
-	c_ISCHR  = 020000  // Character special file
616
-	c_ISSOCK = 0140000 // Socket
617
-)
618
-
619
-// FileInfoHeader creates a partially-populated Header from fi.
620
-// If fi describes a symlink, FileInfoHeader records link as the link target.
621
-// If fi describes a directory, a slash is appended to the name.
622
-//
623
-// Since os.FileInfo's Name method only returns the base name of
624
-// the file it describes, it may be necessary to modify Header.Name
625
-// to provide the full path name of the file.
626
-func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
627
-	if fi == nil {
628
-		return nil, errors.New("archive/tar: FileInfo is nil")
629
-	}
630
-	fm := fi.Mode()
631
-	h := &Header{
632
-		Name:    fi.Name(),
633
-		ModTime: fi.ModTime(),
634
-		Mode:    int64(fm.Perm()), // or'd with c_IS* constants later
635
-	}
636
-	switch {
637
-	case fm.IsRegular():
638
-		h.Typeflag = TypeReg
639
-		h.Size = fi.Size()
640
-	case fi.IsDir():
641
-		h.Typeflag = TypeDir
642
-		h.Name += "/"
643
-	case fm&os.ModeSymlink != 0:
644
-		h.Typeflag = TypeSymlink
645
-		h.Linkname = link
646
-	case fm&os.ModeDevice != 0:
647
-		if fm&os.ModeCharDevice != 0 {
648
-			h.Typeflag = TypeChar
649
-		} else {
650
-			h.Typeflag = TypeBlock
651
-		}
652
-	case fm&os.ModeNamedPipe != 0:
653
-		h.Typeflag = TypeFifo
654
-	case fm&os.ModeSocket != 0:
655
-		return nil, fmt.Errorf("archive/tar: sockets not supported")
656
-	default:
657
-		return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
658
-	}
659
-	if fm&os.ModeSetuid != 0 {
660
-		h.Mode |= c_ISUID
661
-	}
662
-	if fm&os.ModeSetgid != 0 {
663
-		h.Mode |= c_ISGID
664
-	}
665
-	if fm&os.ModeSticky != 0 {
666
-		h.Mode |= c_ISVTX
667
-	}
668
-	// If possible, populate additional fields from OS-specific
669
-	// FileInfo fields.
670
-	if sys, ok := fi.Sys().(*Header); ok {
671
-		// This FileInfo came from a Header (not the OS). Use the
672
-		// original Header to populate all remaining fields.
673
-		h.Uid = sys.Uid
674
-		h.Gid = sys.Gid
675
-		h.Uname = sys.Uname
676
-		h.Gname = sys.Gname
677
-		h.AccessTime = sys.AccessTime
678
-		h.ChangeTime = sys.ChangeTime
679
-		if sys.Xattrs != nil {
680
-			h.Xattrs = make(map[string]string)
681
-			for k, v := range sys.Xattrs {
682
-				h.Xattrs[k] = v
683
-			}
684
-		}
685
-		if sys.Typeflag == TypeLink {
686
-			// hard link
687
-			h.Typeflag = TypeLink
688
-			h.Size = 0
689
-			h.Linkname = sys.Linkname
690
-		}
691
-		if sys.PAXRecords != nil {
692
-			h.PAXRecords = make(map[string]string)
693
-			for k, v := range sys.PAXRecords {
694
-				h.PAXRecords[k] = v
695
-			}
696
-		}
697
-	}
698
-	if sysStat != nil {
699
-		return h, sysStat(fi, h)
700
-	}
701
-	return h, nil
702
-}
703
-
704
-// isHeaderOnlyType checks if the given type flag is of the type that has no
705
-// data section even if a size is specified.
706
-func isHeaderOnlyType(flag byte) bool {
707
-	switch flag {
708
-	case TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo:
709
-		return true
710
-	default:
711
-		return false
712
-	}
713
-}
714
-
715
-func min(a, b int64) int64 {
716
-	if a < b {
717
-		return a
718
-	}
719
-	return b
720
-}
721 1
deleted file mode 100644
... ...
@@ -1,303 +0,0 @@
1
-// Copyright 2016 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 "strings"
8
-
9
-// Format represents the tar archive format.
10
-//
11
-// The original tar format was introduced in Unix V7.
12
-// Since then, there have been multiple competing formats attempting to
13
-// standardize or extend the V7 format to overcome its limitations.
14
-// The most common formats are the USTAR, PAX, and GNU formats,
15
-// each with their own advantages and limitations.
16
-//
17
-// The following table captures the capabilities of each format:
18
-//
19
-//	                  |  USTAR |       PAX |       GNU
20
-//	------------------+--------+-----------+----------
21
-//	Name              |   256B | unlimited | unlimited
22
-//	Linkname          |   100B | unlimited | unlimited
23
-//	Size              | uint33 | unlimited |    uint89
24
-//	Mode              | uint21 |    uint21 |    uint57
25
-//	Uid/Gid           | uint21 | unlimited |    uint57
26
-//	Uname/Gname       |    32B | unlimited |       32B
27
-//	ModTime           | uint33 | unlimited |     int89
28
-//	AccessTime        |    n/a | unlimited |     int89
29
-//	ChangeTime        |    n/a | unlimited |     int89
30
-//	Devmajor/Devminor | uint21 |    uint21 |    uint57
31
-//	------------------+--------+-----------+----------
32
-//	string encoding   |  ASCII |     UTF-8 |    binary
33
-//	sub-second times  |     no |       yes |        no
34
-//	sparse files      |     no |       yes |       yes
35
-//
36
-// The table's upper portion shows the Header fields, where each format reports
37
-// the maximum number of bytes allowed for each string field and
38
-// the integer type used to store each numeric field
39
-// (where timestamps are stored as the number of seconds since the Unix epoch).
40
-//
41
-// The table's lower portion shows specialized features of each format,
42
-// such as supported string encodings, support for sub-second timestamps,
43
-// or support for sparse files.
44
-//
45
-// The Writer currently provides no support for sparse files.
46
-type Format int
47
-
48
-// Constants to identify various tar formats.
49
-const (
50
-	// Deliberately hide the meaning of constants from public API.
51
-	_ Format = (1 << iota) / 4 // Sequence of 0, 0, 1, 2, 4, 8, etc...
52
-
53
-	// FormatUnknown indicates that the format is unknown.
54
-	FormatUnknown
55
-
56
-	// The format of the original Unix V7 tar tool prior to standardization.
57
-	formatV7
58
-
59
-	// FormatUSTAR represents the USTAR header format defined in POSIX.1-1988.
60
-	//
61
-	// While this format is compatible with most tar readers,
62
-	// the format has several limitations making it unsuitable for some usages.
63
-	// Most notably, it cannot support sparse files, files larger than 8GiB,
64
-	// filenames larger than 256 characters, and non-ASCII filenames.
65
-	//
66
-	// Reference:
67
-	//	http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_06
68
-	FormatUSTAR
69
-
70
-	// FormatPAX represents the PAX header format defined in POSIX.1-2001.
71
-	//
72
-	// PAX extends USTAR by writing a special file with Typeflag TypeXHeader
73
-	// preceding the original header. This file contains a set of key-value
74
-	// records, which are used to overcome USTAR's shortcomings, in addition to
75
-	// providing the ability to have sub-second resolution for timestamps.
76
-	//
77
-	// Some newer formats add their own extensions to PAX by defining their
78
-	// own keys and assigning certain semantic meaning to the associated values.
79
-	// For example, sparse file support in PAX is implemented using keys
80
-	// defined by the GNU manual (e.g., "GNU.sparse.map").
81
-	//
82
-	// Reference:
83
-	//	http://pubs.opengroup.org/onlinepubs/009695399/utilities/pax.html
84
-	FormatPAX
85
-
86
-	// FormatGNU represents the GNU header format.
87
-	//
88
-	// The GNU header format is older than the USTAR and PAX standards and
89
-	// is not compatible with them. The GNU format supports
90
-	// arbitrary file sizes, filenames of arbitrary encoding and length,
91
-	// sparse files, and other features.
92
-	//
93
-	// It is recommended that PAX be chosen over GNU unless the target
94
-	// application can only parse GNU formatted archives.
95
-	//
96
-	// Reference:
97
-	//	http://www.gnu.org/software/tar/manual/html_node/Standard.html
98
-	FormatGNU
99
-
100
-	// Schily's tar format, which is incompatible with USTAR.
101
-	// This does not cover STAR extensions to the PAX format; these fall under
102
-	// the PAX format.
103
-	formatSTAR
104
-
105
-	formatMax
106
-)
107
-
108
-func (f Format) has(f2 Format) bool   { return f&f2 != 0 }
109
-func (f *Format) mayBe(f2 Format)     { *f |= f2 }
110
-func (f *Format) mayOnlyBe(f2 Format) { *f &= f2 }
111
-func (f *Format) mustNotBe(f2 Format) { *f &^= f2 }
112
-
113
-var formatNames = map[Format]string{
114
-	formatV7: "V7", FormatUSTAR: "USTAR", FormatPAX: "PAX", FormatGNU: "GNU", formatSTAR: "STAR",
115
-}
116
-
117
-func (f Format) String() string {
118
-	var ss []string
119
-	for f2 := Format(1); f2 < formatMax; f2 <<= 1 {
120
-		if f.has(f2) {
121
-			ss = append(ss, formatNames[f2])
122
-		}
123
-	}
124
-	switch len(ss) {
125
-	case 0:
126
-		return "<unknown>"
127
-	case 1:
128
-		return ss[0]
129
-	default:
130
-		return "(" + strings.Join(ss, " | ") + ")"
131
-	}
132
-}
133
-
134
-// Magics used to identify various formats.
135
-const (
136
-	magicGNU, versionGNU     = "ustar ", " \x00"
137
-	magicUSTAR, versionUSTAR = "ustar\x00", "00"
138
-	trailerSTAR              = "tar\x00"
139
-)
140
-
141
-// Size constants from various tar specifications.
142
-const (
143
-	blockSize  = 512 // Size of each block in a tar stream
144
-	nameSize   = 100 // Max length of the name field in USTAR format
145
-	prefixSize = 155 // Max length of the prefix field in USTAR format
146
-)
147
-
148
-// blockPadding computes the number of bytes needed to pad offset up to the
149
-// nearest block edge where 0 <= n < blockSize.
150
-func blockPadding(offset int64) (n int64) {
151
-	return -offset & (blockSize - 1)
152
-}
153
-
154
-var zeroBlock block
155
-
156
-type block [blockSize]byte
157
-
158
-// Convert block to any number of formats.
159
-func (b *block) V7() *headerV7       { return (*headerV7)(b) }
160
-func (b *block) GNU() *headerGNU     { return (*headerGNU)(b) }
161
-func (b *block) STAR() *headerSTAR   { return (*headerSTAR)(b) }
162
-func (b *block) USTAR() *headerUSTAR { return (*headerUSTAR)(b) }
163
-func (b *block) Sparse() sparseArray { return (sparseArray)(b[:]) }
164
-
165
-// GetFormat checks that the block is a valid tar header based on the checksum.
166
-// It then attempts to guess the specific format based on magic values.
167
-// If the checksum fails, then FormatUnknown is returned.
168
-func (b *block) GetFormat() Format {
169
-	// Verify checksum.
170
-	var p parser
171
-	value := p.parseOctal(b.V7().Chksum())
172
-	chksum1, chksum2 := b.ComputeChecksum()
173
-	if p.err != nil || (value != chksum1 && value != chksum2) {
174
-		return FormatUnknown
175
-	}
176
-
177
-	// Guess the magic values.
178
-	magic := string(b.USTAR().Magic())
179
-	version := string(b.USTAR().Version())
180
-	trailer := string(b.STAR().Trailer())
181
-	switch {
182
-	case magic == magicUSTAR && trailer == trailerSTAR:
183
-		return formatSTAR
184
-	case magic == magicUSTAR:
185
-		return FormatUSTAR | FormatPAX
186
-	case magic == magicGNU && version == versionGNU:
187
-		return FormatGNU
188
-	default:
189
-		return formatV7
190
-	}
191
-}
192
-
193
-// SetFormat writes the magic values necessary for specified format
194
-// and then updates the checksum accordingly.
195
-func (b *block) SetFormat(format Format) {
196
-	// Set the magic values.
197
-	switch {
198
-	case format.has(formatV7):
199
-		// Do nothing.
200
-	case format.has(FormatGNU):
201
-		copy(b.GNU().Magic(), magicGNU)
202
-		copy(b.GNU().Version(), versionGNU)
203
-	case format.has(formatSTAR):
204
-		copy(b.STAR().Magic(), magicUSTAR)
205
-		copy(b.STAR().Version(), versionUSTAR)
206
-		copy(b.STAR().Trailer(), trailerSTAR)
207
-	case format.has(FormatUSTAR | FormatPAX):
208
-		copy(b.USTAR().Magic(), magicUSTAR)
209
-		copy(b.USTAR().Version(), versionUSTAR)
210
-	default:
211
-		panic("invalid format")
212
-	}
213
-
214
-	// Update checksum.
215
-	// This field is special in that it is terminated by a NULL then space.
216
-	var f formatter
217
-	field := b.V7().Chksum()
218
-	chksum, _ := b.ComputeChecksum() // Possible values are 256..128776
219
-	f.formatOctal(field[:7], chksum) // Never fails since 128776 < 262143
220
-	field[7] = ' '
221
-}
222
-
223
-// ComputeChecksum computes the checksum for the header block.
224
-// POSIX specifies a sum of the unsigned byte values, but the Sun tar used
225
-// signed byte values.
226
-// We compute and return both.
227
-func (b *block) ComputeChecksum() (unsigned, signed int64) {
228
-	for i, c := range b {
229
-		if 148 <= i && i < 156 {
230
-			c = ' ' // Treat the checksum field itself as all spaces.
231
-		}
232
-		unsigned += int64(c)
233
-		signed += int64(int8(c))
234
-	}
235
-	return unsigned, signed
236
-}
237
-
238
-// Reset clears the block with all zeros.
239
-func (b *block) Reset() {
240
-	*b = block{}
241
-}
242
-
243
-type headerV7 [blockSize]byte
244
-
245
-func (h *headerV7) Name() []byte     { return h[000:][:100] }
246
-func (h *headerV7) Mode() []byte     { return h[100:][:8] }
247
-func (h *headerV7) UID() []byte      { return h[108:][:8] }
248
-func (h *headerV7) GID() []byte      { return h[116:][:8] }
249
-func (h *headerV7) Size() []byte     { return h[124:][:12] }
250
-func (h *headerV7) ModTime() []byte  { return h[136:][:12] }
251
-func (h *headerV7) Chksum() []byte   { return h[148:][:8] }
252
-func (h *headerV7) TypeFlag() []byte { return h[156:][:1] }
253
-func (h *headerV7) LinkName() []byte { return h[157:][:100] }
254
-
255
-type headerGNU [blockSize]byte
256
-
257
-func (h *headerGNU) V7() *headerV7       { return (*headerV7)(h) }
258
-func (h *headerGNU) Magic() []byte       { return h[257:][:6] }
259
-func (h *headerGNU) Version() []byte     { return h[263:][:2] }
260
-func (h *headerGNU) UserName() []byte    { return h[265:][:32] }
261
-func (h *headerGNU) GroupName() []byte   { return h[297:][:32] }
262
-func (h *headerGNU) DevMajor() []byte    { return h[329:][:8] }
263
-func (h *headerGNU) DevMinor() []byte    { return h[337:][:8] }
264
-func (h *headerGNU) AccessTime() []byte  { return h[345:][:12] }
265
-func (h *headerGNU) ChangeTime() []byte  { return h[357:][:12] }
266
-func (h *headerGNU) Sparse() sparseArray { return (sparseArray)(h[386:][:24*4+1]) }
267
-func (h *headerGNU) RealSize() []byte    { return h[483:][:12] }
268
-
269
-type headerSTAR [blockSize]byte
270
-
271
-func (h *headerSTAR) V7() *headerV7      { return (*headerV7)(h) }
272
-func (h *headerSTAR) Magic() []byte      { return h[257:][:6] }
273
-func (h *headerSTAR) Version() []byte    { return h[263:][:2] }
274
-func (h *headerSTAR) UserName() []byte   { return h[265:][:32] }
275
-func (h *headerSTAR) GroupName() []byte  { return h[297:][:32] }
276
-func (h *headerSTAR) DevMajor() []byte   { return h[329:][:8] }
277
-func (h *headerSTAR) DevMinor() []byte   { return h[337:][:8] }
278
-func (h *headerSTAR) Prefix() []byte     { return h[345:][:131] }
279
-func (h *headerSTAR) AccessTime() []byte { return h[476:][:12] }
280
-func (h *headerSTAR) ChangeTime() []byte { return h[488:][:12] }
281
-func (h *headerSTAR) Trailer() []byte    { return h[508:][:4] }
282
-
283
-type headerUSTAR [blockSize]byte
284
-
285
-func (h *headerUSTAR) V7() *headerV7     { return (*headerV7)(h) }
286
-func (h *headerUSTAR) Magic() []byte     { return h[257:][:6] }
287
-func (h *headerUSTAR) Version() []byte   { return h[263:][:2] }
288
-func (h *headerUSTAR) UserName() []byte  { return h[265:][:32] }
289
-func (h *headerUSTAR) GroupName() []byte { return h[297:][:32] }
290
-func (h *headerUSTAR) DevMajor() []byte  { return h[329:][:8] }
291
-func (h *headerUSTAR) DevMinor() []byte  { return h[337:][:8] }
292
-func (h *headerUSTAR) Prefix() []byte    { return h[345:][:155] }
293
-
294
-type sparseArray []byte
295
-
296
-func (s sparseArray) Entry(i int) sparseElem { return (sparseElem)(s[i*24:]) }
297
-func (s sparseArray) IsExtended() []byte     { return s[24*s.MaxEntries():][:1] }
298
-func (s sparseArray) MaxEntries() int        { return len(s) / 24 }
299
-
300
-type sparseElem []byte
301
-
302
-func (s sparseElem) Offset() []byte { return s[00:][:12] }
303
-func (s sparseElem) Length() []byte { return s[12:][:12] }
304 1
deleted file mode 100644
... ...
@@ -1,855 +0,0 @@
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
-	"io"
10
-	"io/ioutil"
11
-	"strconv"
12
-	"strings"
13
-	"time"
14
-)
15
-
16
-// Reader provides sequential access to the contents of a tar archive.
17
-// Reader.Next advances to the next file in the archive (including the first),
18
-// and then Reader can be treated as an io.Reader to access the file's data.
19
-type Reader struct {
20
-	r    io.Reader
21
-	pad  int64      // Amount of padding (ignored) after current file entry
22
-	curr fileReader // Reader for current file entry
23
-	blk  block      // Buffer to use as temporary local storage
24
-
25
-	// err is a persistent error.
26
-	// It is only the responsibility of every exported method of Reader to
27
-	// ensure that this error is sticky.
28
-	err error
29
-}
30
-
31
-type fileReader interface {
32
-	io.Reader
33
-	fileState
34
-
35
-	WriteTo(io.Writer) (int64, error)
36
-}
37
-
38
-// NewReader creates a new Reader reading from r.
39
-func NewReader(r io.Reader) *Reader {
40
-	return &Reader{r: r, curr: &regFileReader{r, 0}}
41
-}
42
-
43
-// Next advances to the next entry in the tar archive.
44
-// The Header.Size determines how many bytes can be read for the next file.
45
-// Any remaining data in the current file is automatically discarded.
46
-//
47
-// io.EOF is returned at the end of the input.
48
-func (tr *Reader) Next() (*Header, error) {
49
-	if tr.err != nil {
50
-		return nil, tr.err
51
-	}
52
-	hdr, err := tr.next()
53
-	tr.err = err
54
-	return hdr, err
55
-}
56
-
57
-func (tr *Reader) next() (*Header, error) {
58
-	var paxHdrs map[string]string
59
-	var gnuLongName, gnuLongLink string
60
-
61
-	// Externally, Next iterates through the tar archive as if it is a series of
62
-	// files. Internally, the tar format often uses fake "files" to add meta
63
-	// data that describes the next file. These meta data "files" should not
64
-	// normally be visible to the outside. As such, this loop iterates through
65
-	// one or more "header files" until it finds a "normal file".
66
-	format := FormatUSTAR | FormatPAX | FormatGNU
67
-loop:
68
-	for {
69
-		// Discard the remainder of the file and any padding.
70
-		if err := discard(tr.r, tr.curr.PhysicalRemaining()); err != nil {
71
-			return nil, err
72
-		}
73
-		if _, err := tryReadFull(tr.r, tr.blk[:tr.pad]); err != nil {
74
-			return nil, err
75
-		}
76
-		tr.pad = 0
77
-
78
-		hdr, rawHdr, err := tr.readHeader()
79
-		if err != nil {
80
-			return nil, err
81
-		}
82
-		if err := tr.handleRegularFile(hdr); err != nil {
83
-			return nil, err
84
-		}
85
-		format.mayOnlyBe(hdr.Format)
86
-
87
-		// Check for PAX/GNU special headers and files.
88
-		switch hdr.Typeflag {
89
-		case TypeXHeader, TypeXGlobalHeader:
90
-			format.mayOnlyBe(FormatPAX)
91
-			paxHdrs, err = parsePAX(tr)
92
-			if err != nil {
93
-				return nil, err
94
-			}
95
-			if hdr.Typeflag == TypeXGlobalHeader {
96
-				mergePAX(hdr, paxHdrs)
97
-				return &Header{
98
-					Name:       hdr.Name,
99
-					Typeflag:   hdr.Typeflag,
100
-					Xattrs:     hdr.Xattrs,
101
-					PAXRecords: hdr.PAXRecords,
102
-					Format:     format,
103
-				}, nil
104
-			}
105
-			continue loop // This is a meta header affecting the next header
106
-		case TypeGNULongName, TypeGNULongLink:
107
-			format.mayOnlyBe(FormatGNU)
108
-			realname, err := ioutil.ReadAll(tr)
109
-			if err != nil {
110
-				return nil, err
111
-			}
112
-
113
-			var p parser
114
-			switch hdr.Typeflag {
115
-			case TypeGNULongName:
116
-				gnuLongName = p.parseString(realname)
117
-			case TypeGNULongLink:
118
-				gnuLongLink = p.parseString(realname)
119
-			}
120
-			continue loop // This is a meta header affecting the next header
121
-		default:
122
-			// The old GNU sparse format is handled here since it is technically
123
-			// just a regular file with additional attributes.
124
-
125
-			if err := mergePAX(hdr, paxHdrs); err != nil {
126
-				return nil, err
127
-			}
128
-			if gnuLongName != "" {
129
-				hdr.Name = gnuLongName
130
-			}
131
-			if gnuLongLink != "" {
132
-				hdr.Linkname = gnuLongLink
133
-			}
134
-			if hdr.Typeflag == TypeRegA && strings.HasSuffix(hdr.Name, "/") {
135
-				hdr.Typeflag = TypeDir // Legacy archives use trailing slash for directories
136
-			}
137
-
138
-			// The extended headers may have updated the size.
139
-			// Thus, setup the regFileReader again after merging PAX headers.
140
-			if err := tr.handleRegularFile(hdr); err != nil {
141
-				return nil, err
142
-			}
143
-
144
-			// Sparse formats rely on being able to read from the logical data
145
-			// section; there must be a preceding call to handleRegularFile.
146
-			if err := tr.handleSparseFile(hdr, rawHdr); err != nil {
147
-				return nil, err
148
-			}
149
-
150
-			// Set the final guess at the format.
151
-			if format.has(FormatUSTAR) && format.has(FormatPAX) {
152
-				format.mayOnlyBe(FormatUSTAR)
153
-			}
154
-			hdr.Format = format
155
-			return hdr, nil // This is a file, so stop
156
-		}
157
-	}
158
-}
159
-
160
-// handleRegularFile sets up the current file reader and padding such that it
161
-// can only read the following logical data section. It will properly handle
162
-// special headers that contain no data section.
163
-func (tr *Reader) handleRegularFile(hdr *Header) error {
164
-	nb := hdr.Size
165
-	if isHeaderOnlyType(hdr.Typeflag) {
166
-		nb = 0
167
-	}
168
-	if nb < 0 {
169
-		return ErrHeader
170
-	}
171
-
172
-	tr.pad = blockPadding(nb)
173
-	tr.curr = &regFileReader{r: tr.r, nb: nb}
174
-	return nil
175
-}
176
-
177
-// handleSparseFile checks if the current file is a sparse format of any type
178
-// and sets the curr reader appropriately.
179
-func (tr *Reader) handleSparseFile(hdr *Header, rawHdr *block) error {
180
-	var spd sparseDatas
181
-	var err error
182
-	if hdr.Typeflag == TypeGNUSparse {
183
-		spd, err = tr.readOldGNUSparseMap(hdr, rawHdr)
184
-	} else {
185
-		spd, err = tr.readGNUSparsePAXHeaders(hdr)
186
-	}
187
-
188
-	// If sp is non-nil, then this is a sparse file.
189
-	// Note that it is possible for len(sp) == 0.
190
-	if err == nil && spd != nil {
191
-		if isHeaderOnlyType(hdr.Typeflag) || !validateSparseEntries(spd, hdr.Size) {
192
-			return ErrHeader
193
-		}
194
-		sph := invertSparseEntries(spd, hdr.Size)
195
-		tr.curr = &sparseFileReader{tr.curr, sph, 0}
196
-	}
197
-	return err
198
-}
199
-
200
-// readGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers.
201
-// If they are found, then this function reads the sparse map and returns it.
202
-// This assumes that 0.0 headers have already been converted to 0.1 headers
203
-// by the the PAX header parsing logic.
204
-func (tr *Reader) readGNUSparsePAXHeaders(hdr *Header) (sparseDatas, error) {
205
-	// Identify the version of GNU headers.
206
-	var is1x0 bool
207
-	major, minor := hdr.PAXRecords[paxGNUSparseMajor], hdr.PAXRecords[paxGNUSparseMinor]
208
-	switch {
209
-	case major == "0" && (minor == "0" || minor == "1"):
210
-		is1x0 = false
211
-	case major == "1" && minor == "0":
212
-		is1x0 = true
213
-	case major != "" || minor != "":
214
-		return nil, nil // Unknown GNU sparse PAX version
215
-	case hdr.PAXRecords[paxGNUSparseMap] != "":
216
-		is1x0 = false // 0.0 and 0.1 did not have explicit version records, so guess
217
-	default:
218
-		return nil, nil // Not a PAX format GNU sparse file.
219
-	}
220
-	hdr.Format.mayOnlyBe(FormatPAX)
221
-
222
-	// Update hdr from GNU sparse PAX headers.
223
-	if name := hdr.PAXRecords[paxGNUSparseName]; name != "" {
224
-		hdr.Name = name
225
-	}
226
-	size := hdr.PAXRecords[paxGNUSparseSize]
227
-	if size == "" {
228
-		size = hdr.PAXRecords[paxGNUSparseRealSize]
229
-	}
230
-	if size != "" {
231
-		n, err := strconv.ParseInt(size, 10, 64)
232
-		if err != nil {
233
-			return nil, ErrHeader
234
-		}
235
-		hdr.Size = n
236
-	}
237
-
238
-	// Read the sparse map according to the appropriate format.
239
-	if is1x0 {
240
-		return readGNUSparseMap1x0(tr.curr)
241
-	}
242
-	return readGNUSparseMap0x1(hdr.PAXRecords)
243
-}
244
-
245
-// mergePAX merges paxHdrs into hdr for all relevant fields of Header.
246
-func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) {
247
-	for k, v := range paxHdrs {
248
-		if v == "" {
249
-			continue // Keep the original USTAR value
250
-		}
251
-		var id64 int64
252
-		switch k {
253
-		case paxPath:
254
-			hdr.Name = v
255
-		case paxLinkpath:
256
-			hdr.Linkname = v
257
-		case paxUname:
258
-			hdr.Uname = v
259
-		case paxGname:
260
-			hdr.Gname = v
261
-		case paxUid:
262
-			id64, err = strconv.ParseInt(v, 10, 64)
263
-			hdr.Uid = int(id64) // Integer overflow possible
264
-		case paxGid:
265
-			id64, err = strconv.ParseInt(v, 10, 64)
266
-			hdr.Gid = int(id64) // Integer overflow possible
267
-		case paxAtime:
268
-			hdr.AccessTime, err = parsePAXTime(v)
269
-		case paxMtime:
270
-			hdr.ModTime, err = parsePAXTime(v)
271
-		case paxCtime:
272
-			hdr.ChangeTime, err = parsePAXTime(v)
273
-		case paxSize:
274
-			hdr.Size, err = strconv.ParseInt(v, 10, 64)
275
-		default:
276
-			if strings.HasPrefix(k, paxSchilyXattr) {
277
-				if hdr.Xattrs == nil {
278
-					hdr.Xattrs = make(map[string]string)
279
-				}
280
-				hdr.Xattrs[k[len(paxSchilyXattr):]] = v
281
-			}
282
-		}
283
-		if err != nil {
284
-			return ErrHeader
285
-		}
286
-	}
287
-	hdr.PAXRecords = paxHdrs
288
-	return nil
289
-}
290
-
291
-// parsePAX parses PAX headers.
292
-// If an extended header (type 'x') is invalid, ErrHeader is returned
293
-func parsePAX(r io.Reader) (map[string]string, error) {
294
-	buf, err := ioutil.ReadAll(r)
295
-	if err != nil {
296
-		return nil, err
297
-	}
298
-	sbuf := string(buf)
299
-
300
-	// For GNU PAX sparse format 0.0 support.
301
-	// This function transforms the sparse format 0.0 headers into format 0.1
302
-	// headers since 0.0 headers were not PAX compliant.
303
-	var sparseMap []string
304
-
305
-	paxHdrs := make(map[string]string)
306
-	for len(sbuf) > 0 {
307
-		key, value, residual, err := parsePAXRecord(sbuf)
308
-		if err != nil {
309
-			return nil, ErrHeader
310
-		}
311
-		sbuf = residual
312
-
313
-		switch key {
314
-		case paxGNUSparseOffset, paxGNUSparseNumBytes:
315
-			// Validate sparse header order and value.
316
-			if (len(sparseMap)%2 == 0 && key != paxGNUSparseOffset) ||
317
-				(len(sparseMap)%2 == 1 && key != paxGNUSparseNumBytes) ||
318
-				strings.Contains(value, ",") {
319
-				return nil, ErrHeader
320
-			}
321
-			sparseMap = append(sparseMap, value)
322
-		default:
323
-			paxHdrs[key] = value
324
-		}
325
-	}
326
-	if len(sparseMap) > 0 {
327
-		paxHdrs[paxGNUSparseMap] = strings.Join(sparseMap, ",")
328
-	}
329
-	return paxHdrs, nil
330
-}
331
-
332
-// readHeader reads the next block header and assumes that the underlying reader
333
-// is already aligned to a block boundary. It returns the raw block of the
334
-// header in case further processing is required.
335
-//
336
-// The err will be set to io.EOF only when one of the following occurs:
337
-//	* Exactly 0 bytes are read and EOF is hit.
338
-//	* Exactly 1 block of zeros is read and EOF is hit.
339
-//	* At least 2 blocks of zeros are read.
340
-func (tr *Reader) readHeader() (*Header, *block, error) {
341
-	// Two blocks of zero bytes marks the end of the archive.
342
-	if _, err := io.ReadFull(tr.r, tr.blk[:]); err != nil {
343
-		return nil, nil, err // EOF is okay here; exactly 0 bytes read
344
-	}
345
-	if bytes.Equal(tr.blk[:], zeroBlock[:]) {
346
-		if _, err := io.ReadFull(tr.r, tr.blk[:]); err != nil {
347
-			return nil, nil, err // EOF is okay here; exactly 1 block of zeros read
348
-		}
349
-		if bytes.Equal(tr.blk[:], zeroBlock[:]) {
350
-			return nil, nil, io.EOF // normal EOF; exactly 2 block of zeros read
351
-		}
352
-		return nil, nil, ErrHeader // Zero block and then non-zero block
353
-	}
354
-
355
-	// Verify the header matches a known format.
356
-	format := tr.blk.GetFormat()
357
-	if format == FormatUnknown {
358
-		return nil, nil, ErrHeader
359
-	}
360
-
361
-	var p parser
362
-	hdr := new(Header)
363
-
364
-	// Unpack the V7 header.
365
-	v7 := tr.blk.V7()
366
-	hdr.Typeflag = v7.TypeFlag()[0]
367
-	hdr.Name = p.parseString(v7.Name())
368
-	hdr.Linkname = p.parseString(v7.LinkName())
369
-	hdr.Size = p.parseNumeric(v7.Size())
370
-	hdr.Mode = p.parseNumeric(v7.Mode())
371
-	hdr.Uid = int(p.parseNumeric(v7.UID()))
372
-	hdr.Gid = int(p.parseNumeric(v7.GID()))
373
-	hdr.ModTime = time.Unix(p.parseNumeric(v7.ModTime()), 0)
374
-
375
-	// Unpack format specific fields.
376
-	if format > formatV7 {
377
-		ustar := tr.blk.USTAR()
378
-		hdr.Uname = p.parseString(ustar.UserName())
379
-		hdr.Gname = p.parseString(ustar.GroupName())
380
-		hdr.Devmajor = p.parseNumeric(ustar.DevMajor())
381
-		hdr.Devminor = p.parseNumeric(ustar.DevMinor())
382
-
383
-		var prefix string
384
-		switch {
385
-		case format.has(FormatUSTAR | FormatPAX):
386
-			hdr.Format = format
387
-			ustar := tr.blk.USTAR()
388
-			prefix = p.parseString(ustar.Prefix())
389
-
390
-			// For Format detection, check if block is properly formatted since
391
-			// the parser is more liberal than what USTAR actually permits.
392
-			notASCII := func(r rune) bool { return r >= 0x80 }
393
-			if bytes.IndexFunc(tr.blk[:], notASCII) >= 0 {
394
-				hdr.Format = FormatUnknown // Non-ASCII characters in block.
395
-			}
396
-			nul := func(b []byte) bool { return int(b[len(b)-1]) == 0 }
397
-			if !(nul(v7.Size()) && nul(v7.Mode()) && nul(v7.UID()) && nul(v7.GID()) &&
398
-				nul(v7.ModTime()) && nul(ustar.DevMajor()) && nul(ustar.DevMinor())) {
399
-				hdr.Format = FormatUnknown // Numeric fields must end in NUL
400
-			}
401
-		case format.has(formatSTAR):
402
-			star := tr.blk.STAR()
403
-			prefix = p.parseString(star.Prefix())
404
-			hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0)
405
-			hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0)
406
-		case format.has(FormatGNU):
407
-			hdr.Format = format
408
-			var p2 parser
409
-			gnu := tr.blk.GNU()
410
-			if b := gnu.AccessTime(); b[0] != 0 {
411
-				hdr.AccessTime = time.Unix(p2.parseNumeric(b), 0)
412
-			}
413
-			if b := gnu.ChangeTime(); b[0] != 0 {
414
-				hdr.ChangeTime = time.Unix(p2.parseNumeric(b), 0)
415
-			}
416
-
417
-			// Prior to Go1.8, the Writer had a bug where it would output
418
-			// an invalid tar file in certain rare situations because the logic
419
-			// incorrectly believed that the old GNU format had a prefix field.
420
-			// This is wrong and leads to an output file that mangles the
421
-			// atime and ctime fields, which are often left unused.
422
-			//
423
-			// In order to continue reading tar files created by former, buggy
424
-			// versions of Go, we skeptically parse the atime and ctime fields.
425
-			// If we are unable to parse them and the prefix field looks like
426
-			// an ASCII string, then we fallback on the pre-Go1.8 behavior
427
-			// of treating these fields as the USTAR prefix field.
428
-			//
429
-			// Note that this will not use the fallback logic for all possible
430
-			// files generated by a pre-Go1.8 toolchain. If the generated file
431
-			// happened to have a prefix field that parses as valid
432
-			// atime and ctime fields (e.g., when they are valid octal strings),
433
-			// then it is impossible to distinguish between an valid GNU file
434
-			// and an invalid pre-Go1.8 file.
435
-			//
436
-			// See https://golang.org/issues/12594
437
-			// See https://golang.org/issues/21005
438
-			if p2.err != nil {
439
-				hdr.AccessTime, hdr.ChangeTime = time.Time{}, time.Time{}
440
-				ustar := tr.blk.USTAR()
441
-				if s := p.parseString(ustar.Prefix()); isASCII(s) {
442
-					prefix = s
443
-				}
444
-				hdr.Format = FormatUnknown // Buggy file is not GNU
445
-			}
446
-		}
447
-		if len(prefix) > 0 {
448
-			hdr.Name = prefix + "/" + hdr.Name
449
-		}
450
-	}
451
-	return hdr, &tr.blk, p.err
452
-}
453
-
454
-// readOldGNUSparseMap reads the sparse map from the old GNU sparse format.
455
-// The sparse map is stored in the tar header if it's small enough.
456
-// If it's larger than four entries, then one or more extension headers are used
457
-// to store the rest of the sparse map.
458
-//
459
-// The Header.Size does not reflect the size of any extended headers used.
460
-// Thus, this function will read from the raw io.Reader to fetch extra headers.
461
-// This method mutates blk in the process.
462
-func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) (sparseDatas, error) {
463
-	// Make sure that the input format is GNU.
464
-	// Unfortunately, the STAR format also has a sparse header format that uses
465
-	// the same type flag but has a completely different layout.
466
-	if blk.GetFormat() != FormatGNU {
467
-		return nil, ErrHeader
468
-	}
469
-	hdr.Format.mayOnlyBe(FormatGNU)
470
-
471
-	var p parser
472
-	hdr.Size = p.parseNumeric(blk.GNU().RealSize())
473
-	if p.err != nil {
474
-		return nil, p.err
475
-	}
476
-	s := blk.GNU().Sparse()
477
-	spd := make(sparseDatas, 0, s.MaxEntries())
478
-	for {
479
-		for i := 0; i < s.MaxEntries(); i++ {
480
-			// This termination condition is identical to GNU and BSD tar.
481
-			if s.Entry(i).Offset()[0] == 0x00 {
482
-				break // Don't return, need to process extended headers (even if empty)
483
-			}
484
-			offset := p.parseNumeric(s.Entry(i).Offset())
485
-			length := p.parseNumeric(s.Entry(i).Length())
486
-			if p.err != nil {
487
-				return nil, p.err
488
-			}
489
-			spd = append(spd, sparseEntry{Offset: offset, Length: length})
490
-		}
491
-
492
-		if s.IsExtended()[0] > 0 {
493
-			// There are more entries. Read an extension header and parse its entries.
494
-			if _, err := mustReadFull(tr.r, blk[:]); err != nil {
495
-				return nil, err
496
-			}
497
-			s = blk.Sparse()
498
-			continue
499
-		}
500
-		return spd, nil // Done
501
-	}
502
-}
503
-
504
-// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
505
-// version 1.0. The format of the sparse map consists of a series of
506
-// newline-terminated numeric fields. The first field is the number of entries
507
-// and is always present. Following this are the entries, consisting of two
508
-// fields (offset, length). This function must stop reading at the end
509
-// boundary of the block containing the last newline.
510
-//
511
-// Note that the GNU manual says that numeric values should be encoded in octal
512
-// format. However, the GNU tar utility itself outputs these values in decimal.
513
-// As such, this library treats values as being encoded in decimal.
514
-func readGNUSparseMap1x0(r io.Reader) (sparseDatas, error) {
515
-	var (
516
-		cntNewline int64
517
-		buf        bytes.Buffer
518
-		blk        block
519
-	)
520
-
521
-	// feedTokens copies data in blocks from r into buf until there are
522
-	// at least cnt newlines in buf. It will not read more blocks than needed.
523
-	feedTokens := func(n int64) error {
524
-		for cntNewline < n {
525
-			if _, err := mustReadFull(r, blk[:]); err != nil {
526
-				return err
527
-			}
528
-			buf.Write(blk[:])
529
-			for _, c := range blk {
530
-				if c == '\n' {
531
-					cntNewline++
532
-				}
533
-			}
534
-		}
535
-		return nil
536
-	}
537
-
538
-	// nextToken gets the next token delimited by a newline. This assumes that
539
-	// at least one newline exists in the buffer.
540
-	nextToken := func() string {
541
-		cntNewline--
542
-		tok, _ := buf.ReadString('\n')
543
-		return strings.TrimRight(tok, "\n")
544
-	}
545
-
546
-	// Parse for the number of entries.
547
-	// Use integer overflow resistant math to check this.
548
-	if err := feedTokens(1); err != nil {
549
-		return nil, err
550
-	}
551
-	numEntries, err := strconv.ParseInt(nextToken(), 10, 0) // Intentionally parse as native int
552
-	if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
553
-		return nil, ErrHeader
554
-	}
555
-
556
-	// Parse for all member entries.
557
-	// numEntries is trusted after this since a potential attacker must have
558
-	// committed resources proportional to what this library used.
559
-	if err := feedTokens(2 * numEntries); err != nil {
560
-		return nil, err
561
-	}
562
-	spd := make(sparseDatas, 0, numEntries)
563
-	for i := int64(0); i < numEntries; i++ {
564
-		offset, err1 := strconv.ParseInt(nextToken(), 10, 64)
565
-		length, err2 := strconv.ParseInt(nextToken(), 10, 64)
566
-		if err1 != nil || err2 != nil {
567
-			return nil, ErrHeader
568
-		}
569
-		spd = append(spd, sparseEntry{Offset: offset, Length: length})
570
-	}
571
-	return spd, nil
572
-}
573
-
574
-// readGNUSparseMap0x1 reads the sparse map as stored in GNU's PAX sparse format
575
-// version 0.1. The sparse map is stored in the PAX headers.
576
-func readGNUSparseMap0x1(paxHdrs map[string]string) (sparseDatas, error) {
577
-	// Get number of entries.
578
-	// Use integer overflow resistant math to check this.
579
-	numEntriesStr := paxHdrs[paxGNUSparseNumBlocks]
580
-	numEntries, err := strconv.ParseInt(numEntriesStr, 10, 0) // Intentionally parse as native int
581
-	if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
582
-		return nil, ErrHeader
583
-	}
584
-
585
-	// There should be two numbers in sparseMap for each entry.
586
-	sparseMap := strings.Split(paxHdrs[paxGNUSparseMap], ",")
587
-	if len(sparseMap) == 1 && sparseMap[0] == "" {
588
-		sparseMap = sparseMap[:0]
589
-	}
590
-	if int64(len(sparseMap)) != 2*numEntries {
591
-		return nil, ErrHeader
592
-	}
593
-
594
-	// Loop through the entries in the sparse map.
595
-	// numEntries is trusted now.
596
-	spd := make(sparseDatas, 0, numEntries)
597
-	for len(sparseMap) >= 2 {
598
-		offset, err1 := strconv.ParseInt(sparseMap[0], 10, 64)
599
-		length, err2 := strconv.ParseInt(sparseMap[1], 10, 64)
600
-		if err1 != nil || err2 != nil {
601
-			return nil, ErrHeader
602
-		}
603
-		spd = append(spd, sparseEntry{Offset: offset, Length: length})
604
-		sparseMap = sparseMap[2:]
605
-	}
606
-	return spd, nil
607
-}
608
-
609
-// Read reads from the current file in the tar archive.
610
-// It returns (0, io.EOF) when it reaches the end of that file,
611
-// until Next is called to advance to the next file.
612
-//
613
-// If the current file is sparse, then the regions marked as a hole
614
-// are read back as NUL-bytes.
615
-//
616
-// Calling Read on special types like TypeLink, TypeSymlink, TypeChar,
617
-// TypeBlock, TypeDir, and TypeFifo returns (0, io.EOF) regardless of what
618
-// the Header.Size claims.
619
-func (tr *Reader) Read(b []byte) (int, error) {
620
-	if tr.err != nil {
621
-		return 0, tr.err
622
-	}
623
-	n, err := tr.curr.Read(b)
624
-	if err != nil && err != io.EOF {
625
-		tr.err = err
626
-	}
627
-	return n, err
628
-}
629
-
630
-// writeTo writes the content of the current file to w.
631
-// The bytes written matches the number of remaining bytes in the current file.
632
-//
633
-// If the current file is sparse and w is an io.WriteSeeker,
634
-// then writeTo uses Seek to skip past holes defined in Header.SparseHoles,
635
-// assuming that skipped regions are filled with NULs.
636
-// This always writes the last byte to ensure w is the right size.
637
-//
638
-// TODO(dsnet): Re-export this when adding sparse file support.
639
-// See https://golang.org/issue/22735
640
-func (tr *Reader) writeTo(w io.Writer) (int64, error) {
641
-	if tr.err != nil {
642
-		return 0, tr.err
643
-	}
644
-	n, err := tr.curr.WriteTo(w)
645
-	if err != nil {
646
-		tr.err = err
647
-	}
648
-	return n, err
649
-}
650
-
651
-// regFileReader is a fileReader for reading data from a regular file entry.
652
-type regFileReader struct {
653
-	r  io.Reader // Underlying Reader
654
-	nb int64     // Number of remaining bytes to read
655
-}
656
-
657
-func (fr *regFileReader) Read(b []byte) (n int, err error) {
658
-	if int64(len(b)) > fr.nb {
659
-		b = b[:fr.nb]
660
-	}
661
-	if len(b) > 0 {
662
-		n, err = fr.r.Read(b)
663
-		fr.nb -= int64(n)
664
-	}
665
-	switch {
666
-	case err == io.EOF && fr.nb > 0:
667
-		return n, io.ErrUnexpectedEOF
668
-	case err == nil && fr.nb == 0:
669
-		return n, io.EOF
670
-	default:
671
-		return n, err
672
-	}
673
-}
674
-
675
-func (fr *regFileReader) WriteTo(w io.Writer) (int64, error) {
676
-	return io.Copy(w, struct{ io.Reader }{fr})
677
-}
678
-
679
-func (fr regFileReader) LogicalRemaining() int64 {
680
-	return fr.nb
681
-}
682
-
683
-func (fr regFileReader) PhysicalRemaining() int64 {
684
-	return fr.nb
685
-}
686
-
687
-// sparseFileReader is a fileReader for reading data from a sparse file entry.
688
-type sparseFileReader struct {
689
-	fr  fileReader  // Underlying fileReader
690
-	sp  sparseHoles // Normalized list of sparse holes
691
-	pos int64       // Current position in sparse file
692
-}
693
-
694
-func (sr *sparseFileReader) Read(b []byte) (n int, err error) {
695
-	finished := int64(len(b)) >= sr.LogicalRemaining()
696
-	if finished {
697
-		b = b[:sr.LogicalRemaining()]
698
-	}
699
-
700
-	b0 := b
701
-	endPos := sr.pos + int64(len(b))
702
-	for endPos > sr.pos && err == nil {
703
-		var nf int // Bytes read in fragment
704
-		holeStart, holeEnd := sr.sp[0].Offset, sr.sp[0].endOffset()
705
-		if sr.pos < holeStart { // In a data fragment
706
-			bf := b[:min(int64(len(b)), holeStart-sr.pos)]
707
-			nf, err = tryReadFull(sr.fr, bf)
708
-		} else { // In a hole fragment
709
-			bf := b[:min(int64(len(b)), holeEnd-sr.pos)]
710
-			nf, err = tryReadFull(zeroReader{}, bf)
711
-		}
712
-		b = b[nf:]
713
-		sr.pos += int64(nf)
714
-		if sr.pos >= holeEnd && len(sr.sp) > 1 {
715
-			sr.sp = sr.sp[1:] // Ensure last fragment always remains
716
-		}
717
-	}
718
-
719
-	n = len(b0) - len(b)
720
-	switch {
721
-	case err == io.EOF:
722
-		return n, errMissData // Less data in dense file than sparse file
723
-	case err != nil:
724
-		return n, err
725
-	case sr.LogicalRemaining() == 0 && sr.PhysicalRemaining() > 0:
726
-		return n, errUnrefData // More data in dense file than sparse file
727
-	case finished:
728
-		return n, io.EOF
729
-	default:
730
-		return n, nil
731
-	}
732
-}
733
-
734
-func (sr *sparseFileReader) WriteTo(w io.Writer) (n int64, err error) {
735
-	ws, ok := w.(io.WriteSeeker)
736
-	if ok {
737
-		if _, err := ws.Seek(0, io.SeekCurrent); err != nil {
738
-			ok = false // Not all io.Seeker can really seek
739
-		}
740
-	}
741
-	if !ok {
742
-		return io.Copy(w, struct{ io.Reader }{sr})
743
-	}
744
-
745
-	var writeLastByte bool
746
-	pos0 := sr.pos
747
-	for sr.LogicalRemaining() > 0 && !writeLastByte && err == nil {
748
-		var nf int64 // Size of fragment
749
-		holeStart, holeEnd := sr.sp[0].Offset, sr.sp[0].endOffset()
750
-		if sr.pos < holeStart { // In a data fragment
751
-			nf = holeStart - sr.pos
752
-			nf, err = io.CopyN(ws, sr.fr, nf)
753
-		} else { // In a hole fragment
754
-			nf = holeEnd - sr.pos
755
-			if sr.PhysicalRemaining() == 0 {
756
-				writeLastByte = true
757
-				nf--
758
-			}
759
-			_, err = ws.Seek(nf, io.SeekCurrent)
760
-		}
761
-		sr.pos += nf
762
-		if sr.pos >= holeEnd && len(sr.sp) > 1 {
763
-			sr.sp = sr.sp[1:] // Ensure last fragment always remains
764
-		}
765
-	}
766
-
767
-	// If the last fragment is a hole, then seek to 1-byte before EOF, and
768
-	// write a single byte to ensure the file is the right size.
769
-	if writeLastByte && err == nil {
770
-		_, err = ws.Write([]byte{0})
771
-		sr.pos++
772
-	}
773
-
774
-	n = sr.pos - pos0
775
-	switch {
776
-	case err == io.EOF:
777
-		return n, errMissData // Less data in dense file than sparse file
778
-	case err != nil:
779
-		return n, err
780
-	case sr.LogicalRemaining() == 0 && sr.PhysicalRemaining() > 0:
781
-		return n, errUnrefData // More data in dense file than sparse file
782
-	default:
783
-		return n, nil
784
-	}
785
-}
786
-
787
-func (sr sparseFileReader) LogicalRemaining() int64 {
788
-	return sr.sp[len(sr.sp)-1].endOffset() - sr.pos
789
-}
790
-func (sr sparseFileReader) PhysicalRemaining() int64 {
791
-	return sr.fr.PhysicalRemaining()
792
-}
793
-
794
-type zeroReader struct{}
795
-
796
-func (zeroReader) Read(b []byte) (int, error) {
797
-	for i := range b {
798
-		b[i] = 0
799
-	}
800
-	return len(b), nil
801
-}
802
-
803
-// mustReadFull is like io.ReadFull except it returns
804
-// io.ErrUnexpectedEOF when io.EOF is hit before len(b) bytes are read.
805
-func mustReadFull(r io.Reader, b []byte) (int, error) {
806
-	n, err := tryReadFull(r, b)
807
-	if err == io.EOF {
808
-		err = io.ErrUnexpectedEOF
809
-	}
810
-	return n, err
811
-}
812
-
813
-// tryReadFull is like io.ReadFull except it returns
814
-// io.EOF when it is hit before len(b) bytes are read.
815
-func tryReadFull(r io.Reader, b []byte) (n int, err error) {
816
-	for len(b) > n && err == nil {
817
-		var nn int
818
-		nn, err = r.Read(b[n:])
819
-		n += nn
820
-	}
821
-	if len(b) == n && err == io.EOF {
822
-		err = nil
823
-	}
824
-	return n, err
825
-}
826
-
827
-// discard skips n bytes in r, reporting an error if unable to do so.
828
-func discard(r io.Reader, n int64) error {
829
-	// If possible, Seek to the last byte before the end of the data section.
830
-	// Do this because Seek is often lazy about reporting errors; this will mask
831
-	// the fact that the stream may be truncated. We can rely on the
832
-	// io.CopyN done shortly afterwards to trigger any IO errors.
833
-	var seekSkipped int64 // Number of bytes skipped via Seek
834
-	if sr, ok := r.(io.Seeker); ok && n > 1 {
835
-		// Not all io.Seeker can actually Seek. For example, os.Stdin implements
836
-		// io.Seeker, but calling Seek always returns an error and performs
837
-		// no action. Thus, we try an innocent seek to the current position
838
-		// to see if Seek is really supported.
839
-		pos1, err := sr.Seek(0, io.SeekCurrent)
840
-		if pos1 >= 0 && err == nil {
841
-			// Seek seems supported, so perform the real Seek.
842
-			pos2, err := sr.Seek(n-1, io.SeekCurrent)
843
-			if pos2 < 0 || err != nil {
844
-				return err
845
-			}
846
-			seekSkipped = pos2 - pos1
847
-		}
848
-	}
849
-
850
-	copySkipped, err := io.CopyN(ioutil.Discard, r, n-seekSkipped)
851
-	if err == io.EOF && seekSkipped+copySkipped < n {
852
-		err = io.ErrUnexpectedEOF
853
-	}
854
-	return err
855
-}
856 1
deleted file mode 100644
... ...
@@ -1,20 +0,0 @@
1
-// Copyright 2012 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
-// +build linux dragonfly openbsd solaris
6
-
7
-package tar
8
-
9
-import (
10
-	"syscall"
11
-	"time"
12
-)
13
-
14
-func statAtime(st *syscall.Stat_t) time.Time {
15
-	return time.Unix(st.Atim.Unix())
16
-}
17
-
18
-func statCtime(st *syscall.Stat_t) time.Time {
19
-	return time.Unix(st.Ctim.Unix())
20
-}
21 1
deleted file mode 100644
... ...
@@ -1,20 +0,0 @@
1
-// Copyright 2012 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
-// +build darwin freebsd netbsd
6
-
7
-package tar
8
-
9
-import (
10
-	"syscall"
11
-	"time"
12
-)
13
-
14
-func statAtime(st *syscall.Stat_t) time.Time {
15
-	return time.Unix(st.Atimespec.Unix())
16
-}
17
-
18
-func statCtime(st *syscall.Stat_t) time.Time {
19
-	return time.Unix(st.Ctimespec.Unix())
20
-}
21 1
deleted file mode 100644
... ...
@@ -1,76 +0,0 @@
1
-// Copyright 2012 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
-// +build linux darwin dragonfly freebsd openbsd netbsd solaris
6
-
7
-package tar
8
-
9
-import (
10
-	"os"
11
-	"runtime"
12
-	"syscall"
13
-)
14
-
15
-func init() {
16
-	sysStat = statUnix
17
-}
18
-
19
-func statUnix(fi os.FileInfo, h *Header) error {
20
-	sys, ok := fi.Sys().(*syscall.Stat_t)
21
-	if !ok {
22
-		return nil
23
-	}
24
-	h.Uid = int(sys.Uid)
25
-	h.Gid = int(sys.Gid)
26
-
27
-	// TODO(bradfitz): populate username & group.  os/user
28
-	// doesn't cache LookupId lookups, and lacks group
29
-	// lookup functions.
30
-	h.AccessTime = statAtime(sys)
31
-	h.ChangeTime = statCtime(sys)
32
-
33
-	// Best effort at populating Devmajor and Devminor.
34
-	if h.Typeflag == TypeChar || h.Typeflag == TypeBlock {
35
-		dev := uint64(sys.Rdev) // May be int32 or uint32
36
-		switch runtime.GOOS {
37
-		case "linux":
38
-			// Copied from golang.org/x/sys/unix/dev_linux.go.
39
-			major := uint32((dev & 0x00000000000fff00) >> 8)
40
-			major |= uint32((dev & 0xfffff00000000000) >> 32)
41
-			minor := uint32((dev & 0x00000000000000ff) >> 0)
42
-			minor |= uint32((dev & 0x00000ffffff00000) >> 12)
43
-			h.Devmajor, h.Devminor = int64(major), int64(minor)
44
-		case "darwin":
45
-			// Copied from golang.org/x/sys/unix/dev_darwin.go.
46
-			major := uint32((dev >> 24) & 0xff)
47
-			minor := uint32(dev & 0xffffff)
48
-			h.Devmajor, h.Devminor = int64(major), int64(minor)
49
-		case "dragonfly":
50
-			// Copied from golang.org/x/sys/unix/dev_dragonfly.go.
51
-			major := uint32((dev >> 8) & 0xff)
52
-			minor := uint32(dev & 0xffff00ff)
53
-			h.Devmajor, h.Devminor = int64(major), int64(minor)
54
-		case "freebsd":
55
-			// Copied from golang.org/x/sys/unix/dev_freebsd.go.
56
-			major := uint32((dev >> 8) & 0xff)
57
-			minor := uint32(dev & 0xffff00ff)
58
-			h.Devmajor, h.Devminor = int64(major), int64(minor)
59
-		case "netbsd":
60
-			// Copied from golang.org/x/sys/unix/dev_netbsd.go.
61
-			major := uint32((dev & 0x000fff00) >> 8)
62
-			minor := uint32((dev & 0x000000ff) >> 0)
63
-			minor |= uint32((dev & 0xfff00000) >> 12)
64
-			h.Devmajor, h.Devminor = int64(major), int64(minor)
65
-		case "openbsd":
66
-			// Copied from golang.org/x/sys/unix/dev_openbsd.go.
67
-			major := uint32((dev & 0x0000ff00) >> 8)
68
-			minor := uint32((dev & 0x000000ff) >> 0)
69
-			minor |= uint32((dev & 0xffff0000) >> 8)
70
-			h.Devmajor, h.Devminor = int64(major), int64(minor)
71
-		default:
72
-			// TODO: Implement solaris (see https://golang.org/issue/8106)
73
-		}
74
-	}
75
-	return nil
76
-}
77 1
deleted file mode 100644
... ...
@@ -1,326 +0,0 @@
1
-// Copyright 2016 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
-	"strconv"
11
-	"strings"
12
-	"time"
13
-)
14
-
15
-// hasNUL reports whether the NUL character exists within s.
16
-func hasNUL(s string) bool {
17
-	return strings.IndexByte(s, 0) >= 0
18
-}
19
-
20
-// isASCII reports whether the input is an ASCII C-style string.
21
-func isASCII(s string) bool {
22
-	for _, c := range s {
23
-		if c >= 0x80 || c == 0x00 {
24
-			return false
25
-		}
26
-	}
27
-	return true
28
-}
29
-
30
-// toASCII converts the input to an ASCII C-style string.
31
-// This a best effort conversion, so invalid characters are dropped.
32
-func toASCII(s string) string {
33
-	if isASCII(s) {
34
-		return s
35
-	}
36
-	b := make([]byte, 0, len(s))
37
-	for _, c := range s {
38
-		if c < 0x80 && c != 0x00 {
39
-			b = append(b, byte(c))
40
-		}
41
-	}
42
-	return string(b)
43
-}
44
-
45
-type parser struct {
46
-	err error // Last error seen
47
-}
48
-
49
-type formatter struct {
50
-	err error // Last error seen
51
-}
52
-
53
-// parseString parses bytes as a NUL-terminated C-style string.
54
-// If a NUL byte is not found then the whole slice is returned as a string.
55
-func (*parser) parseString(b []byte) string {
56
-	if i := bytes.IndexByte(b, 0); i >= 0 {
57
-		return string(b[:i])
58
-	}
59
-	return string(b)
60
-}
61
-
62
-// formatString copies s into b, NUL-terminating if possible.
63
-func (f *formatter) formatString(b []byte, s string) {
64
-	if len(s) > len(b) {
65
-		f.err = ErrFieldTooLong
66
-	}
67
-	copy(b, s)
68
-	if len(s) < len(b) {
69
-		b[len(s)] = 0
70
-	}
71
-
72
-	// Some buggy readers treat regular files with a trailing slash
73
-	// in the V7 path field as a directory even though the full path
74
-	// recorded elsewhere (e.g., via PAX record) contains no trailing slash.
75
-	if len(s) > len(b) && b[len(b)-1] == '/' {
76
-		n := len(strings.TrimRight(s[:len(b)], "/"))
77
-		b[n] = 0 // Replace trailing slash with NUL terminator
78
-	}
79
-}
80
-
81
-// fitsInBase256 reports whether x can be encoded into n bytes using base-256
82
-// encoding. Unlike octal encoding, base-256 encoding does not require that the
83
-// string ends with a NUL character. Thus, all n bytes are available for output.
84
-//
85
-// If operating in binary mode, this assumes strict GNU binary mode; which means
86
-// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
87
-// equivalent to the sign bit in two's complement form.
88
-func fitsInBase256(n int, x int64) bool {
89
-	binBits := uint(n-1) * 8
90
-	return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
91
-}
92
-
93
-// parseNumeric parses the input as being encoded in either base-256 or octal.
94
-// This function may return negative numbers.
95
-// If parsing fails or an integer overflow occurs, err will be set.
96
-func (p *parser) parseNumeric(b []byte) int64 {
97
-	// Check for base-256 (binary) format first.
98
-	// If the first bit is set, then all following bits constitute a two's
99
-	// complement encoded number in big-endian byte order.
100
-	if len(b) > 0 && b[0]&0x80 != 0 {
101
-		// Handling negative numbers relies on the following identity:
102
-		//	-a-1 == ^a
103
-		//
104
-		// If the number is negative, we use an inversion mask to invert the
105
-		// data bytes and treat the value as an unsigned number.
106
-		var inv byte // 0x00 if positive or zero, 0xff if negative
107
-		if b[0]&0x40 != 0 {
108
-			inv = 0xff
109
-		}
110
-
111
-		var x uint64
112
-		for i, c := range b {
113
-			c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing
114
-			if i == 0 {
115
-				c &= 0x7f // Ignore signal bit in first byte
116
-			}
117
-			if (x >> 56) > 0 {
118
-				p.err = ErrHeader // Integer overflow
119
-				return 0
120
-			}
121
-			x = x<<8 | uint64(c)
122
-		}
123
-		if (x >> 63) > 0 {
124
-			p.err = ErrHeader // Integer overflow
125
-			return 0
126
-		}
127
-		if inv == 0xff {
128
-			return ^int64(x)
129
-		}
130
-		return int64(x)
131
-	}
132
-
133
-	// Normal case is base-8 (octal) format.
134
-	return p.parseOctal(b)
135
-}
136
-
137
-// formatNumeric encodes x into b using base-8 (octal) encoding if possible.
138
-// Otherwise it will attempt to use base-256 (binary) encoding.
139
-func (f *formatter) formatNumeric(b []byte, x int64) {
140
-	if fitsInOctal(len(b), x) {
141
-		f.formatOctal(b, x)
142
-		return
143
-	}
144
-
145
-	if fitsInBase256(len(b), x) {
146
-		for i := len(b) - 1; i >= 0; i-- {
147
-			b[i] = byte(x)
148
-			x >>= 8
149
-		}
150
-		b[0] |= 0x80 // Highest bit indicates binary format
151
-		return
152
-	}
153
-
154
-	f.formatOctal(b, 0) // Last resort, just write zero
155
-	f.err = ErrFieldTooLong
156
-}
157
-
158
-func (p *parser) parseOctal(b []byte) int64 {
159
-	// Because unused fields are filled with NULs, we need
160
-	// to skip leading NULs. Fields may also be padded with
161
-	// spaces or NULs.
162
-	// So we remove leading and trailing NULs and spaces to
163
-	// be sure.
164
-	b = bytes.Trim(b, " \x00")
165
-
166
-	if len(b) == 0 {
167
-		return 0
168
-	}
169
-	x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
170
-	if perr != nil {
171
-		p.err = ErrHeader
172
-	}
173
-	return int64(x)
174
-}
175
-
176
-func (f *formatter) formatOctal(b []byte, x int64) {
177
-	if !fitsInOctal(len(b), x) {
178
-		x = 0 // Last resort, just write zero
179
-		f.err = ErrFieldTooLong
180
-	}
181
-
182
-	s := strconv.FormatInt(x, 8)
183
-	// Add leading zeros, but leave room for a NUL.
184
-	if n := len(b) - len(s) - 1; n > 0 {
185
-		s = strings.Repeat("0", n) + s
186
-	}
187
-	f.formatString(b, s)
188
-}
189
-
190
-// fitsInOctal reports whether the integer x fits in a field n-bytes long
191
-// using octal encoding with the appropriate NUL terminator.
192
-func fitsInOctal(n int, x int64) bool {
193
-	octBits := uint(n-1) * 3
194
-	return x >= 0 && (n >= 22 || x < 1<<octBits)
195
-}
196
-
197
-// parsePAXTime takes a string of the form %d.%d as described in the PAX
198
-// specification. Note that this implementation allows for negative timestamps,
199
-// which is allowed for by the PAX specification, but not always portable.
200
-func parsePAXTime(s string) (time.Time, error) {
201
-	const maxNanoSecondDigits = 9
202
-
203
-	// Split string into seconds and sub-seconds parts.
204
-	ss, sn := s, ""
205
-	if pos := strings.IndexByte(s, '.'); pos >= 0 {
206
-		ss, sn = s[:pos], s[pos+1:]
207
-	}
208
-
209
-	// Parse the seconds.
210
-	secs, err := strconv.ParseInt(ss, 10, 64)
211
-	if err != nil {
212
-		return time.Time{}, ErrHeader
213
-	}
214
-	if len(sn) == 0 {
215
-		return time.Unix(secs, 0), nil // No sub-second values
216
-	}
217
-
218
-	// Parse the nanoseconds.
219
-	if strings.Trim(sn, "0123456789") != "" {
220
-		return time.Time{}, ErrHeader
221
-	}
222
-	if len(sn) < maxNanoSecondDigits {
223
-		sn += strings.Repeat("0", maxNanoSecondDigits-len(sn)) // Right pad
224
-	} else {
225
-		sn = sn[:maxNanoSecondDigits] // Right truncate
226
-	}
227
-	nsecs, _ := strconv.ParseInt(sn, 10, 64) // Must succeed
228
-	if len(ss) > 0 && ss[0] == '-' {
229
-		return time.Unix(secs, -1*nsecs), nil // Negative correction
230
-	}
231
-	return time.Unix(secs, nsecs), nil
232
-}
233
-
234
-// formatPAXTime converts ts into a time of the form %d.%d as described in the
235
-// PAX specification. This function is capable of negative timestamps.
236
-func formatPAXTime(ts time.Time) (s string) {
237
-	secs, nsecs := ts.Unix(), ts.Nanosecond()
238
-	if nsecs == 0 {
239
-		return strconv.FormatInt(secs, 10)
240
-	}
241
-
242
-	// If seconds is negative, then perform correction.
243
-	sign := ""
244
-	if secs < 0 {
245
-		sign = "-"             // Remember sign
246
-		secs = -(secs + 1)     // Add a second to secs
247
-		nsecs = -(nsecs - 1E9) // Take that second away from nsecs
248
-	}
249
-	return strings.TrimRight(fmt.Sprintf("%s%d.%09d", sign, secs, nsecs), "0")
250
-}
251
-
252
-// parsePAXRecord parses the input PAX record string into a key-value pair.
253
-// If parsing is successful, it will slice off the currently read record and
254
-// return the remainder as r.
255
-func parsePAXRecord(s string) (k, v, r string, err error) {
256
-	// The size field ends at the first space.
257
-	sp := strings.IndexByte(s, ' ')
258
-	if sp == -1 {
259
-		return "", "", s, ErrHeader
260
-	}
261
-
262
-	// Parse the first token as a decimal integer.
263
-	n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
264
-	if perr != nil || n < 5 || int64(len(s)) < n {
265
-		return "", "", s, ErrHeader
266
-	}
267
-
268
-	// Extract everything between the space and the final newline.
269
-	rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
270
-	if nl != "\n" {
271
-		return "", "", s, ErrHeader
272
-	}
273
-
274
-	// The first equals separates the key from the value.
275
-	eq := strings.IndexByte(rec, '=')
276
-	if eq == -1 {
277
-		return "", "", s, ErrHeader
278
-	}
279
-	k, v = rec[:eq], rec[eq+1:]
280
-
281
-	if !validPAXRecord(k, v) {
282
-		return "", "", s, ErrHeader
283
-	}
284
-	return k, v, rem, nil
285
-}
286
-
287
-// formatPAXRecord formats a single PAX record, prefixing it with the
288
-// appropriate length.
289
-func formatPAXRecord(k, v string) (string, error) {
290
-	if !validPAXRecord(k, v) {
291
-		return "", ErrHeader
292
-	}
293
-
294
-	const padding = 3 // Extra padding for ' ', '=', and '\n'
295
-	size := len(k) + len(v) + padding
296
-	size += len(strconv.Itoa(size))
297
-	record := strconv.Itoa(size) + " " + k + "=" + v + "\n"
298
-
299
-	// Final adjustment if adding size field increased the record size.
300
-	if len(record) != size {
301
-		size = len(record)
302
-		record = strconv.Itoa(size) + " " + k + "=" + v + "\n"
303
-	}
304
-	return record, nil
305
-}
306
-
307
-// validPAXRecord reports whether the key-value pair is valid where each
308
-// record is formatted as:
309
-//	"%d %s=%s\n" % (size, key, value)
310
-//
311
-// Keys and values should be UTF-8, but the number of bad writers out there
312
-// forces us to be a more liberal.
313
-// Thus, we only reject all keys with NUL, and only reject NULs in values
314
-// for the PAX version of the USTAR string fields.
315
-// The key must not contain an '=' character.
316
-func validPAXRecord(k, v string) bool {
317
-	if k == "" || strings.IndexByte(k, '=') >= 0 {
318
-		return false
319
-	}
320
-	switch k {
321
-	case paxPath, paxLinkpath, paxUname, paxGname:
322
-		return !hasNUL(v)
323
-	default:
324
-		return !hasNUL(k)
325
-	}
326
-}
327 1
deleted file mode 100644
... ...
@@ -1,644 +0,0 @@
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
-	"path"
12
-	"sort"
13
-	"strings"
14
-	"time"
15
-)
16
-
17
-// Writer provides sequential writing of a tar archive.
18
-// Write.WriteHeader begins a new file with the provided Header,
19
-// and then Writer can be treated as an io.Writer to supply that file's data.
20
-type Writer struct {
21
-	w    io.Writer
22
-	pad  int64      // Amount of padding to write after current file entry
23
-	curr fileWriter // Writer for current file entry
24
-	hdr  Header     // Shallow copy of Header that is safe for mutations
25
-	blk  block      // Buffer to use as temporary local storage
26
-
27
-	// err is a persistent error.
28
-	// It is only the responsibility of every exported method of Writer to
29
-	// ensure that this error is sticky.
30
-	err error
31
-}
32
-
33
-// NewWriter creates a new Writer writing to w.
34
-func NewWriter(w io.Writer) *Writer {
35
-	return &Writer{w: w, curr: &regFileWriter{w, 0}}
36
-}
37
-
38
-type fileWriter interface {
39
-	io.Writer
40
-	fileState
41
-
42
-	ReadFrom(io.Reader) (int64, error)
43
-}
44
-
45
-// Flush finishes writing the current file's block padding.
46
-// The current file must be fully written before Flush can be called.
47
-//
48
-// This is unnecessary as the next call to WriteHeader or Close
49
-// will implicitly flush out the file's padding.
50
-func (tw *Writer) Flush() error {
51
-	if tw.err != nil {
52
-		return tw.err
53
-	}
54
-	if nb := tw.curr.LogicalRemaining(); nb > 0 {
55
-		return fmt.Errorf("archive/tar: missed writing %d bytes", nb)
56
-	}
57
-	if _, tw.err = tw.w.Write(zeroBlock[:tw.pad]); tw.err != nil {
58
-		return tw.err
59
-	}
60
-	tw.pad = 0
61
-	return nil
62
-}
63
-
64
-// WriteHeader writes hdr and prepares to accept the file's contents.
65
-// The Header.Size determines how many bytes can be written for the next file.
66
-// If the current file is not fully written, then this returns an error.
67
-// This implicitly flushes any padding necessary before writing the header.
68
-func (tw *Writer) WriteHeader(hdr *Header) error {
69
-	if err := tw.Flush(); err != nil {
70
-		return err
71
-	}
72
-	tw.hdr = *hdr // Shallow copy of Header
73
-
74
-	// Round ModTime and ignore AccessTime and ChangeTime unless
75
-	// the format is explicitly chosen.
76
-	// This ensures nominal usage of WriteHeader (without specifying the format)
77
-	// does not always result in the PAX format being chosen, which
78
-	// causes a 1KiB increase to every header.
79
-	if tw.hdr.Format == FormatUnknown {
80
-		tw.hdr.ModTime = tw.hdr.ModTime.Round(time.Second)
81
-		tw.hdr.AccessTime = time.Time{}
82
-		tw.hdr.ChangeTime = time.Time{}
83
-	}
84
-
85
-	allowedFormats, paxHdrs, err := tw.hdr.allowedFormats()
86
-	switch {
87
-	case allowedFormats.has(FormatUSTAR):
88
-		tw.err = tw.writeUSTARHeader(&tw.hdr)
89
-		return tw.err
90
-	case allowedFormats.has(FormatPAX):
91
-		tw.err = tw.writePAXHeader(&tw.hdr, paxHdrs)
92
-		return tw.err
93
-	case allowedFormats.has(FormatGNU):
94
-		tw.err = tw.writeGNUHeader(&tw.hdr)
95
-		return tw.err
96
-	default:
97
-		return err // Non-fatal error
98
-	}
99
-}
100
-
101
-func (tw *Writer) writeUSTARHeader(hdr *Header) error {
102
-	// Check if we can use USTAR prefix/suffix splitting.
103
-	var namePrefix string
104
-	if prefix, suffix, ok := splitUSTARPath(hdr.Name); ok {
105
-		namePrefix, hdr.Name = prefix, suffix
106
-	}
107
-
108
-	// Pack the main header.
109
-	var f formatter
110
-	blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal)
111
-	f.formatString(blk.USTAR().Prefix(), namePrefix)
112
-	blk.SetFormat(FormatUSTAR)
113
-	if f.err != nil {
114
-		return f.err // Should never happen since header is validated
115
-	}
116
-	return tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag)
117
-}
118
-
119
-func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error {
120
-	realName, realSize := hdr.Name, hdr.Size
121
-
122
-	// TODO(dsnet): Re-enable this when adding sparse support.
123
-	// See https://golang.org/issue/22735
124
-	/*
125
-		// Handle sparse files.
126
-		var spd sparseDatas
127
-		var spb []byte
128
-		if len(hdr.SparseHoles) > 0 {
129
-			sph := append([]sparseEntry{}, hdr.SparseHoles...) // Copy sparse map
130
-			sph = alignSparseEntries(sph, hdr.Size)
131
-			spd = invertSparseEntries(sph, hdr.Size)
132
-
133
-			// Format the sparse map.
134
-			hdr.Size = 0 // Replace with encoded size
135
-			spb = append(strconv.AppendInt(spb, int64(len(spd)), 10), '\n')
136
-			for _, s := range spd {
137
-				hdr.Size += s.Length
138
-				spb = append(strconv.AppendInt(spb, s.Offset, 10), '\n')
139
-				spb = append(strconv.AppendInt(spb, s.Length, 10), '\n')
140
-			}
141
-			pad := blockPadding(int64(len(spb)))
142
-			spb = append(spb, zeroBlock[:pad]...)
143
-			hdr.Size += int64(len(spb)) // Accounts for encoded sparse map
144
-
145
-			// Add and modify appropriate PAX records.
146
-			dir, file := path.Split(realName)
147
-			hdr.Name = path.Join(dir, "GNUSparseFile.0", file)
148
-			paxHdrs[paxGNUSparseMajor] = "1"
149
-			paxHdrs[paxGNUSparseMinor] = "0"
150
-			paxHdrs[paxGNUSparseName] = realName
151
-			paxHdrs[paxGNUSparseRealSize] = strconv.FormatInt(realSize, 10)
152
-			paxHdrs[paxSize] = strconv.FormatInt(hdr.Size, 10)
153
-			delete(paxHdrs, paxPath) // Recorded by paxGNUSparseName
154
-		}
155
-	*/
156
-	_ = realSize
157
-
158
-	// Write PAX records to the output.
159
-	isGlobal := hdr.Typeflag == TypeXGlobalHeader
160
-	if len(paxHdrs) > 0 || isGlobal {
161
-		// Sort keys for deterministic ordering.
162
-		var keys []string
163
-		for k := range paxHdrs {
164
-			keys = append(keys, k)
165
-		}
166
-		sort.Strings(keys)
167
-
168
-		// Write each record to a buffer.
169
-		var buf bytes.Buffer
170
-		for _, k := range keys {
171
-			rec, err := formatPAXRecord(k, paxHdrs[k])
172
-			if err != nil {
173
-				return err
174
-			}
175
-			buf.WriteString(rec)
176
-		}
177
-
178
-		// Write the extended header file.
179
-		var name string
180
-		var flag byte
181
-		if isGlobal {
182
-			name = realName
183
-			if name == "" {
184
-				name = "GlobalHead.0.0"
185
-			}
186
-			flag = TypeXGlobalHeader
187
-		} else {
188
-			dir, file := path.Split(realName)
189
-			name = path.Join(dir, "PaxHeaders.0", file)
190
-			flag = TypeXHeader
191
-		}
192
-		data := buf.String()
193
-		if err := tw.writeRawFile(name, data, flag, FormatPAX); err != nil || isGlobal {
194
-			return err // Global headers return here
195
-		}
196
-	}
197
-
198
-	// Pack the main header.
199
-	var f formatter // Ignore errors since they are expected
200
-	fmtStr := func(b []byte, s string) { f.formatString(b, toASCII(s)) }
201
-	blk := tw.templateV7Plus(hdr, fmtStr, f.formatOctal)
202
-	blk.SetFormat(FormatPAX)
203
-	if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
204
-		return err
205
-	}
206
-
207
-	// TODO(dsnet): Re-enable this when adding sparse support.
208
-	// See https://golang.org/issue/22735
209
-	/*
210
-		// Write the sparse map and setup the sparse writer if necessary.
211
-		if len(spd) > 0 {
212
-			// Use tw.curr since the sparse map is accounted for in hdr.Size.
213
-			if _, err := tw.curr.Write(spb); err != nil {
214
-				return err
215
-			}
216
-			tw.curr = &sparseFileWriter{tw.curr, spd, 0}
217
-		}
218
-	*/
219
-	return nil
220
-}
221
-
222
-func (tw *Writer) writeGNUHeader(hdr *Header) error {
223
-	// Use long-link files if Name or Linkname exceeds the field size.
224
-	const longName = "././@LongLink"
225
-	if len(hdr.Name) > nameSize {
226
-		data := hdr.Name + "\x00"
227
-		if err := tw.writeRawFile(longName, data, TypeGNULongName, FormatGNU); err != nil {
228
-			return err
229
-		}
230
-	}
231
-	if len(hdr.Linkname) > nameSize {
232
-		data := hdr.Linkname + "\x00"
233
-		if err := tw.writeRawFile(longName, data, TypeGNULongLink, FormatGNU); err != nil {
234
-			return err
235
-		}
236
-	}
237
-
238
-	// Pack the main header.
239
-	var f formatter // Ignore errors since they are expected
240
-	var spd sparseDatas
241
-	var spb []byte
242
-	blk := tw.templateV7Plus(hdr, f.formatString, f.formatNumeric)
243
-	if !hdr.AccessTime.IsZero() {
244
-		f.formatNumeric(blk.GNU().AccessTime(), hdr.AccessTime.Unix())
245
-	}
246
-	if !hdr.ChangeTime.IsZero() {
247
-		f.formatNumeric(blk.GNU().ChangeTime(), hdr.ChangeTime.Unix())
248
-	}
249
-	// TODO(dsnet): Re-enable this when adding sparse support.
250
-	// See https://golang.org/issue/22735
251
-	/*
252
-		if hdr.Typeflag == TypeGNUSparse {
253
-			sph := append([]sparseEntry{}, hdr.SparseHoles...) // Copy sparse map
254
-			sph = alignSparseEntries(sph, hdr.Size)
255
-			spd = invertSparseEntries(sph, hdr.Size)
256
-
257
-			// Format the sparse map.
258
-			formatSPD := func(sp sparseDatas, sa sparseArray) sparseDatas {
259
-				for i := 0; len(sp) > 0 && i < sa.MaxEntries(); i++ {
260
-					f.formatNumeric(sa.Entry(i).Offset(), sp[0].Offset)
261
-					f.formatNumeric(sa.Entry(i).Length(), sp[0].Length)
262
-					sp = sp[1:]
263
-				}
264
-				if len(sp) > 0 {
265
-					sa.IsExtended()[0] = 1
266
-				}
267
-				return sp
268
-			}
269
-			sp2 := formatSPD(spd, blk.GNU().Sparse())
270
-			for len(sp2) > 0 {
271
-				var spHdr block
272
-				sp2 = formatSPD(sp2, spHdr.Sparse())
273
-				spb = append(spb, spHdr[:]...)
274
-			}
275
-
276
-			// Update size fields in the header block.
277
-			realSize := hdr.Size
278
-			hdr.Size = 0 // Encoded size; does not account for encoded sparse map
279
-			for _, s := range spd {
280
-				hdr.Size += s.Length
281
-			}
282
-			copy(blk.V7().Size(), zeroBlock[:]) // Reset field
283
-			f.formatNumeric(blk.V7().Size(), hdr.Size)
284
-			f.formatNumeric(blk.GNU().RealSize(), realSize)
285
-		}
286
-	*/
287
-	blk.SetFormat(FormatGNU)
288
-	if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
289
-		return err
290
-	}
291
-
292
-	// Write the extended sparse map and setup the sparse writer if necessary.
293
-	if len(spd) > 0 {
294
-		// Use tw.w since the sparse map is not accounted for in hdr.Size.
295
-		if _, err := tw.w.Write(spb); err != nil {
296
-			return err
297
-		}
298
-		tw.curr = &sparseFileWriter{tw.curr, spd, 0}
299
-	}
300
-	return nil
301
-}
302
-
303
-type (
304
-	stringFormatter func([]byte, string)
305
-	numberFormatter func([]byte, int64)
306
-)
307
-
308
-// templateV7Plus fills out the V7 fields of a block using values from hdr.
309
-// It also fills out fields (uname, gname, devmajor, devminor) that are
310
-// shared in the USTAR, PAX, and GNU formats using the provided formatters.
311
-//
312
-// The block returned is only valid until the next call to
313
-// templateV7Plus or writeRawFile.
314
-func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum numberFormatter) *block {
315
-	tw.blk.Reset()
316
-
317
-	modTime := hdr.ModTime
318
-	if modTime.IsZero() {
319
-		modTime = time.Unix(0, 0)
320
-	}
321
-
322
-	v7 := tw.blk.V7()
323
-	v7.TypeFlag()[0] = hdr.Typeflag
324
-	fmtStr(v7.Name(), hdr.Name)
325
-	fmtStr(v7.LinkName(), hdr.Linkname)
326
-	fmtNum(v7.Mode(), hdr.Mode)
327
-	fmtNum(v7.UID(), int64(hdr.Uid))
328
-	fmtNum(v7.GID(), int64(hdr.Gid))
329
-	fmtNum(v7.Size(), hdr.Size)
330
-	fmtNum(v7.ModTime(), modTime.Unix())
331
-
332
-	ustar := tw.blk.USTAR()
333
-	fmtStr(ustar.UserName(), hdr.Uname)
334
-	fmtStr(ustar.GroupName(), hdr.Gname)
335
-	fmtNum(ustar.DevMajor(), hdr.Devmajor)
336
-	fmtNum(ustar.DevMinor(), hdr.Devminor)
337
-
338
-	return &tw.blk
339
-}
340
-
341
-// writeRawFile writes a minimal file with the given name and flag type.
342
-// It uses format to encode the header format and will write data as the body.
343
-// It uses default values for all of the other fields (as BSD and GNU tar does).
344
-func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) error {
345
-	tw.blk.Reset()
346
-
347
-	// Best effort for the filename.
348
-	name = toASCII(name)
349
-	if len(name) > nameSize {
350
-		name = name[:nameSize]
351
-	}
352
-	name = strings.TrimRight(name, "/")
353
-
354
-	var f formatter
355
-	v7 := tw.blk.V7()
356
-	v7.TypeFlag()[0] = flag
357
-	f.formatString(v7.Name(), name)
358
-	f.formatOctal(v7.Mode(), 0)
359
-	f.formatOctal(v7.UID(), 0)
360
-	f.formatOctal(v7.GID(), 0)
361
-	f.formatOctal(v7.Size(), int64(len(data))) // Must be < 8GiB
362
-	f.formatOctal(v7.ModTime(), 0)
363
-	tw.blk.SetFormat(format)
364
-	if f.err != nil {
365
-		return f.err // Only occurs if size condition is violated
366
-	}
367
-
368
-	// Write the header and data.
369
-	if err := tw.writeRawHeader(&tw.blk, int64(len(data)), flag); err != nil {
370
-		return err
371
-	}
372
-	_, err := io.WriteString(tw, data)
373
-	return err
374
-}
375
-
376
-// writeRawHeader writes the value of blk, regardless of its value.
377
-// It sets up the Writer such that it can accept a file of the given size.
378
-// If the flag is a special header-only flag, then the size is treated as zero.
379
-func (tw *Writer) writeRawHeader(blk *block, size int64, flag byte) error {
380
-	if err := tw.Flush(); err != nil {
381
-		return err
382
-	}
383
-	if _, err := tw.w.Write(blk[:]); err != nil {
384
-		return err
385
-	}
386
-	if isHeaderOnlyType(flag) {
387
-		size = 0
388
-	}
389
-	tw.curr = &regFileWriter{tw.w, size}
390
-	tw.pad = blockPadding(size)
391
-	return nil
392
-}
393
-
394
-// splitUSTARPath splits a path according to USTAR prefix and suffix rules.
395
-// If the path is not splittable, then it will return ("", "", false).
396
-func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
397
-	length := len(name)
398
-	if length <= nameSize || !isASCII(name) {
399
-		return "", "", false
400
-	} else if length > prefixSize+1 {
401
-		length = prefixSize + 1
402
-	} else if name[length-1] == '/' {
403
-		length--
404
-	}
405
-
406
-	i := strings.LastIndex(name[:length], "/")
407
-	nlen := len(name) - i - 1 // nlen is length of suffix
408
-	plen := i                 // plen is length of prefix
409
-	if i <= 0 || nlen > nameSize || nlen == 0 || plen > prefixSize {
410
-		return "", "", false
411
-	}
412
-	return name[:i], name[i+1:], true
413
-}
414
-
415
-// Write writes to the current file in the tar archive.
416
-// Write returns the error ErrWriteTooLong if more than
417
-// Header.Size bytes are written after WriteHeader.
418
-//
419
-// Calling Write on special types like TypeLink, TypeSymlink, TypeChar,
420
-// TypeBlock, TypeDir, and TypeFifo returns (0, ErrWriteTooLong) regardless
421
-// of what the Header.Size claims.
422
-func (tw *Writer) Write(b []byte) (int, error) {
423
-	if tw.err != nil {
424
-		return 0, tw.err
425
-	}
426
-	n, err := tw.curr.Write(b)
427
-	if err != nil && err != ErrWriteTooLong {
428
-		tw.err = err
429
-	}
430
-	return n, err
431
-}
432
-
433
-// readFrom populates the content of the current file by reading from r.
434
-// The bytes read must match the number of remaining bytes in the current file.
435
-//
436
-// If the current file is sparse and r is an io.ReadSeeker,
437
-// then readFrom uses Seek to skip past holes defined in Header.SparseHoles,
438
-// assuming that skipped regions are all NULs.
439
-// This always reads the last byte to ensure r is the right size.
440
-//
441
-// TODO(dsnet): Re-export this when adding sparse file support.
442
-// See https://golang.org/issue/22735
443
-func (tw *Writer) readFrom(r io.Reader) (int64, error) {
444
-	if tw.err != nil {
445
-		return 0, tw.err
446
-	}
447
-	n, err := tw.curr.ReadFrom(r)
448
-	if err != nil && err != ErrWriteTooLong {
449
-		tw.err = err
450
-	}
451
-	return n, err
452
-}
453
-
454
-// Close closes the tar archive by flushing the padding, and writing the footer.
455
-// If the current file (from a prior call to WriteHeader) is not fully written,
456
-// then this returns an error.
457
-func (tw *Writer) Close() error {
458
-	if tw.err == ErrWriteAfterClose {
459
-		return nil
460
-	}
461
-	if tw.err != nil {
462
-		return tw.err
463
-	}
464
-
465
-	// Trailer: two zero blocks.
466
-	err := tw.Flush()
467
-	for i := 0; i < 2 && err == nil; i++ {
468
-		_, err = tw.w.Write(zeroBlock[:])
469
-	}
470
-
471
-	// Ensure all future actions are invalid.
472
-	tw.err = ErrWriteAfterClose
473
-	return err // Report IO errors
474
-}
475
-
476
-// regFileWriter is a fileWriter for writing data to a regular file entry.
477
-type regFileWriter struct {
478
-	w  io.Writer // Underlying Writer
479
-	nb int64     // Number of remaining bytes to write
480
-}
481
-
482
-func (fw *regFileWriter) Write(b []byte) (n int, err error) {
483
-	overwrite := int64(len(b)) > fw.nb
484
-	if overwrite {
485
-		b = b[:fw.nb]
486
-	}
487
-	if len(b) > 0 {
488
-		n, err = fw.w.Write(b)
489
-		fw.nb -= int64(n)
490
-	}
491
-	switch {
492
-	case err != nil:
493
-		return n, err
494
-	case overwrite:
495
-		return n, ErrWriteTooLong
496
-	default:
497
-		return n, nil
498
-	}
499
-}
500
-
501
-func (fw *regFileWriter) ReadFrom(r io.Reader) (int64, error) {
502
-	return io.Copy(struct{ io.Writer }{fw}, r)
503
-}
504
-
505
-func (fw regFileWriter) LogicalRemaining() int64 {
506
-	return fw.nb
507
-}
508
-func (fw regFileWriter) PhysicalRemaining() int64 {
509
-	return fw.nb
510
-}
511
-
512
-// sparseFileWriter is a fileWriter for writing data to a sparse file entry.
513
-type sparseFileWriter struct {
514
-	fw  fileWriter  // Underlying fileWriter
515
-	sp  sparseDatas // Normalized list of data fragments
516
-	pos int64       // Current position in sparse file
517
-}
518
-
519
-func (sw *sparseFileWriter) Write(b []byte) (n int, err error) {
520
-	overwrite := int64(len(b)) > sw.LogicalRemaining()
521
-	if overwrite {
522
-		b = b[:sw.LogicalRemaining()]
523
-	}
524
-
525
-	b0 := b
526
-	endPos := sw.pos + int64(len(b))
527
-	for endPos > sw.pos && err == nil {
528
-		var nf int // Bytes written in fragment
529
-		dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
530
-		if sw.pos < dataStart { // In a hole fragment
531
-			bf := b[:min(int64(len(b)), dataStart-sw.pos)]
532
-			nf, err = zeroWriter{}.Write(bf)
533
-		} else { // In a data fragment
534
-			bf := b[:min(int64(len(b)), dataEnd-sw.pos)]
535
-			nf, err = sw.fw.Write(bf)
536
-		}
537
-		b = b[nf:]
538
-		sw.pos += int64(nf)
539
-		if sw.pos >= dataEnd && len(sw.sp) > 1 {
540
-			sw.sp = sw.sp[1:] // Ensure last fragment always remains
541
-		}
542
-	}
543
-
544
-	n = len(b0) - len(b)
545
-	switch {
546
-	case err == ErrWriteTooLong:
547
-		return n, errMissData // Not possible; implies bug in validation logic
548
-	case err != nil:
549
-		return n, err
550
-	case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0:
551
-		return n, errUnrefData // Not possible; implies bug in validation logic
552
-	case overwrite:
553
-		return n, ErrWriteTooLong
554
-	default:
555
-		return n, nil
556
-	}
557
-}
558
-
559
-func (sw *sparseFileWriter) ReadFrom(r io.Reader) (n int64, err error) {
560
-	rs, ok := r.(io.ReadSeeker)
561
-	if ok {
562
-		if _, err := rs.Seek(0, io.SeekCurrent); err != nil {
563
-			ok = false // Not all io.Seeker can really seek
564
-		}
565
-	}
566
-	if !ok {
567
-		return io.Copy(struct{ io.Writer }{sw}, r)
568
-	}
569
-
570
-	var readLastByte bool
571
-	pos0 := sw.pos
572
-	for sw.LogicalRemaining() > 0 && !readLastByte && err == nil {
573
-		var nf int64 // Size of fragment
574
-		dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
575
-		if sw.pos < dataStart { // In a hole fragment
576
-			nf = dataStart - sw.pos
577
-			if sw.PhysicalRemaining() == 0 {
578
-				readLastByte = true
579
-				nf--
580
-			}
581
-			_, err = rs.Seek(nf, io.SeekCurrent)
582
-		} else { // In a data fragment
583
-			nf = dataEnd - sw.pos
584
-			nf, err = io.CopyN(sw.fw, rs, nf)
585
-		}
586
-		sw.pos += nf
587
-		if sw.pos >= dataEnd && len(sw.sp) > 1 {
588
-			sw.sp = sw.sp[1:] // Ensure last fragment always remains
589
-		}
590
-	}
591
-
592
-	// If the last fragment is a hole, then seek to 1-byte before EOF, and
593
-	// read a single byte to ensure the file is the right size.
594
-	if readLastByte && err == nil {
595
-		_, err = mustReadFull(rs, []byte{0})
596
-		sw.pos++
597
-	}
598
-
599
-	n = sw.pos - pos0
600
-	switch {
601
-	case err == io.EOF:
602
-		return n, io.ErrUnexpectedEOF
603
-	case err == ErrWriteTooLong:
604
-		return n, errMissData // Not possible; implies bug in validation logic
605
-	case err != nil:
606
-		return n, err
607
-	case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0:
608
-		return n, errUnrefData // Not possible; implies bug in validation logic
609
-	default:
610
-		return n, ensureEOF(rs)
611
-	}
612
-}
613
-
614
-func (sw sparseFileWriter) LogicalRemaining() int64 {
615
-	return sw.sp[len(sw.sp)-1].endOffset() - sw.pos
616
-}
617
-func (sw sparseFileWriter) PhysicalRemaining() int64 {
618
-	return sw.fw.PhysicalRemaining()
619
-}
620
-
621
-// zeroWriter may only be written with NULs, otherwise it returns errWriteHole.
622
-type zeroWriter struct{}
623
-
624
-func (zeroWriter) Write(b []byte) (int, error) {
625
-	for i, c := range b {
626
-		if c != 0 {
627
-			return i, errWriteHole
628
-		}
629
-	}
630
-	return len(b), nil
631
-}
632
-
633
-// ensureEOF checks whether r is at EOF, reporting ErrWriteTooLong if not so.
634
-func ensureEOF(r io.Reader) error {
635
-	n, err := tryReadFull(r, []byte{0})
636
-	switch {
637
-	case n > 0:
638
-		return ErrWriteTooLong
639
-	case err == io.EOF:
640
-		return nil
641
-	default:
642
-		return err
643
-	}
644
-}
... ...
@@ -6,7 +6,6 @@ import (
6 6
 	"errors"
7 7
 	"fmt"
8 8
 	"os"
9
-	"path/filepath"
10 9
 	"sort"
11 10
 
12 11
 	"github.com/containerd/continuity/devices"
... ...
@@ -26,18 +25,6 @@ func (d *driver) Mkfifo(path string, mode os.FileMode) error {
26 26
 	return devices.Mknod(path, mode, 0, 0)
27 27
 }
28 28
 
29
-// Lchmod changes the mode of an file not following symlinks.
30
-func (d *driver) Lchmod(path string, mode os.FileMode) (err error) {
31
-	if !filepath.IsAbs(path) {
32
-		path, err = filepath.Abs(path)
33
-		if err != nil {
34
-			return
35
-		}
36
-	}
37
-
38
-	return sysx.Fchmodat(0, path, uint32(mode), sysx.AtSymlinkNofollow)
39
-}
40
-
41 29
 // Getxattr returns all of the extended attributes for the file at path p.
42 30
 func (d *driver) Getxattr(p string) (map[string][]byte, error) {
43 31
 	xattrs, err := sysx.Listxattr(p)
44 32
new file mode 100644
... ...
@@ -0,0 +1,19 @@
0
+package driver
1
+
2
+import (
3
+	"os"
4
+
5
+	"golang.org/x/sys/unix"
6
+)
7
+
8
+// Lchmod changes the mode of a file not following symlinks.
9
+func (d *driver) Lchmod(path string, mode os.FileMode) error {
10
+	// On Linux, file mode is not supported for symlinks,
11
+	// and fchmodat() does not support AT_SYMLINK_NOFOLLOW,
12
+	// so symlinks need to be skipped entirely.
13
+	if st, err := os.Stat(path); err == nil && st.Mode()&os.ModeSymlink != 0 {
14
+		return nil
15
+	}
16
+
17
+	return unix.Fchmodat(unix.AT_FDCWD, path, uint32(mode), 0)
18
+}
0 19
new file mode 100644
... ...
@@ -0,0 +1,14 @@
0
+// +build darwin freebsd solaris
1
+
2
+package driver
3
+
4
+import (
5
+	"os"
6
+
7
+	"golang.org/x/sys/unix"
8
+)
9
+
10
+// Lchmod changes the mode of a file not following symlinks.
11
+func (d *driver) Lchmod(path string, mode os.FileMode) error {
12
+	return unix.Fchmodat(unix.AT_FDCWD, path, uint32(mode), unix.AT_SYMLINK_NOFOLLOW)
13
+}
... ...
@@ -10,8 +10,8 @@ type Usage struct {
10 10
 
11 11
 // DiskUsage counts the number of inodes and disk usage for the resources under
12 12
 // path.
13
-func DiskUsage(roots ...string) (Usage, error) {
14
-	return diskUsage(roots...)
13
+func DiskUsage(ctx context.Context, roots ...string) (Usage, error) {
14
+	return diskUsage(ctx, roots...)
15 15
 }
16 16
 
17 17
 // DiffUsage counts the numbers of inodes and disk usage in the
... ...
@@ -24,7 +24,7 @@ func newInode(stat *syscall.Stat_t) inode {
24 24
 	}
25 25
 }
26 26
 
27
-func diskUsage(roots ...string) (Usage, error) {
27
+func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
28 28
 
29 29
 	var (
30 30
 		size   int64
... ...
@@ -37,6 +37,12 @@ func diskUsage(roots ...string) (Usage, error) {
37 37
 				return err
38 38
 			}
39 39
 
40
+			select {
41
+			case <-ctx.Done():
42
+				return ctx.Err()
43
+			default:
44
+			}
45
+
40 46
 			inoKey := newInode(fi.Sys().(*syscall.Stat_t))
41 47
 			if _, ok := inodes[inoKey]; !ok {
42 48
 				inodes[inoKey] = struct{}{}
... ...
@@ -8,7 +8,7 @@ import (
8 8
 	"path/filepath"
9 9
 )
10 10
 
11
-func diskUsage(roots ...string) (Usage, error) {
11
+func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
12 12
 	var (
13 13
 		size int64
14 14
 	)
... ...
@@ -21,6 +21,12 @@ func diskUsage(roots ...string) (Usage, error) {
21 21
 				return err
22 22
 			}
23 23
 
24
+			select {
25
+			case <-ctx.Done():
26
+				return ctx.Err()
27
+			default:
28
+			}
29
+
24 30
 			size += fi.Size()
25 31
 			return nil
26 32
 		}); err != nil {
27 33
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+This package is for internal use only. It is intended to only have
1
+temporary changes before they are upstreamed to golang.org/x/sys/
2
+(a.k.a. https://github.com/golang/sys).
0 3
deleted file mode 100644
... ...
@@ -1,10 +0,0 @@
1
-// Copyright 2014 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
-// +build !gccgo
6
-
7
-#include "textflag.h"
8
-
9
-TEXT ·use(SB),NOSPLIT,$0
10
-	RET
11 1
deleted file mode 100644
... ...
@@ -1,18 +0,0 @@
1
-package sysx
2
-
3
-const (
4
-	// AtSymlinkNoFollow defined from AT_SYMLINK_NOFOLLOW in <sys/fcntl.h>
5
-	AtSymlinkNofollow = 0x20
6
-)
7
-
8
-const (
9
-
10
-	// SYS_FCHMODAT defined from golang.org/sys/unix
11
-	SYS_FCHMODAT = 467
12
-)
13
-
14
-// These functions will be generated by generate.sh
15
-//    $ GOOS=darwin GOARCH=386 ./generate.sh chmod
16
-//    $ GOOS=darwin GOARCH=amd64 ./generate.sh chmod
17
-
18
-//sys  Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
19 1
deleted file mode 100644
... ...
@@ -1,25 +0,0 @@
1
-// mksyscall.pl -l32 chmod_darwin.go
2
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
3
-
4
-package sysx
5
-
6
-import (
7
-	"syscall"
8
-	"unsafe"
9
-)
10
-
11
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
12
-
13
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
14
-	var _p0 *byte
15
-	_p0, err = syscall.BytePtrFromString(path)
16
-	if err != nil {
17
-		return
18
-	}
19
-	_, _, e1 := syscall.Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
20
-	use(unsafe.Pointer(_p0))
21
-	if e1 != 0 {
22
-		err = errnoErr(e1)
23
-	}
24
-	return
25
-}
26 1
deleted file mode 100644
... ...
@@ -1,25 +0,0 @@
1
-// mksyscall.pl chmod_darwin.go
2
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
3
-
4
-package sysx
5
-
6
-import (
7
-	"syscall"
8
-	"unsafe"
9
-)
10
-
11
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
12
-
13
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
14
-	var _p0 *byte
15
-	_p0, err = syscall.BytePtrFromString(path)
16
-	if err != nil {
17
-		return
18
-	}
19
-	_, _, e1 := syscall.Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
20
-	use(unsafe.Pointer(_p0))
21
-	if e1 != 0 {
22
-		err = errnoErr(e1)
23
-	}
24
-	return
25
-}
26 1
deleted file mode 100644
... ...
@@ -1,17 +0,0 @@
1
-package sysx
2
-
3
-const (
4
-	// AtSymlinkNoFollow defined from AT_SYMLINK_NOFOLLOW in <sys/fcntl.h>
5
-	AtSymlinkNofollow = 0x200
6
-)
7
-
8
-const (
9
-
10
-	// SYS_FCHMODAT defined from golang.org/sys/unix
11
-	SYS_FCHMODAT = 490
12
-)
13
-
14
-// These functions will be generated by generate.sh
15
-//    $ GOOS=freebsd GOARCH=amd64 ./generate.sh chmod
16
-
17
-//sys  Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
18 1
deleted file mode 100644
... ...
@@ -1,25 +0,0 @@
1
-// mksyscall.pl chmod_freebsd.go
2
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
3
-
4
-package sysx
5
-
6
-import (
7
-	"syscall"
8
-	"unsafe"
9
-)
10
-
11
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
12
-
13
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
14
-	var _p0 *byte
15
-	_p0, err = syscall.BytePtrFromString(path)
16
-	if err != nil {
17
-		return
18
-	}
19
-	_, _, e1 := syscall.Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
20
-	use(unsafe.Pointer(_p0))
21
-	if e1 != 0 {
22
-		err = errnoErr(e1)
23
-	}
24
-	return
25
-}
26 1
deleted file mode 100644
... ...
@@ -1,12 +0,0 @@
1
-package sysx
2
-
3
-import "syscall"
4
-
5
-const (
6
-	// AtSymlinkNoFollow defined from AT_SYMLINK_NOFOLLOW in /usr/include/linux/fcntl.h
7
-	AtSymlinkNofollow = 0x100
8
-)
9
-
10
-func Fchmodat(dirfd int, path string, mode uint32, flags int) error {
11
-	return syscall.Fchmodat(dirfd, path, mode, flags)
12
-}
13 1
deleted file mode 100644
... ...
@@ -1,11 +0,0 @@
1
-package sysx
2
-
3
-import "golang.org/x/sys/unix"
4
-
5
-const (
6
-	AtSymlinkNofollow = unix.AT_SYMLINK_NOFOLLOW
7
-)
8
-
9
-func Fchmodat(dirfd int, path string, mode uint32, flags int) error {
10
-	return unix.Fchmodat(dirfd, path, mode, flags)
11
-}
12 1
deleted file mode 100644
... ...
@@ -1,37 +0,0 @@
1
-package sysx
2
-
3
-import (
4
-	"syscall"
5
-	"unsafe"
6
-)
7
-
8
-var _zero uintptr
9
-
10
-// use is a no-op, but the compiler cannot see that it is.
11
-// Calling use(p) ensures that p is kept live until that point.
12
-//go:noescape
13
-func use(p unsafe.Pointer)
14
-
15
-// Do the interface allocations only once for common
16
-// Errno values.
17
-var (
18
-	errEAGAIN error = syscall.EAGAIN
19
-	errEINVAL error = syscall.EINVAL
20
-	errENOENT error = syscall.ENOENT
21
-)
22
-
23
-// errnoErr returns common boxed Errno values, to prevent
24
-// allocations at runtime.
25
-func errnoErr(e syscall.Errno) error {
26
-	switch e {
27
-	case 0:
28
-		return nil
29
-	case syscall.EAGAIN:
30
-		return errEAGAIN
31
-	case syscall.EINVAL:
32
-		return errEINVAL
33
-	case syscall.ENOENT:
34
-		return errENOENT
35
-	}
36
-	return e
37
-}
... ...
@@ -1,14 +1,56 @@
1
+// +build linux darwin
2
+
1 3
 package sysx
2 4
 
3 5
 import (
4 6
 	"bytes"
5
-	"fmt"
6 7
 	"syscall"
8
+
9
+	"golang.org/x/sys/unix"
7 10
 )
8 11
 
9
-const defaultXattrBufferSize = 5
12
+// Listxattr calls syscall listxattr and reads all content
13
+// and returns a string array
14
+func Listxattr(path string) ([]string, error) {
15
+	return listxattrAll(path, unix.Listxattr)
16
+}
17
+
18
+// Removexattr calls syscall removexattr
19
+func Removexattr(path string, attr string) (err error) {
20
+	return unix.Removexattr(path, attr)
21
+}
22
+
23
+// Setxattr calls syscall setxattr
24
+func Setxattr(path string, attr string, data []byte, flags int) (err error) {
25
+	return unix.Setxattr(path, attr, data, flags)
26
+}
27
+
28
+// Getxattr calls syscall getxattr
29
+func Getxattr(path, attr string) ([]byte, error) {
30
+	return getxattrAll(path, attr, unix.Getxattr)
31
+}
10 32
 
11
-var ErrNotSupported = fmt.Errorf("not supported")
33
+// LListxattr lists xattrs, not following symlinks
34
+func LListxattr(path string) ([]string, error) {
35
+	return listxattrAll(path, unix.Llistxattr)
36
+}
37
+
38
+// LRemovexattr removes an xattr, not following symlinks
39
+func LRemovexattr(path string, attr string) (err error) {
40
+	return unix.Lremovexattr(path, attr)
41
+}
42
+
43
+// LSetxattr sets an xattr, not following symlinks
44
+func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
45
+	return unix.Lsetxattr(path, attr, data, flags)
46
+}
47
+
48
+// LGetxattr gets an xattr, not following symlinks
49
+func LGetxattr(path, attr string) ([]byte, error) {
50
+	return getxattrAll(path, attr, unix.Lgetxattr)
51
+}
52
+
53
+const defaultXattrBufferSize = 5
12 54
 
13 55
 type listxattrFunc func(path string, dest []byte) (int, error)
14 56
 
15 57
deleted file mode 100644
... ...
@@ -1,71 +0,0 @@
1
-package sysx
2
-
3
-// These functions will be generated by generate.sh
4
-//    $ GOOS=darwin GOARCH=386 ./generate.sh xattr
5
-//    $ GOOS=darwin GOARCH=amd64 ./generate.sh xattr
6
-
7
-//sys  getxattr(path string, attr string, dest []byte, pos int, options int) (sz int, err error)
8
-//sys  setxattr(path string, attr string, data []byte, flags int) (err error)
9
-//sys  removexattr(path string, attr string, options int) (err error)
10
-//sys  listxattr(path string, dest []byte, options int) (sz int, err error)
11
-//sys  Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
12
-
13
-const (
14
-	xattrNoFollow = 0x01
15
-)
16
-
17
-func listxattrFollow(path string, dest []byte) (sz int, err error) {
18
-	return listxattr(path, dest, 0)
19
-}
20
-
21
-// Listxattr calls syscall getxattr
22
-func Listxattr(path string) ([]string, error) {
23
-	return listxattrAll(path, listxattrFollow)
24
-}
25
-
26
-// Removexattr calls syscall getxattr
27
-func Removexattr(path string, attr string) (err error) {
28
-	return removexattr(path, attr, 0)
29
-}
30
-
31
-// Setxattr calls syscall setxattr
32
-func Setxattr(path string, attr string, data []byte, flags int) (err error) {
33
-	return setxattr(path, attr, data, flags)
34
-}
35
-
36
-func getxattrFollow(path, attr string, dest []byte) (sz int, err error) {
37
-	return getxattr(path, attr, dest, 0, 0)
38
-}
39
-
40
-// Getxattr calls syscall getxattr
41
-func Getxattr(path, attr string) ([]byte, error) {
42
-	return getxattrAll(path, attr, getxattrFollow)
43
-}
44
-
45
-func listxattrNoFollow(path string, dest []byte) (sz int, err error) {
46
-	return listxattr(path, dest, xattrNoFollow)
47
-}
48
-
49
-// LListxattr calls syscall listxattr with XATTR_NOFOLLOW
50
-func LListxattr(path string) ([]string, error) {
51
-	return listxattrAll(path, listxattrNoFollow)
52
-}
53
-
54
-// LRemovexattr calls syscall removexattr with XATTR_NOFOLLOW
55
-func LRemovexattr(path string, attr string) (err error) {
56
-	return removexattr(path, attr, xattrNoFollow)
57
-}
58
-
59
-// Setxattr calls syscall setxattr with XATTR_NOFOLLOW
60
-func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
61
-	return setxattr(path, attr, data, flags|xattrNoFollow)
62
-}
63
-
64
-func getxattrNoFollow(path, attr string, dest []byte) (sz int, err error) {
65
-	return getxattr(path, attr, dest, 0, xattrNoFollow)
66
-}
67
-
68
-// LGetxattr calls syscall getxattr with XATTR_NOFOLLOW
69
-func LGetxattr(path, attr string) ([]byte, error) {
70
-	return getxattrAll(path, attr, getxattrNoFollow)
71
-}
72 1
deleted file mode 100644
... ...
@@ -1,111 +0,0 @@
1
-// mksyscall.pl -l32 xattr_darwin.go
2
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
3
-
4
-package sysx
5
-
6
-import (
7
-	"syscall"
8
-	"unsafe"
9
-)
10
-
11
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
12
-
13
-func getxattr(path string, attr string, dest []byte, pos int, options int) (sz int, err error) {
14
-	var _p0 *byte
15
-	_p0, err = syscall.BytePtrFromString(path)
16
-	if err != nil {
17
-		return
18
-	}
19
-	var _p1 *byte
20
-	_p1, err = syscall.BytePtrFromString(attr)
21
-	if err != nil {
22
-		return
23
-	}
24
-	var _p2 unsafe.Pointer
25
-	if len(dest) > 0 {
26
-		_p2 = unsafe.Pointer(&dest[0])
27
-	} else {
28
-		_p2 = unsafe.Pointer(&_zero)
29
-	}
30
-	r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), uintptr(pos), uintptr(options))
31
-	use(unsafe.Pointer(_p0))
32
-	use(unsafe.Pointer(_p1))
33
-	sz = int(r0)
34
-	if e1 != 0 {
35
-		err = errnoErr(e1)
36
-	}
37
-	return
38
-}
39
-
40
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
41
-
42
-func setxattr(path string, attr string, data []byte, flags int) (err error) {
43
-	var _p0 *byte
44
-	_p0, err = syscall.BytePtrFromString(path)
45
-	if err != nil {
46
-		return
47
-	}
48
-	var _p1 *byte
49
-	_p1, err = syscall.BytePtrFromString(attr)
50
-	if err != nil {
51
-		return
52
-	}
53
-	var _p2 unsafe.Pointer
54
-	if len(data) > 0 {
55
-		_p2 = unsafe.Pointer(&data[0])
56
-	} else {
57
-		_p2 = unsafe.Pointer(&_zero)
58
-	}
59
-	_, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
60
-	use(unsafe.Pointer(_p0))
61
-	use(unsafe.Pointer(_p1))
62
-	if e1 != 0 {
63
-		err = errnoErr(e1)
64
-	}
65
-	return
66
-}
67
-
68
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
69
-
70
-func removexattr(path string, attr string, options int) (err error) {
71
-	var _p0 *byte
72
-	_p0, err = syscall.BytePtrFromString(path)
73
-	if err != nil {
74
-		return
75
-	}
76
-	var _p1 *byte
77
-	_p1, err = syscall.BytePtrFromString(attr)
78
-	if err != nil {
79
-		return
80
-	}
81
-	_, _, e1 := syscall.Syscall(syscall.SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options))
82
-	use(unsafe.Pointer(_p0))
83
-	use(unsafe.Pointer(_p1))
84
-	if e1 != 0 {
85
-		err = errnoErr(e1)
86
-	}
87
-	return
88
-}
89
-
90
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
91
-
92
-func listxattr(path string, dest []byte, options int) (sz int, err error) {
93
-	var _p0 *byte
94
-	_p0, err = syscall.BytePtrFromString(path)
95
-	if err != nil {
96
-		return
97
-	}
98
-	var _p1 unsafe.Pointer
99
-	if len(dest) > 0 {
100
-		_p1 = unsafe.Pointer(&dest[0])
101
-	} else {
102
-		_p1 = unsafe.Pointer(&_zero)
103
-	}
104
-	r0, _, e1 := syscall.Syscall6(syscall.SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(options), 0, 0)
105
-	use(unsafe.Pointer(_p0))
106
-	sz = int(r0)
107
-	if e1 != 0 {
108
-		err = errnoErr(e1)
109
-	}
110
-	return
111
-}
112 1
deleted file mode 100644
... ...
@@ -1,111 +0,0 @@
1
-// mksyscall.pl xattr_darwin.go
2
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
3
-
4
-package sysx
5
-
6
-import (
7
-	"syscall"
8
-	"unsafe"
9
-)
10
-
11
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
12
-
13
-func getxattr(path string, attr string, dest []byte, pos int, options int) (sz int, err error) {
14
-	var _p0 *byte
15
-	_p0, err = syscall.BytePtrFromString(path)
16
-	if err != nil {
17
-		return
18
-	}
19
-	var _p1 *byte
20
-	_p1, err = syscall.BytePtrFromString(attr)
21
-	if err != nil {
22
-		return
23
-	}
24
-	var _p2 unsafe.Pointer
25
-	if len(dest) > 0 {
26
-		_p2 = unsafe.Pointer(&dest[0])
27
-	} else {
28
-		_p2 = unsafe.Pointer(&_zero)
29
-	}
30
-	r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), uintptr(pos), uintptr(options))
31
-	use(unsafe.Pointer(_p0))
32
-	use(unsafe.Pointer(_p1))
33
-	sz = int(r0)
34
-	if e1 != 0 {
35
-		err = errnoErr(e1)
36
-	}
37
-	return
38
-}
39
-
40
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
41
-
42
-func setxattr(path string, attr string, data []byte, flags int) (err error) {
43
-	var _p0 *byte
44
-	_p0, err = syscall.BytePtrFromString(path)
45
-	if err != nil {
46
-		return
47
-	}
48
-	var _p1 *byte
49
-	_p1, err = syscall.BytePtrFromString(attr)
50
-	if err != nil {
51
-		return
52
-	}
53
-	var _p2 unsafe.Pointer
54
-	if len(data) > 0 {
55
-		_p2 = unsafe.Pointer(&data[0])
56
-	} else {
57
-		_p2 = unsafe.Pointer(&_zero)
58
-	}
59
-	_, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
60
-	use(unsafe.Pointer(_p0))
61
-	use(unsafe.Pointer(_p1))
62
-	if e1 != 0 {
63
-		err = errnoErr(e1)
64
-	}
65
-	return
66
-}
67
-
68
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
69
-
70
-func removexattr(path string, attr string, options int) (err error) {
71
-	var _p0 *byte
72
-	_p0, err = syscall.BytePtrFromString(path)
73
-	if err != nil {
74
-		return
75
-	}
76
-	var _p1 *byte
77
-	_p1, err = syscall.BytePtrFromString(attr)
78
-	if err != nil {
79
-		return
80
-	}
81
-	_, _, e1 := syscall.Syscall(syscall.SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options))
82
-	use(unsafe.Pointer(_p0))
83
-	use(unsafe.Pointer(_p1))
84
-	if e1 != 0 {
85
-		err = errnoErr(e1)
86
-	}
87
-	return
88
-}
89
-
90
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
91
-
92
-func listxattr(path string, dest []byte, options int) (sz int, err error) {
93
-	var _p0 *byte
94
-	_p0, err = syscall.BytePtrFromString(path)
95
-	if err != nil {
96
-		return
97
-	}
98
-	var _p1 unsafe.Pointer
99
-	if len(dest) > 0 {
100
-		_p1 = unsafe.Pointer(&dest[0])
101
-	} else {
102
-		_p1 = unsafe.Pointer(&_zero)
103
-	}
104
-	r0, _, e1 := syscall.Syscall6(syscall.SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(options), 0, 0)
105
-	use(unsafe.Pointer(_p0))
106
-	sz = int(r0)
107
-	if e1 != 0 {
108
-		err = errnoErr(e1)
109
-	}
110
-	return
111
-}
112 1
deleted file mode 100644
... ...
@@ -1,12 +0,0 @@
1
-package sysx
2
-
3
-import (
4
-	"errors"
5
-)
6
-
7
-// Initial stub version for FreeBSD. FreeBSD has a different
8
-// syscall API from Darwin and Linux for extended attributes;
9
-// it is also not widely used. It is not exposed at all by the
10
-// Go syscall package, so we need to implement directly eventually.
11
-
12
-var unsupported = errors.New("extended attributes unsupported on FreeBSD")
13 1
deleted file mode 100644
... ...
@@ -1,44 +0,0 @@
1
-package sysx
2
-
3
-import "golang.org/x/sys/unix"
4
-
5
-// Listxattr calls syscall listxattr and reads all content
6
-// and returns a string array
7
-func Listxattr(path string) ([]string, error) {
8
-	return listxattrAll(path, unix.Listxattr)
9
-}
10
-
11
-// Removexattr calls syscall removexattr
12
-func Removexattr(path string, attr string) (err error) {
13
-	return unix.Removexattr(path, attr)
14
-}
15
-
16
-// Setxattr calls syscall setxattr
17
-func Setxattr(path string, attr string, data []byte, flags int) (err error) {
18
-	return unix.Setxattr(path, attr, data, flags)
19
-}
20
-
21
-// Getxattr calls syscall getxattr
22
-func Getxattr(path, attr string) ([]byte, error) {
23
-	return getxattrAll(path, attr, unix.Getxattr)
24
-}
25
-
26
-// LListxattr lists xattrs, not following symlinks
27
-func LListxattr(path string) ([]string, error) {
28
-	return listxattrAll(path, unix.Llistxattr)
29
-}
30
-
31
-// LRemovexattr removes an xattr, not following symlinks
32
-func LRemovexattr(path string, attr string) (err error) {
33
-	return unix.Lremovexattr(path, attr)
34
-}
35
-
36
-// LSetxattr sets an xattr, not following symlinks
37
-func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
38
-	return unix.Lsetxattr(path, attr, data, flags)
39
-}
40
-
41
-// LGetxattr gets an xattr, not following symlinks
42
-func LGetxattr(path, attr string) ([]byte, error) {
43
-	return getxattrAll(path, attr, unix.Lgetxattr)
44
-}
45 1
deleted file mode 100644
... ...
@@ -1,7 +0,0 @@
1
-package sysx
2
-
3
-import (
4
-	"errors"
5
-)
6
-
7
-var unsupported = errors.New("extended attributes unsupported on OpenBSD")
8 1
deleted file mode 100644
... ...
@@ -1,12 +0,0 @@
1
-package sysx
2
-
3
-import (
4
-	"errors"
5
-)
6
-
7
-// Initial stub version for Solaris. Solaris has a different
8
-// syscall API from Darwin and Linux for extended attributes;
9
-// it is also not widely used. It is not exposed at all by the
10
-// Go syscall package, so we need to implement directly eventually.
11
-
12
-var unsupported = errors.New("extended attributes unsupported on Solaris")
... ...
@@ -1,7 +1,14 @@
1
-// +build freebsd openbsd solaris
1
+// +build !linux,!darwin
2 2
 
3 3
 package sysx
4 4
 
5
+import (
6
+	"errors"
7
+	"runtime"
8
+)
9
+
10
+var unsupported = errors.New("extended attributes unsupported on " + runtime.GOOS)
11
+
5 12
 // Listxattr calls syscall listxattr and reads all content
6 13
 // and returns a string array
7 14
 func Listxattr(path string) ([]string, error) {
... ...
@@ -10,4 +10,4 @@ github.com/spf13/pflag 4c012f6dcd9546820e378d0bdda4d8fc772cdfea
10 10
 golang.org/x/crypto 9f005a07e0d31d45e6656d241bb5c0f2efd4bc94
11 11
 golang.org/x/net a337091b0525af65de94df2eb7e98bd9962dcbe2
12 12
 golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
13
-golang.org/x/sys 665f6529cca930e27b831a0d1dafffbe1c172924
13
+golang.org/x/sys 77b0e4315053a57ed2962443614bdb28db152054
... ...
@@ -1,4 +1,4 @@
1
-// //+build ignore
1
+/* //+build ignore */
2 2
 
3 3
 // Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
4 4
 // Use of this source code is governed by a MIT license found in the LICENSE file.
5 5
new file mode 100644
... ...
@@ -0,0 +1,197 @@
0
+// Copyright 2012 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// This code can be compiled and used to test the otr package against libotr.
5
+// See otr_test.go.
6
+
7
+// +build ignore
8
+
9
+#include <stdio.h>
10
+#include <stdlib.h>
11
+#include <unistd.h>
12
+
13
+#include <proto.h>
14
+#include <message.h>
15
+#include <privkey.h>
16
+
17
+static int g_session_established = 0;
18
+
19
+OtrlPolicy policy(void *opdata, ConnContext *context) {
20
+  return OTRL_POLICY_ALWAYS;
21
+}
22
+
23
+int is_logged_in(void *opdata, const char *accountname, const char *protocol,
24
+                 const char *recipient) {
25
+  return 1;
26
+}
27
+
28
+void inject_message(void *opdata, const char *accountname, const char *protocol,
29
+                    const char *recipient, const char *message) {
30
+  printf("%s\n", message);
31
+  fflush(stdout);
32
+  fprintf(stderr, "libotr helper sent: %s\n", message);
33
+}
34
+
35
+void update_context_list(void *opdata) {}
36
+
37
+void new_fingerprint(void *opdata, OtrlUserState us, const char *accountname,
38
+                     const char *protocol, const char *username,
39
+                     unsigned char fingerprint[20]) {
40
+  fprintf(stderr, "NEW FINGERPRINT\n");
41
+  g_session_established = 1;
42
+}
43
+
44
+void write_fingerprints(void *opdata) {}
45
+
46
+void gone_secure(void *opdata, ConnContext *context) {}
47
+
48
+void gone_insecure(void *opdata, ConnContext *context) {}
49
+
50
+void still_secure(void *opdata, ConnContext *context, int is_reply) {}
51
+
52
+int max_message_size(void *opdata, ConnContext *context) { return 99999; }
53
+
54
+const char *account_name(void *opdata, const char *account,
55
+                         const char *protocol) {
56
+  return "ACCOUNT";
57
+}
58
+
59
+void account_name_free(void *opdata, const char *account_name) {}
60
+
61
+const char *error_message(void *opdata, ConnContext *context,
62
+                          OtrlErrorCode err_code) {
63
+  return "ERR";
64
+}
65
+
66
+void error_message_free(void *opdata, const char *msg) {}
67
+
68
+void resent_msg_prefix_free(void *opdata, const char *prefix) {}
69
+
70
+void handle_smp_event(void *opdata, OtrlSMPEvent smp_event,
71
+                      ConnContext *context, unsigned short progress_event,
72
+                      char *question) {}
73
+
74
+void handle_msg_event(void *opdata, OtrlMessageEvent msg_event,
75
+                      ConnContext *context, const char *message,
76
+                      gcry_error_t err) {
77
+  fprintf(stderr, "msg event: %d %s\n", msg_event, message);
78
+}
79
+
80
+OtrlMessageAppOps uiops = {
81
+    policy,
82
+    NULL,
83
+    is_logged_in,
84
+    inject_message,
85
+    update_context_list,
86
+    new_fingerprint,
87
+    write_fingerprints,
88
+    gone_secure,
89
+    gone_insecure,
90
+    still_secure,
91
+    max_message_size,
92
+    account_name,
93
+    account_name_free,
94
+    NULL, /* received_symkey */
95
+    error_message,
96
+    error_message_free,
97
+    NULL, /* resent_msg_prefix */
98
+    resent_msg_prefix_free,
99
+    handle_smp_event,
100
+    handle_msg_event,
101
+    NULL /* create_instag */,
102
+    NULL /* convert_msg */,
103
+    NULL /* convert_free */,
104
+    NULL /* timer_control */,
105
+};
106
+
107
+static const char kPrivateKeyData[] =
108
+    "(privkeys (account (name \"account\") (protocol proto) (private-key (dsa "
109
+    "(p "
110
+    "#00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F"
111
+    "30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E"
112
+    "5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB"
113
+    "8C031D3561FECEE72EBB4A090D450A9B7A857#) (q "
114
+    "#00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#) (g "
115
+    "#535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F"
116
+    "1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F"
117
+    "6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57"
118
+    "597766A2F9CE3857D7ACE3E1E3BC1FC6F26#) (y "
119
+    "#0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF"
120
+    "2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93"
121
+    "454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A"
122
+    "3C0FF501E3DC673B76D7BABF349009B6ECF#) (x "
123
+    "#14D0345A3562C480A039E3C72764F72D79043216#)))))\n";
124
+
125
+int main() {
126
+  OTRL_INIT;
127
+
128
+  // We have to write the private key information to a file because the libotr
129
+  // API demands a filename to read from.
130
+  const char *tmpdir = "/tmp";
131
+  if (getenv("TMP")) {
132
+    tmpdir = getenv("TMP");
133
+  }
134
+
135
+  char private_key_file[256];
136
+  snprintf(private_key_file, sizeof(private_key_file),
137
+           "%s/libotr_test_helper_privatekeys-XXXXXX", tmpdir);
138
+  int fd = mkstemp(private_key_file);
139
+  if (fd == -1) {
140
+    perror("creating temp file");
141
+  }
142
+  write(fd, kPrivateKeyData, sizeof(kPrivateKeyData) - 1);
143
+  close(fd);
144
+
145
+  OtrlUserState userstate = otrl_userstate_create();
146
+  otrl_privkey_read(userstate, private_key_file);
147
+  unlink(private_key_file);
148
+
149
+  fprintf(stderr, "libotr helper started\n");
150
+
151
+  char buf[4096];
152
+
153
+  for (;;) {
154
+    char *message = fgets(buf, sizeof(buf), stdin);
155
+    if (strlen(message) == 0) {
156
+      break;
157
+    }
158
+    message[strlen(message) - 1] = 0;
159
+    fprintf(stderr, "libotr helper got: %s\n", message);
160
+
161
+    char *newmessage = NULL;
162
+    OtrlTLV *tlvs;
163
+    int ignore_message = otrl_message_receiving(
164
+        userstate, &uiops, NULL, "account", "proto", "peer", message,
165
+        &newmessage, &tlvs, NULL, NULL, NULL);
166
+    if (tlvs) {
167
+      otrl_tlv_free(tlvs);
168
+    }
169
+
170
+    if (newmessage != NULL) {
171
+      fprintf(stderr, "libotr got: %s\n", newmessage);
172
+      otrl_message_free(newmessage);
173
+
174
+      gcry_error_t err;
175
+      char *newmessage = NULL;
176
+
177
+      err = otrl_message_sending(userstate, &uiops, NULL, "account", "proto",
178
+                                 "peer", 0, "test message", NULL, &newmessage,
179
+                                 OTRL_FRAGMENT_SEND_SKIP, NULL, NULL, NULL);
180
+      if (newmessage == NULL) {
181
+        fprintf(stderr, "libotr didn't encrypt message\n");
182
+        return 1;
183
+      }
184
+      write(1, newmessage, strlen(newmessage));
185
+      write(1, "\n", 1);
186
+      fprintf(stderr, "libotr sent: %s\n", newmessage);
187
+      otrl_message_free(newmessage);
188
+
189
+      g_session_established = 0;
190
+      write(1, "?OTRv2?\n", 8);
191
+      fprintf(stderr, "libotr sent: ?OTRv2\n");
192
+    }
193
+  }
194
+
195
+  return 0;
196
+}
0 197
new file mode 100644
... ...
@@ -0,0 +1,1415 @@
0
+// Copyright 2012 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// Package otr implements the Off The Record protocol as specified in
5
+// http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html
6
+package otr // import "golang.org/x/crypto/otr"
7
+
8
+import (
9
+	"bytes"
10
+	"crypto/aes"
11
+	"crypto/cipher"
12
+	"crypto/dsa"
13
+	"crypto/hmac"
14
+	"crypto/rand"
15
+	"crypto/sha1"
16
+	"crypto/sha256"
17
+	"crypto/subtle"
18
+	"encoding/base64"
19
+	"encoding/hex"
20
+	"errors"
21
+	"hash"
22
+	"io"
23
+	"math/big"
24
+	"strconv"
25
+)
26
+
27
+// SecurityChange describes a change in the security state of a Conversation.
28
+type SecurityChange int
29
+
30
+const (
31
+	NoChange SecurityChange = iota
32
+	// NewKeys indicates that a key exchange has completed. This occurs
33
+	// when a conversation first becomes encrypted, and when the keys are
34
+	// renegotiated within an encrypted conversation.
35
+	NewKeys
36
+	// SMPSecretNeeded indicates that the peer has started an
37
+	// authentication and that we need to supply a secret. Call SMPQuestion
38
+	// to get the optional, human readable challenge and then Authenticate
39
+	// to supply the matching secret.
40
+	SMPSecretNeeded
41
+	// SMPComplete indicates that an authentication completed. The identity
42
+	// of the peer has now been confirmed.
43
+	SMPComplete
44
+	// SMPFailed indicates that an authentication failed.
45
+	SMPFailed
46
+	// ConversationEnded indicates that the peer ended the secure
47
+	// conversation.
48
+	ConversationEnded
49
+)
50
+
51
+// QueryMessage can be sent to a peer to start an OTR conversation.
52
+var QueryMessage = "?OTRv2?"
53
+
54
+// ErrorPrefix can be used to make an OTR error by appending an error message
55
+// to it.
56
+var ErrorPrefix = "?OTR Error:"
57
+
58
+var (
59
+	fragmentPartSeparator = []byte(",")
60
+	fragmentPrefix        = []byte("?OTR,")
61
+	msgPrefix             = []byte("?OTR:")
62
+	queryMarker           = []byte("?OTR")
63
+)
64
+
65
+// isQuery attempts to parse an OTR query from msg and returns the greatest
66
+// common version, or 0 if msg is not an OTR query.
67
+func isQuery(msg []byte) (greatestCommonVersion int) {
68
+	pos := bytes.Index(msg, queryMarker)
69
+	if pos == -1 {
70
+		return 0
71
+	}
72
+	for i, c := range msg[pos+len(queryMarker):] {
73
+		if i == 0 {
74
+			if c == '?' {
75
+				// Indicates support for version 1, but we don't
76
+				// implement that.
77
+				continue
78
+			}
79
+
80
+			if c != 'v' {
81
+				// Invalid message
82
+				return 0
83
+			}
84
+
85
+			continue
86
+		}
87
+
88
+		if c == '?' {
89
+			// End of message
90
+			return
91
+		}
92
+
93
+		if c == ' ' || c == '\t' {
94
+			// Probably an invalid message
95
+			return 0
96
+		}
97
+
98
+		if c == '2' {
99
+			greatestCommonVersion = 2
100
+		}
101
+	}
102
+
103
+	return 0
104
+}
105
+
106
+const (
107
+	statePlaintext = iota
108
+	stateEncrypted
109
+	stateFinished
110
+)
111
+
112
+const (
113
+	authStateNone = iota
114
+	authStateAwaitingDHKey
115
+	authStateAwaitingRevealSig
116
+	authStateAwaitingSig
117
+)
118
+
119
+const (
120
+	msgTypeDHCommit  = 2
121
+	msgTypeData      = 3
122
+	msgTypeDHKey     = 10
123
+	msgTypeRevealSig = 17
124
+	msgTypeSig       = 18
125
+)
126
+
127
+const (
128
+	// If the requested fragment size is less than this, it will be ignored.
129
+	minFragmentSize = 18
130
+	// Messages are padded to a multiple of this number of bytes.
131
+	paddingGranularity = 256
132
+	// The number of bytes in a Diffie-Hellman private value (320-bits).
133
+	dhPrivateBytes = 40
134
+	// The number of bytes needed to represent an element of the DSA
135
+	// subgroup (160-bits).
136
+	dsaSubgroupBytes = 20
137
+	// The number of bytes of the MAC that are sent on the wire (160-bits).
138
+	macPrefixBytes = 20
139
+)
140
+
141
+// These are the global, common group parameters for OTR.
142
+var (
143
+	p       *big.Int // group prime
144
+	g       *big.Int // group generator
145
+	q       *big.Int // group order
146
+	pMinus2 *big.Int
147
+)
148
+
149
+func init() {
150
+	p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16)
151
+	q, _ = new(big.Int).SetString("7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68948127044533E63A0105DF531D89CD9128A5043CC71A026EF7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6F71C35FDAD44CFD2D74F9208BE258FF324943328F6722D9EE1003E5C50B1DF82CC6D241B0E2AE9CD348B1FD47E9267AFC1B2AE91EE51D6CB0E3179AB1042A95DCF6A9483B84B4B36B3861AA7255E4C0278BA36046511B993FFFFFFFFFFFFFFFF", 16)
152
+	g = new(big.Int).SetInt64(2)
153
+	pMinus2 = new(big.Int).Sub(p, g)
154
+}
155
+
156
+// Conversation represents a relation with a peer. The zero value is a valid
157
+// Conversation, although PrivateKey must be set.
158
+//
159
+// When communicating with a peer, all inbound messages should be passed to
160
+// Conversation.Receive and all outbound messages to Conversation.Send. The
161
+// Conversation will take care of maintaining the encryption state and
162
+// negotiating encryption as needed.
163
+type Conversation struct {
164
+	// PrivateKey contains the private key to use to sign key exchanges.
165
+	PrivateKey *PrivateKey
166
+
167
+	// Rand can be set to override the entropy source. Otherwise,
168
+	// crypto/rand will be used.
169
+	Rand io.Reader
170
+	// If FragmentSize is set, all messages produced by Receive and Send
171
+	// will be fragmented into messages of, at most, this number of bytes.
172
+	FragmentSize int
173
+
174
+	// Once Receive has returned NewKeys once, the following fields are
175
+	// valid.
176
+	SSID           [8]byte
177
+	TheirPublicKey PublicKey
178
+
179
+	state, authState int
180
+
181
+	r       [16]byte
182
+	x, y    *big.Int
183
+	gx, gy  *big.Int
184
+	gxBytes []byte
185
+	digest  [sha256.Size]byte
186
+
187
+	revealKeys, sigKeys akeKeys
188
+
189
+	myKeyId         uint32
190
+	myCurrentDHPub  *big.Int
191
+	myCurrentDHPriv *big.Int
192
+	myLastDHPub     *big.Int
193
+	myLastDHPriv    *big.Int
194
+
195
+	theirKeyId        uint32
196
+	theirCurrentDHPub *big.Int
197
+	theirLastDHPub    *big.Int
198
+
199
+	keySlots [4]keySlot
200
+
201
+	myCounter    [8]byte
202
+	theirLastCtr [8]byte
203
+	oldMACs      []byte
204
+
205
+	k, n int // fragment state
206
+	frag []byte
207
+
208
+	smp smpState
209
+}
210
+
211
+// A keySlot contains key material for a specific (their keyid, my keyid) pair.
212
+type keySlot struct {
213
+	// used is true if this slot is valid. If false, it's free for reuse.
214
+	used                   bool
215
+	theirKeyId             uint32
216
+	myKeyId                uint32
217
+	sendAESKey, recvAESKey []byte
218
+	sendMACKey, recvMACKey []byte
219
+	theirLastCtr           [8]byte
220
+}
221
+
222
+// akeKeys are generated during key exchange. There's one set for the reveal
223
+// signature message and another for the signature message. In the protocol
224
+// spec the latter are indicated with a prime mark.
225
+type akeKeys struct {
226
+	c      [16]byte
227
+	m1, m2 [32]byte
228
+}
229
+
230
+func (c *Conversation) rand() io.Reader {
231
+	if c.Rand != nil {
232
+		return c.Rand
233
+	}
234
+	return rand.Reader
235
+}
236
+
237
+func (c *Conversation) randMPI(buf []byte) *big.Int {
238
+	_, err := io.ReadFull(c.rand(), buf)
239
+	if err != nil {
240
+		panic("otr: short read from random source")
241
+	}
242
+
243
+	return new(big.Int).SetBytes(buf)
244
+}
245
+
246
+// tlv represents the type-length value from the protocol.
247
+type tlv struct {
248
+	typ, length uint16
249
+	data        []byte
250
+}
251
+
252
+const (
253
+	tlvTypePadding          = 0
254
+	tlvTypeDisconnected     = 1
255
+	tlvTypeSMP1             = 2
256
+	tlvTypeSMP2             = 3
257
+	tlvTypeSMP3             = 4
258
+	tlvTypeSMP4             = 5
259
+	tlvTypeSMPAbort         = 6
260
+	tlvTypeSMP1WithQuestion = 7
261
+)
262
+
263
+// Receive handles a message from a peer. It returns a human readable message,
264
+// an indicator of whether that message was encrypted, a hint about the
265
+// encryption state and zero or more messages to send back to the peer.
266
+// These messages do not need to be passed to Send before transmission.
267
+func (c *Conversation) Receive(in []byte) (out []byte, encrypted bool, change SecurityChange, toSend [][]byte, err error) {
268
+	if bytes.HasPrefix(in, fragmentPrefix) {
269
+		in, err = c.processFragment(in)
270
+		if in == nil || err != nil {
271
+			return
272
+		}
273
+	}
274
+
275
+	if bytes.HasPrefix(in, msgPrefix) && in[len(in)-1] == '.' {
276
+		in = in[len(msgPrefix) : len(in)-1]
277
+	} else if version := isQuery(in); version > 0 {
278
+		c.authState = authStateAwaitingDHKey
279
+		c.reset()
280
+		toSend = c.encode(c.generateDHCommit())
281
+		return
282
+	} else {
283
+		// plaintext message
284
+		out = in
285
+		return
286
+	}
287
+
288
+	msg := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
289
+	msgLen, err := base64.StdEncoding.Decode(msg, in)
290
+	if err != nil {
291
+		err = errors.New("otr: invalid base64 encoding in message")
292
+		return
293
+	}
294
+	msg = msg[:msgLen]
295
+
296
+	// The first two bytes are the protocol version (2)
297
+	if len(msg) < 3 || msg[0] != 0 || msg[1] != 2 {
298
+		err = errors.New("otr: invalid OTR message")
299
+		return
300
+	}
301
+
302
+	msgType := int(msg[2])
303
+	msg = msg[3:]
304
+
305
+	switch msgType {
306
+	case msgTypeDHCommit:
307
+		switch c.authState {
308
+		case authStateNone:
309
+			c.authState = authStateAwaitingRevealSig
310
+			if err = c.processDHCommit(msg); err != nil {
311
+				return
312
+			}
313
+			c.reset()
314
+			toSend = c.encode(c.generateDHKey())
315
+			return
316
+		case authStateAwaitingDHKey:
317
+			// This is a 'SYN-crossing'. The greater digest wins.
318
+			var cmp int
319
+			if cmp, err = c.compareToDHCommit(msg); err != nil {
320
+				return
321
+			}
322
+			if cmp > 0 {
323
+				// We win. Retransmit DH commit.
324
+				toSend = c.encode(c.serializeDHCommit())
325
+				return
326
+			} else {
327
+				// They win. We forget about our DH commit.
328
+				c.authState = authStateAwaitingRevealSig
329
+				if err = c.processDHCommit(msg); err != nil {
330
+					return
331
+				}
332
+				c.reset()
333
+				toSend = c.encode(c.generateDHKey())
334
+				return
335
+			}
336
+		case authStateAwaitingRevealSig:
337
+			if err = c.processDHCommit(msg); err != nil {
338
+				return
339
+			}
340
+			toSend = c.encode(c.serializeDHKey())
341
+		case authStateAwaitingSig:
342
+			if err = c.processDHCommit(msg); err != nil {
343
+				return
344
+			}
345
+			c.reset()
346
+			toSend = c.encode(c.generateDHKey())
347
+			c.authState = authStateAwaitingRevealSig
348
+		default:
349
+			panic("bad state")
350
+		}
351
+	case msgTypeDHKey:
352
+		switch c.authState {
353
+		case authStateAwaitingDHKey:
354
+			var isSame bool
355
+			if isSame, err = c.processDHKey(msg); err != nil {
356
+				return
357
+			}
358
+			if isSame {
359
+				err = errors.New("otr: unexpected duplicate DH key")
360
+				return
361
+			}
362
+			toSend = c.encode(c.generateRevealSig())
363
+			c.authState = authStateAwaitingSig
364
+		case authStateAwaitingSig:
365
+			var isSame bool
366
+			if isSame, err = c.processDHKey(msg); err != nil {
367
+				return
368
+			}
369
+			if isSame {
370
+				toSend = c.encode(c.serializeDHKey())
371
+			}
372
+		}
373
+	case msgTypeRevealSig:
374
+		if c.authState != authStateAwaitingRevealSig {
375
+			return
376
+		}
377
+		if err = c.processRevealSig(msg); err != nil {
378
+			return
379
+		}
380
+		toSend = c.encode(c.generateSig())
381
+		c.authState = authStateNone
382
+		c.state = stateEncrypted
383
+		change = NewKeys
384
+	case msgTypeSig:
385
+		if c.authState != authStateAwaitingSig {
386
+			return
387
+		}
388
+		if err = c.processSig(msg); err != nil {
389
+			return
390
+		}
391
+		c.authState = authStateNone
392
+		c.state = stateEncrypted
393
+		change = NewKeys
394
+	case msgTypeData:
395
+		if c.state != stateEncrypted {
396
+			err = errors.New("otr: encrypted message received without encrypted session established")
397
+			return
398
+		}
399
+		var tlvs []tlv
400
+		out, tlvs, err = c.processData(msg)
401
+		encrypted = true
402
+
403
+	EachTLV:
404
+		for _, inTLV := range tlvs {
405
+			switch inTLV.typ {
406
+			case tlvTypeDisconnected:
407
+				change = ConversationEnded
408
+				c.state = stateFinished
409
+				break EachTLV
410
+			case tlvTypeSMP1, tlvTypeSMP2, tlvTypeSMP3, tlvTypeSMP4, tlvTypeSMPAbort, tlvTypeSMP1WithQuestion:
411
+				var reply tlv
412
+				var complete bool
413
+				reply, complete, err = c.processSMP(inTLV)
414
+				if err == smpSecretMissingError {
415
+					err = nil
416
+					change = SMPSecretNeeded
417
+					c.smp.saved = &inTLV
418
+					return
419
+				}
420
+				if err == smpFailureError {
421
+					err = nil
422
+					change = SMPFailed
423
+				} else if complete {
424
+					change = SMPComplete
425
+				}
426
+				if reply.typ != 0 {
427
+					toSend = c.encode(c.generateData(nil, &reply))
428
+				}
429
+				break EachTLV
430
+			default:
431
+				// skip unknown TLVs
432
+			}
433
+		}
434
+	default:
435
+		err = errors.New("otr: unknown message type " + strconv.Itoa(msgType))
436
+	}
437
+
438
+	return
439
+}
440
+
441
+// Send takes a human readable message from the local user, possibly encrypts
442
+// it and returns zero one or more messages to send to the peer.
443
+func (c *Conversation) Send(msg []byte) ([][]byte, error) {
444
+	switch c.state {
445
+	case statePlaintext:
446
+		return [][]byte{msg}, nil
447
+	case stateEncrypted:
448
+		return c.encode(c.generateData(msg, nil)), nil
449
+	case stateFinished:
450
+		return nil, errors.New("otr: cannot send message because secure conversation has finished")
451
+	}
452
+
453
+	return nil, errors.New("otr: cannot send message in current state")
454
+}
455
+
456
+// SMPQuestion returns the human readable challenge question from the peer.
457
+// It's only valid after Receive has returned SMPSecretNeeded.
458
+func (c *Conversation) SMPQuestion() string {
459
+	return c.smp.question
460
+}
461
+
462
+// Authenticate begins an authentication with the peer. Authentication involves
463
+// an optional challenge message and a shared secret. The authentication
464
+// proceeds until either Receive returns SMPComplete, SMPSecretNeeded (which
465
+// indicates that a new authentication is happening and thus this one was
466
+// aborted) or SMPFailed.
467
+func (c *Conversation) Authenticate(question string, mutualSecret []byte) (toSend [][]byte, err error) {
468
+	if c.state != stateEncrypted {
469
+		err = errors.New("otr: can't authenticate a peer without a secure conversation established")
470
+		return
471
+	}
472
+
473
+	if c.smp.saved != nil {
474
+		c.calcSMPSecret(mutualSecret, false /* they started it */)
475
+
476
+		var out tlv
477
+		var complete bool
478
+		out, complete, err = c.processSMP(*c.smp.saved)
479
+		if complete {
480
+			panic("SMP completed on the first message")
481
+		}
482
+		c.smp.saved = nil
483
+		if out.typ != 0 {
484
+			toSend = c.encode(c.generateData(nil, &out))
485
+		}
486
+		return
487
+	}
488
+
489
+	c.calcSMPSecret(mutualSecret, true /* we started it */)
490
+	outs := c.startSMP(question)
491
+	for _, out := range outs {
492
+		toSend = append(toSend, c.encode(c.generateData(nil, &out))...)
493
+	}
494
+	return
495
+}
496
+
497
+// End ends a secure conversation by generating a termination message for
498
+// the peer and switches to unencrypted communication.
499
+func (c *Conversation) End() (toSend [][]byte) {
500
+	switch c.state {
501
+	case statePlaintext:
502
+		return nil
503
+	case stateEncrypted:
504
+		c.state = statePlaintext
505
+		return c.encode(c.generateData(nil, &tlv{typ: tlvTypeDisconnected}))
506
+	case stateFinished:
507
+		c.state = statePlaintext
508
+		return nil
509
+	}
510
+	panic("unreachable")
511
+}
512
+
513
+// IsEncrypted returns true if a message passed to Send would be encrypted
514
+// before transmission. This result remains valid until the next call to
515
+// Receive or End, which may change the state of the Conversation.
516
+func (c *Conversation) IsEncrypted() bool {
517
+	return c.state == stateEncrypted
518
+}
519
+
520
+var fragmentError = errors.New("otr: invalid OTR fragment")
521
+
522
+// processFragment processes a fragmented OTR message and possibly returns a
523
+// complete message. Fragmented messages look like "?OTR,k,n,msg," where k is
524
+// the fragment number (starting from 1), n is the number of fragments in this
525
+// message and msg is a substring of the base64 encoded message.
526
+func (c *Conversation) processFragment(in []byte) (out []byte, err error) {
527
+	in = in[len(fragmentPrefix):] // remove "?OTR,"
528
+	parts := bytes.Split(in, fragmentPartSeparator)
529
+	if len(parts) != 4 || len(parts[3]) != 0 {
530
+		return nil, fragmentError
531
+	}
532
+
533
+	k, err := strconv.Atoi(string(parts[0]))
534
+	if err != nil {
535
+		return nil, fragmentError
536
+	}
537
+
538
+	n, err := strconv.Atoi(string(parts[1]))
539
+	if err != nil {
540
+		return nil, fragmentError
541
+	}
542
+
543
+	if k < 1 || n < 1 || k > n {
544
+		return nil, fragmentError
545
+	}
546
+
547
+	if k == 1 {
548
+		c.frag = append(c.frag[:0], parts[2]...)
549
+		c.k, c.n = k, n
550
+	} else if n == c.n && k == c.k+1 {
551
+		c.frag = append(c.frag, parts[2]...)
552
+		c.k++
553
+	} else {
554
+		c.frag = c.frag[:0]
555
+		c.n, c.k = 0, 0
556
+	}
557
+
558
+	if c.n > 0 && c.k == c.n {
559
+		c.n, c.k = 0, 0
560
+		return c.frag, nil
561
+	}
562
+
563
+	return nil, nil
564
+}
565
+
566
+func (c *Conversation) generateDHCommit() []byte {
567
+	_, err := io.ReadFull(c.rand(), c.r[:])
568
+	if err != nil {
569
+		panic("otr: short read from random source")
570
+	}
571
+
572
+	var xBytes [dhPrivateBytes]byte
573
+	c.x = c.randMPI(xBytes[:])
574
+	c.gx = new(big.Int).Exp(g, c.x, p)
575
+	c.gy = nil
576
+	c.gxBytes = appendMPI(nil, c.gx)
577
+
578
+	h := sha256.New()
579
+	h.Write(c.gxBytes)
580
+	h.Sum(c.digest[:0])
581
+
582
+	aesCipher, err := aes.NewCipher(c.r[:])
583
+	if err != nil {
584
+		panic(err.Error())
585
+	}
586
+
587
+	var iv [aes.BlockSize]byte
588
+	ctr := cipher.NewCTR(aesCipher, iv[:])
589
+	ctr.XORKeyStream(c.gxBytes, c.gxBytes)
590
+
591
+	return c.serializeDHCommit()
592
+}
593
+
594
+func (c *Conversation) serializeDHCommit() []byte {
595
+	var ret []byte
596
+	ret = appendU16(ret, 2) // protocol version
597
+	ret = append(ret, msgTypeDHCommit)
598
+	ret = appendData(ret, c.gxBytes)
599
+	ret = appendData(ret, c.digest[:])
600
+	return ret
601
+}
602
+
603
+func (c *Conversation) processDHCommit(in []byte) error {
604
+	var ok1, ok2 bool
605
+	c.gxBytes, in, ok1 = getData(in)
606
+	digest, in, ok2 := getData(in)
607
+	if !ok1 || !ok2 || len(in) > 0 {
608
+		return errors.New("otr: corrupt DH commit message")
609
+	}
610
+	copy(c.digest[:], digest)
611
+	return nil
612
+}
613
+
614
+func (c *Conversation) compareToDHCommit(in []byte) (int, error) {
615
+	_, in, ok1 := getData(in)
616
+	digest, in, ok2 := getData(in)
617
+	if !ok1 || !ok2 || len(in) > 0 {
618
+		return 0, errors.New("otr: corrupt DH commit message")
619
+	}
620
+	return bytes.Compare(c.digest[:], digest), nil
621
+}
622
+
623
+func (c *Conversation) generateDHKey() []byte {
624
+	var yBytes [dhPrivateBytes]byte
625
+	c.y = c.randMPI(yBytes[:])
626
+	c.gy = new(big.Int).Exp(g, c.y, p)
627
+	return c.serializeDHKey()
628
+}
629
+
630
+func (c *Conversation) serializeDHKey() []byte {
631
+	var ret []byte
632
+	ret = appendU16(ret, 2) // protocol version
633
+	ret = append(ret, msgTypeDHKey)
634
+	ret = appendMPI(ret, c.gy)
635
+	return ret
636
+}
637
+
638
+func (c *Conversation) processDHKey(in []byte) (isSame bool, err error) {
639
+	gy, in, ok := getMPI(in)
640
+	if !ok {
641
+		err = errors.New("otr: corrupt DH key message")
642
+		return
643
+	}
644
+	if gy.Cmp(g) < 0 || gy.Cmp(pMinus2) > 0 {
645
+		err = errors.New("otr: DH value out of range")
646
+		return
647
+	}
648
+	if c.gy != nil {
649
+		isSame = c.gy.Cmp(gy) == 0
650
+		return
651
+	}
652
+	c.gy = gy
653
+	return
654
+}
655
+
656
+func (c *Conversation) generateEncryptedSignature(keys *akeKeys, xFirst bool) ([]byte, []byte) {
657
+	var xb []byte
658
+	xb = c.PrivateKey.PublicKey.Serialize(xb)
659
+
660
+	var verifyData []byte
661
+	if xFirst {
662
+		verifyData = appendMPI(verifyData, c.gx)
663
+		verifyData = appendMPI(verifyData, c.gy)
664
+	} else {
665
+		verifyData = appendMPI(verifyData, c.gy)
666
+		verifyData = appendMPI(verifyData, c.gx)
667
+	}
668
+	verifyData = append(verifyData, xb...)
669
+	verifyData = appendU32(verifyData, c.myKeyId)
670
+
671
+	mac := hmac.New(sha256.New, keys.m1[:])
672
+	mac.Write(verifyData)
673
+	mb := mac.Sum(nil)
674
+
675
+	xb = appendU32(xb, c.myKeyId)
676
+	xb = append(xb, c.PrivateKey.Sign(c.rand(), mb)...)
677
+
678
+	aesCipher, err := aes.NewCipher(keys.c[:])
679
+	if err != nil {
680
+		panic(err.Error())
681
+	}
682
+	var iv [aes.BlockSize]byte
683
+	ctr := cipher.NewCTR(aesCipher, iv[:])
684
+	ctr.XORKeyStream(xb, xb)
685
+
686
+	mac = hmac.New(sha256.New, keys.m2[:])
687
+	encryptedSig := appendData(nil, xb)
688
+	mac.Write(encryptedSig)
689
+
690
+	return encryptedSig, mac.Sum(nil)
691
+}
692
+
693
+func (c *Conversation) generateRevealSig() []byte {
694
+	s := new(big.Int).Exp(c.gy, c.x, p)
695
+	c.calcAKEKeys(s)
696
+	c.myKeyId++
697
+
698
+	encryptedSig, mac := c.generateEncryptedSignature(&c.revealKeys, true /* gx comes first */)
699
+
700
+	c.myCurrentDHPub = c.gx
701
+	c.myCurrentDHPriv = c.x
702
+	c.rotateDHKeys()
703
+	incCounter(&c.myCounter)
704
+
705
+	var ret []byte
706
+	ret = appendU16(ret, 2)
707
+	ret = append(ret, msgTypeRevealSig)
708
+	ret = appendData(ret, c.r[:])
709
+	ret = append(ret, encryptedSig...)
710
+	ret = append(ret, mac[:20]...)
711
+	return ret
712
+}
713
+
714
+func (c *Conversation) processEncryptedSig(encryptedSig, theirMAC []byte, keys *akeKeys, xFirst bool) error {
715
+	mac := hmac.New(sha256.New, keys.m2[:])
716
+	mac.Write(appendData(nil, encryptedSig))
717
+	myMAC := mac.Sum(nil)[:20]
718
+
719
+	if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 {
720
+		return errors.New("bad signature MAC in encrypted signature")
721
+	}
722
+
723
+	aesCipher, err := aes.NewCipher(keys.c[:])
724
+	if err != nil {
725
+		panic(err.Error())
726
+	}
727
+	var iv [aes.BlockSize]byte
728
+	ctr := cipher.NewCTR(aesCipher, iv[:])
729
+	ctr.XORKeyStream(encryptedSig, encryptedSig)
730
+
731
+	sig := encryptedSig
732
+	sig, ok1 := c.TheirPublicKey.Parse(sig)
733
+	keyId, sig, ok2 := getU32(sig)
734
+	if !ok1 || !ok2 {
735
+		return errors.New("otr: corrupt encrypted signature")
736
+	}
737
+
738
+	var verifyData []byte
739
+	if xFirst {
740
+		verifyData = appendMPI(verifyData, c.gx)
741
+		verifyData = appendMPI(verifyData, c.gy)
742
+	} else {
743
+		verifyData = appendMPI(verifyData, c.gy)
744
+		verifyData = appendMPI(verifyData, c.gx)
745
+	}
746
+	verifyData = c.TheirPublicKey.Serialize(verifyData)
747
+	verifyData = appendU32(verifyData, keyId)
748
+
749
+	mac = hmac.New(sha256.New, keys.m1[:])
750
+	mac.Write(verifyData)
751
+	mb := mac.Sum(nil)
752
+
753
+	sig, ok1 = c.TheirPublicKey.Verify(mb, sig)
754
+	if !ok1 {
755
+		return errors.New("bad signature in encrypted signature")
756
+	}
757
+	if len(sig) > 0 {
758
+		return errors.New("corrupt encrypted signature")
759
+	}
760
+
761
+	c.theirKeyId = keyId
762
+	zero(c.theirLastCtr[:])
763
+	return nil
764
+}
765
+
766
+func (c *Conversation) processRevealSig(in []byte) error {
767
+	r, in, ok1 := getData(in)
768
+	encryptedSig, in, ok2 := getData(in)
769
+	theirMAC := in
770
+	if !ok1 || !ok2 || len(theirMAC) != 20 {
771
+		return errors.New("otr: corrupt reveal signature message")
772
+	}
773
+
774
+	aesCipher, err := aes.NewCipher(r)
775
+	if err != nil {
776
+		return errors.New("otr: cannot create AES cipher from reveal signature message: " + err.Error())
777
+	}
778
+	var iv [aes.BlockSize]byte
779
+	ctr := cipher.NewCTR(aesCipher, iv[:])
780
+	ctr.XORKeyStream(c.gxBytes, c.gxBytes)
781
+	h := sha256.New()
782
+	h.Write(c.gxBytes)
783
+	digest := h.Sum(nil)
784
+	if len(digest) != len(c.digest) || subtle.ConstantTimeCompare(digest, c.digest[:]) == 0 {
785
+		return errors.New("otr: bad commit MAC in reveal signature message")
786
+	}
787
+	var rest []byte
788
+	c.gx, rest, ok1 = getMPI(c.gxBytes)
789
+	if !ok1 || len(rest) > 0 {
790
+		return errors.New("otr: gx corrupt after decryption")
791
+	}
792
+	if c.gx.Cmp(g) < 0 || c.gx.Cmp(pMinus2) > 0 {
793
+		return errors.New("otr: DH value out of range")
794
+	}
795
+	s := new(big.Int).Exp(c.gx, c.y, p)
796
+	c.calcAKEKeys(s)
797
+
798
+	if err := c.processEncryptedSig(encryptedSig, theirMAC, &c.revealKeys, true /* gx comes first */); err != nil {
799
+		return errors.New("otr: in reveal signature message: " + err.Error())
800
+	}
801
+
802
+	c.theirCurrentDHPub = c.gx
803
+	c.theirLastDHPub = nil
804
+
805
+	return nil
806
+}
807
+
808
+func (c *Conversation) generateSig() []byte {
809
+	c.myKeyId++
810
+
811
+	encryptedSig, mac := c.generateEncryptedSignature(&c.sigKeys, false /* gy comes first */)
812
+
813
+	c.myCurrentDHPub = c.gy
814
+	c.myCurrentDHPriv = c.y
815
+	c.rotateDHKeys()
816
+	incCounter(&c.myCounter)
817
+
818
+	var ret []byte
819
+	ret = appendU16(ret, 2)
820
+	ret = append(ret, msgTypeSig)
821
+	ret = append(ret, encryptedSig...)
822
+	ret = append(ret, mac[:macPrefixBytes]...)
823
+	return ret
824
+}
825
+
826
+func (c *Conversation) processSig(in []byte) error {
827
+	encryptedSig, in, ok1 := getData(in)
828
+	theirMAC := in
829
+	if !ok1 || len(theirMAC) != macPrefixBytes {
830
+		return errors.New("otr: corrupt signature message")
831
+	}
832
+
833
+	if err := c.processEncryptedSig(encryptedSig, theirMAC, &c.sigKeys, false /* gy comes first */); err != nil {
834
+		return errors.New("otr: in signature message: " + err.Error())
835
+	}
836
+
837
+	c.theirCurrentDHPub = c.gy
838
+	c.theirLastDHPub = nil
839
+
840
+	return nil
841
+}
842
+
843
+func (c *Conversation) rotateDHKeys() {
844
+	// evict slots using our retired key id
845
+	for i := range c.keySlots {
846
+		slot := &c.keySlots[i]
847
+		if slot.used && slot.myKeyId == c.myKeyId-1 {
848
+			slot.used = false
849
+			c.oldMACs = append(c.oldMACs, slot.recvMACKey...)
850
+		}
851
+	}
852
+
853
+	c.myLastDHPriv = c.myCurrentDHPriv
854
+	c.myLastDHPub = c.myCurrentDHPub
855
+
856
+	var xBytes [dhPrivateBytes]byte
857
+	c.myCurrentDHPriv = c.randMPI(xBytes[:])
858
+	c.myCurrentDHPub = new(big.Int).Exp(g, c.myCurrentDHPriv, p)
859
+	c.myKeyId++
860
+}
861
+
862
+func (c *Conversation) processData(in []byte) (out []byte, tlvs []tlv, err error) {
863
+	origIn := in
864
+	flags, in, ok1 := getU8(in)
865
+	theirKeyId, in, ok2 := getU32(in)
866
+	myKeyId, in, ok3 := getU32(in)
867
+	y, in, ok4 := getMPI(in)
868
+	counter, in, ok5 := getNBytes(in, 8)
869
+	encrypted, in, ok6 := getData(in)
870
+	macedData := origIn[:len(origIn)-len(in)]
871
+	theirMAC, in, ok7 := getNBytes(in, macPrefixBytes)
872
+	_, in, ok8 := getData(in)
873
+	if !ok1 || !ok2 || !ok3 || !ok4 || !ok5 || !ok6 || !ok7 || !ok8 || len(in) > 0 {
874
+		err = errors.New("otr: corrupt data message")
875
+		return
876
+	}
877
+
878
+	ignoreErrors := flags&1 != 0
879
+
880
+	slot, err := c.calcDataKeys(myKeyId, theirKeyId)
881
+	if err != nil {
882
+		if ignoreErrors {
883
+			err = nil
884
+		}
885
+		return
886
+	}
887
+
888
+	mac := hmac.New(sha1.New, slot.recvMACKey)
889
+	mac.Write([]byte{0, 2, 3})
890
+	mac.Write(macedData)
891
+	myMAC := mac.Sum(nil)
892
+	if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 {
893
+		if !ignoreErrors {
894
+			err = errors.New("otr: bad MAC on data message")
895
+		}
896
+		return
897
+	}
898
+
899
+	if bytes.Compare(counter, slot.theirLastCtr[:]) <= 0 {
900
+		err = errors.New("otr: counter regressed")
901
+		return
902
+	}
903
+	copy(slot.theirLastCtr[:], counter)
904
+
905
+	var iv [aes.BlockSize]byte
906
+	copy(iv[:], counter)
907
+	aesCipher, err := aes.NewCipher(slot.recvAESKey)
908
+	if err != nil {
909
+		panic(err.Error())
910
+	}
911
+	ctr := cipher.NewCTR(aesCipher, iv[:])
912
+	ctr.XORKeyStream(encrypted, encrypted)
913
+	decrypted := encrypted
914
+
915
+	if myKeyId == c.myKeyId {
916
+		c.rotateDHKeys()
917
+	}
918
+	if theirKeyId == c.theirKeyId {
919
+		// evict slots using their retired key id
920
+		for i := range c.keySlots {
921
+			slot := &c.keySlots[i]
922
+			if slot.used && slot.theirKeyId == theirKeyId-1 {
923
+				slot.used = false
924
+				c.oldMACs = append(c.oldMACs, slot.recvMACKey...)
925
+			}
926
+		}
927
+
928
+		c.theirLastDHPub = c.theirCurrentDHPub
929
+		c.theirKeyId++
930
+		c.theirCurrentDHPub = y
931
+	}
932
+
933
+	if nulPos := bytes.IndexByte(decrypted, 0); nulPos >= 0 {
934
+		out = decrypted[:nulPos]
935
+		tlvData := decrypted[nulPos+1:]
936
+		for len(tlvData) > 0 {
937
+			var t tlv
938
+			var ok1, ok2, ok3 bool
939
+
940
+			t.typ, tlvData, ok1 = getU16(tlvData)
941
+			t.length, tlvData, ok2 = getU16(tlvData)
942
+			t.data, tlvData, ok3 = getNBytes(tlvData, int(t.length))
943
+			if !ok1 || !ok2 || !ok3 {
944
+				err = errors.New("otr: corrupt tlv data")
945
+				return
946
+			}
947
+			tlvs = append(tlvs, t)
948
+		}
949
+	} else {
950
+		out = decrypted
951
+	}
952
+
953
+	return
954
+}
955
+
956
+func (c *Conversation) generateData(msg []byte, extra *tlv) []byte {
957
+	slot, err := c.calcDataKeys(c.myKeyId-1, c.theirKeyId)
958
+	if err != nil {
959
+		panic("otr: failed to generate sending keys: " + err.Error())
960
+	}
961
+
962
+	var plaintext []byte
963
+	plaintext = append(plaintext, msg...)
964
+	plaintext = append(plaintext, 0)
965
+
966
+	padding := paddingGranularity - ((len(plaintext) + 4) % paddingGranularity)
967
+	plaintext = appendU16(plaintext, tlvTypePadding)
968
+	plaintext = appendU16(plaintext, uint16(padding))
969
+	for i := 0; i < padding; i++ {
970
+		plaintext = append(plaintext, 0)
971
+	}
972
+
973
+	if extra != nil {
974
+		plaintext = appendU16(plaintext, extra.typ)
975
+		plaintext = appendU16(plaintext, uint16(len(extra.data)))
976
+		plaintext = append(plaintext, extra.data...)
977
+	}
978
+
979
+	encrypted := make([]byte, len(plaintext))
980
+
981
+	var iv [aes.BlockSize]byte
982
+	copy(iv[:], c.myCounter[:])
983
+	aesCipher, err := aes.NewCipher(slot.sendAESKey)
984
+	if err != nil {
985
+		panic(err.Error())
986
+	}
987
+	ctr := cipher.NewCTR(aesCipher, iv[:])
988
+	ctr.XORKeyStream(encrypted, plaintext)
989
+
990
+	var ret []byte
991
+	ret = appendU16(ret, 2)
992
+	ret = append(ret, msgTypeData)
993
+	ret = append(ret, 0 /* flags */)
994
+	ret = appendU32(ret, c.myKeyId-1)
995
+	ret = appendU32(ret, c.theirKeyId)
996
+	ret = appendMPI(ret, c.myCurrentDHPub)
997
+	ret = append(ret, c.myCounter[:]...)
998
+	ret = appendData(ret, encrypted)
999
+
1000
+	mac := hmac.New(sha1.New, slot.sendMACKey)
1001
+	mac.Write(ret)
1002
+	ret = append(ret, mac.Sum(nil)[:macPrefixBytes]...)
1003
+	ret = appendData(ret, c.oldMACs)
1004
+	c.oldMACs = nil
1005
+	incCounter(&c.myCounter)
1006
+
1007
+	return ret
1008
+}
1009
+
1010
+func incCounter(counter *[8]byte) {
1011
+	for i := 7; i >= 0; i-- {
1012
+		counter[i]++
1013
+		if counter[i] > 0 {
1014
+			break
1015
+		}
1016
+	}
1017
+}
1018
+
1019
+// calcDataKeys computes the keys used to encrypt a data message given the key
1020
+// IDs.
1021
+func (c *Conversation) calcDataKeys(myKeyId, theirKeyId uint32) (slot *keySlot, err error) {
1022
+	// Check for a cache hit.
1023
+	for i := range c.keySlots {
1024
+		slot = &c.keySlots[i]
1025
+		if slot.used && slot.theirKeyId == theirKeyId && slot.myKeyId == myKeyId {
1026
+			return
1027
+		}
1028
+	}
1029
+
1030
+	// Find an empty slot to write into.
1031
+	slot = nil
1032
+	for i := range c.keySlots {
1033
+		if !c.keySlots[i].used {
1034
+			slot = &c.keySlots[i]
1035
+			break
1036
+		}
1037
+	}
1038
+	if slot == nil {
1039
+		return nil, errors.New("otr: internal error: no more key slots")
1040
+	}
1041
+
1042
+	var myPriv, myPub, theirPub *big.Int
1043
+
1044
+	if myKeyId == c.myKeyId {
1045
+		myPriv = c.myCurrentDHPriv
1046
+		myPub = c.myCurrentDHPub
1047
+	} else if myKeyId == c.myKeyId-1 {
1048
+		myPriv = c.myLastDHPriv
1049
+		myPub = c.myLastDHPub
1050
+	} else {
1051
+		err = errors.New("otr: peer requested keyid " + strconv.FormatUint(uint64(myKeyId), 10) + " when I'm on " + strconv.FormatUint(uint64(c.myKeyId), 10))
1052
+		return
1053
+	}
1054
+
1055
+	if theirKeyId == c.theirKeyId {
1056
+		theirPub = c.theirCurrentDHPub
1057
+	} else if theirKeyId == c.theirKeyId-1 && c.theirLastDHPub != nil {
1058
+		theirPub = c.theirLastDHPub
1059
+	} else {
1060
+		err = errors.New("otr: peer requested keyid " + strconv.FormatUint(uint64(myKeyId), 10) + " when they're on " + strconv.FormatUint(uint64(c.myKeyId), 10))
1061
+		return
1062
+	}
1063
+
1064
+	var sendPrefixByte, recvPrefixByte [1]byte
1065
+
1066
+	if myPub.Cmp(theirPub) > 0 {
1067
+		// we're the high end
1068
+		sendPrefixByte[0], recvPrefixByte[0] = 1, 2
1069
+	} else {
1070
+		// we're the low end
1071
+		sendPrefixByte[0], recvPrefixByte[0] = 2, 1
1072
+	}
1073
+
1074
+	s := new(big.Int).Exp(theirPub, myPriv, p)
1075
+	sBytes := appendMPI(nil, s)
1076
+
1077
+	h := sha1.New()
1078
+	h.Write(sendPrefixByte[:])
1079
+	h.Write(sBytes)
1080
+	slot.sendAESKey = h.Sum(slot.sendAESKey[:0])[:16]
1081
+
1082
+	h.Reset()
1083
+	h.Write(slot.sendAESKey)
1084
+	slot.sendMACKey = h.Sum(slot.sendMACKey[:0])
1085
+
1086
+	h.Reset()
1087
+	h.Write(recvPrefixByte[:])
1088
+	h.Write(sBytes)
1089
+	slot.recvAESKey = h.Sum(slot.recvAESKey[:0])[:16]
1090
+
1091
+	h.Reset()
1092
+	h.Write(slot.recvAESKey)
1093
+	slot.recvMACKey = h.Sum(slot.recvMACKey[:0])
1094
+
1095
+	slot.theirKeyId = theirKeyId
1096
+	slot.myKeyId = myKeyId
1097
+	slot.used = true
1098
+
1099
+	zero(slot.theirLastCtr[:])
1100
+	return
1101
+}
1102
+
1103
+func (c *Conversation) calcAKEKeys(s *big.Int) {
1104
+	mpi := appendMPI(nil, s)
1105
+	h := sha256.New()
1106
+
1107
+	var cBytes [32]byte
1108
+	hashWithPrefix(c.SSID[:], 0, mpi, h)
1109
+
1110
+	hashWithPrefix(cBytes[:], 1, mpi, h)
1111
+	copy(c.revealKeys.c[:], cBytes[:16])
1112
+	copy(c.sigKeys.c[:], cBytes[16:])
1113
+
1114
+	hashWithPrefix(c.revealKeys.m1[:], 2, mpi, h)
1115
+	hashWithPrefix(c.revealKeys.m2[:], 3, mpi, h)
1116
+	hashWithPrefix(c.sigKeys.m1[:], 4, mpi, h)
1117
+	hashWithPrefix(c.sigKeys.m2[:], 5, mpi, h)
1118
+}
1119
+
1120
+func hashWithPrefix(out []byte, prefix byte, in []byte, h hash.Hash) {
1121
+	h.Reset()
1122
+	var p [1]byte
1123
+	p[0] = prefix
1124
+	h.Write(p[:])
1125
+	h.Write(in)
1126
+	if len(out) == h.Size() {
1127
+		h.Sum(out[:0])
1128
+	} else {
1129
+		digest := h.Sum(nil)
1130
+		copy(out, digest)
1131
+	}
1132
+}
1133
+
1134
+func (c *Conversation) encode(msg []byte) [][]byte {
1135
+	b64 := make([]byte, base64.StdEncoding.EncodedLen(len(msg))+len(msgPrefix)+1)
1136
+	base64.StdEncoding.Encode(b64[len(msgPrefix):], msg)
1137
+	copy(b64, msgPrefix)
1138
+	b64[len(b64)-1] = '.'
1139
+
1140
+	if c.FragmentSize < minFragmentSize || len(b64) <= c.FragmentSize {
1141
+		// We can encode this in a single fragment.
1142
+		return [][]byte{b64}
1143
+	}
1144
+
1145
+	// We have to fragment this message.
1146
+	var ret [][]byte
1147
+	bytesPerFragment := c.FragmentSize - minFragmentSize
1148
+	numFragments := (len(b64) + bytesPerFragment) / bytesPerFragment
1149
+
1150
+	for i := 0; i < numFragments; i++ {
1151
+		frag := []byte("?OTR," + strconv.Itoa(i+1) + "," + strconv.Itoa(numFragments) + ",")
1152
+		todo := bytesPerFragment
1153
+		if todo > len(b64) {
1154
+			todo = len(b64)
1155
+		}
1156
+		frag = append(frag, b64[:todo]...)
1157
+		b64 = b64[todo:]
1158
+		frag = append(frag, ',')
1159
+		ret = append(ret, frag)
1160
+	}
1161
+
1162
+	return ret
1163
+}
1164
+
1165
+func (c *Conversation) reset() {
1166
+	c.myKeyId = 0
1167
+
1168
+	for i := range c.keySlots {
1169
+		c.keySlots[i].used = false
1170
+	}
1171
+}
1172
+
1173
+type PublicKey struct {
1174
+	dsa.PublicKey
1175
+}
1176
+
1177
+func (pk *PublicKey) Parse(in []byte) ([]byte, bool) {
1178
+	var ok bool
1179
+	var pubKeyType uint16
1180
+
1181
+	if pubKeyType, in, ok = getU16(in); !ok || pubKeyType != 0 {
1182
+		return nil, false
1183
+	}
1184
+	if pk.P, in, ok = getMPI(in); !ok {
1185
+		return nil, false
1186
+	}
1187
+	if pk.Q, in, ok = getMPI(in); !ok {
1188
+		return nil, false
1189
+	}
1190
+	if pk.G, in, ok = getMPI(in); !ok {
1191
+		return nil, false
1192
+	}
1193
+	if pk.Y, in, ok = getMPI(in); !ok {
1194
+		return nil, false
1195
+	}
1196
+
1197
+	return in, true
1198
+}
1199
+
1200
+func (pk *PublicKey) Serialize(in []byte) []byte {
1201
+	in = appendU16(in, 0)
1202
+	in = appendMPI(in, pk.P)
1203
+	in = appendMPI(in, pk.Q)
1204
+	in = appendMPI(in, pk.G)
1205
+	in = appendMPI(in, pk.Y)
1206
+	return in
1207
+}
1208
+
1209
+// Fingerprint returns the 20-byte, binary fingerprint of the PublicKey.
1210
+func (pk *PublicKey) Fingerprint() []byte {
1211
+	b := pk.Serialize(nil)
1212
+	h := sha1.New()
1213
+	h.Write(b[2:])
1214
+	return h.Sum(nil)
1215
+}
1216
+
1217
+func (pk *PublicKey) Verify(hashed, sig []byte) ([]byte, bool) {
1218
+	if len(sig) != 2*dsaSubgroupBytes {
1219
+		return nil, false
1220
+	}
1221
+	r := new(big.Int).SetBytes(sig[:dsaSubgroupBytes])
1222
+	s := new(big.Int).SetBytes(sig[dsaSubgroupBytes:])
1223
+	ok := dsa.Verify(&pk.PublicKey, hashed, r, s)
1224
+	return sig[dsaSubgroupBytes*2:], ok
1225
+}
1226
+
1227
+type PrivateKey struct {
1228
+	PublicKey
1229
+	dsa.PrivateKey
1230
+}
1231
+
1232
+func (priv *PrivateKey) Sign(rand io.Reader, hashed []byte) []byte {
1233
+	r, s, err := dsa.Sign(rand, &priv.PrivateKey, hashed)
1234
+	if err != nil {
1235
+		panic(err.Error())
1236
+	}
1237
+	rBytes := r.Bytes()
1238
+	sBytes := s.Bytes()
1239
+	if len(rBytes) > dsaSubgroupBytes || len(sBytes) > dsaSubgroupBytes {
1240
+		panic("DSA signature too large")
1241
+	}
1242
+
1243
+	out := make([]byte, 2*dsaSubgroupBytes)
1244
+	copy(out[dsaSubgroupBytes-len(rBytes):], rBytes)
1245
+	copy(out[len(out)-len(sBytes):], sBytes)
1246
+	return out
1247
+}
1248
+
1249
+func (priv *PrivateKey) Serialize(in []byte) []byte {
1250
+	in = priv.PublicKey.Serialize(in)
1251
+	in = appendMPI(in, priv.PrivateKey.X)
1252
+	return in
1253
+}
1254
+
1255
+func (priv *PrivateKey) Parse(in []byte) ([]byte, bool) {
1256
+	in, ok := priv.PublicKey.Parse(in)
1257
+	if !ok {
1258
+		return in, ok
1259
+	}
1260
+	priv.PrivateKey.PublicKey = priv.PublicKey.PublicKey
1261
+	priv.PrivateKey.X, in, ok = getMPI(in)
1262
+	return in, ok
1263
+}
1264
+
1265
+func (priv *PrivateKey) Generate(rand io.Reader) {
1266
+	if err := dsa.GenerateParameters(&priv.PrivateKey.PublicKey.Parameters, rand, dsa.L1024N160); err != nil {
1267
+		panic(err.Error())
1268
+	}
1269
+	if err := dsa.GenerateKey(&priv.PrivateKey, rand); err != nil {
1270
+		panic(err.Error())
1271
+	}
1272
+	priv.PublicKey.PublicKey = priv.PrivateKey.PublicKey
1273
+}
1274
+
1275
+func notHex(r rune) bool {
1276
+	if r >= '0' && r <= '9' ||
1277
+		r >= 'a' && r <= 'f' ||
1278
+		r >= 'A' && r <= 'F' {
1279
+		return false
1280
+	}
1281
+
1282
+	return true
1283
+}
1284
+
1285
+// Import parses the contents of a libotr private key file.
1286
+func (priv *PrivateKey) Import(in []byte) bool {
1287
+	mpiStart := []byte(" #")
1288
+
1289
+	mpis := make([]*big.Int, 5)
1290
+
1291
+	for i := 0; i < len(mpis); i++ {
1292
+		start := bytes.Index(in, mpiStart)
1293
+		if start == -1 {
1294
+			return false
1295
+		}
1296
+		in = in[start+len(mpiStart):]
1297
+		end := bytes.IndexFunc(in, notHex)
1298
+		if end == -1 {
1299
+			return false
1300
+		}
1301
+		hexBytes := in[:end]
1302
+		in = in[end:]
1303
+
1304
+		if len(hexBytes)&1 != 0 {
1305
+			return false
1306
+		}
1307
+
1308
+		mpiBytes := make([]byte, len(hexBytes)/2)
1309
+		if _, err := hex.Decode(mpiBytes, hexBytes); err != nil {
1310
+			return false
1311
+		}
1312
+
1313
+		mpis[i] = new(big.Int).SetBytes(mpiBytes)
1314
+	}
1315
+
1316
+	for _, mpi := range mpis {
1317
+		if mpi.Sign() <= 0 {
1318
+			return false
1319
+		}
1320
+	}
1321
+
1322
+	priv.PrivateKey.P = mpis[0]
1323
+	priv.PrivateKey.Q = mpis[1]
1324
+	priv.PrivateKey.G = mpis[2]
1325
+	priv.PrivateKey.Y = mpis[3]
1326
+	priv.PrivateKey.X = mpis[4]
1327
+	priv.PublicKey.PublicKey = priv.PrivateKey.PublicKey
1328
+
1329
+	a := new(big.Int).Exp(priv.PrivateKey.G, priv.PrivateKey.X, priv.PrivateKey.P)
1330
+	return a.Cmp(priv.PrivateKey.Y) == 0
1331
+}
1332
+
1333
+func getU8(in []byte) (uint8, []byte, bool) {
1334
+	if len(in) < 1 {
1335
+		return 0, in, false
1336
+	}
1337
+	return in[0], in[1:], true
1338
+}
1339
+
1340
+func getU16(in []byte) (uint16, []byte, bool) {
1341
+	if len(in) < 2 {
1342
+		return 0, in, false
1343
+	}
1344
+	r := uint16(in[0])<<8 | uint16(in[1])
1345
+	return r, in[2:], true
1346
+}
1347
+
1348
+func getU32(in []byte) (uint32, []byte, bool) {
1349
+	if len(in) < 4 {
1350
+		return 0, in, false
1351
+	}
1352
+	r := uint32(in[0])<<24 | uint32(in[1])<<16 | uint32(in[2])<<8 | uint32(in[3])
1353
+	return r, in[4:], true
1354
+}
1355
+
1356
+func getMPI(in []byte) (*big.Int, []byte, bool) {
1357
+	l, in, ok := getU32(in)
1358
+	if !ok || uint32(len(in)) < l {
1359
+		return nil, in, false
1360
+	}
1361
+	r := new(big.Int).SetBytes(in[:l])
1362
+	return r, in[l:], true
1363
+}
1364
+
1365
+func getData(in []byte) ([]byte, []byte, bool) {
1366
+	l, in, ok := getU32(in)
1367
+	if !ok || uint32(len(in)) < l {
1368
+		return nil, in, false
1369
+	}
1370
+	return in[:l], in[l:], true
1371
+}
1372
+
1373
+func getNBytes(in []byte, n int) ([]byte, []byte, bool) {
1374
+	if len(in) < n {
1375
+		return nil, in, false
1376
+	}
1377
+	return in[:n], in[n:], true
1378
+}
1379
+
1380
+func appendU16(out []byte, v uint16) []byte {
1381
+	out = append(out, byte(v>>8), byte(v))
1382
+	return out
1383
+}
1384
+
1385
+func appendU32(out []byte, v uint32) []byte {
1386
+	out = append(out, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
1387
+	return out
1388
+}
1389
+
1390
+func appendData(out, v []byte) []byte {
1391
+	out = appendU32(out, uint32(len(v)))
1392
+	out = append(out, v...)
1393
+	return out
1394
+}
1395
+
1396
+func appendMPI(out []byte, v *big.Int) []byte {
1397
+	vBytes := v.Bytes()
1398
+	out = appendU32(out, uint32(len(vBytes)))
1399
+	out = append(out, vBytes...)
1400
+	return out
1401
+}
1402
+
1403
+func appendMPIs(out []byte, mpis ...*big.Int) []byte {
1404
+	for _, mpi := range mpis {
1405
+		out = appendMPI(out, mpi)
1406
+	}
1407
+	return out
1408
+}
1409
+
1410
+func zero(b []byte) {
1411
+	for i := range b {
1412
+		b[i] = 0
1413
+	}
1414
+}
0 1415
new file mode 100644
... ...
@@ -0,0 +1,572 @@
0
+// Copyright 2012 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// This file implements the Socialist Millionaires Protocol as described in
5
+// http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html. The protocol
6
+// specification is required in order to understand this code and, where
7
+// possible, the variable names in the code match up with the spec.
8
+
9
+package otr
10
+
11
+import (
12
+	"bytes"
13
+	"crypto/sha256"
14
+	"errors"
15
+	"hash"
16
+	"math/big"
17
+)
18
+
19
+type smpFailure string
20
+
21
+func (s smpFailure) Error() string {
22
+	return string(s)
23
+}
24
+
25
+var smpFailureError = smpFailure("otr: SMP protocol failed")
26
+var smpSecretMissingError = smpFailure("otr: mutual secret needed")
27
+
28
+const smpVersion = 1
29
+
30
+const (
31
+	smpState1 = iota
32
+	smpState2
33
+	smpState3
34
+	smpState4
35
+)
36
+
37
+type smpState struct {
38
+	state                  int
39
+	a2, a3, b2, b3, pb, qb *big.Int
40
+	g2a, g3a               *big.Int
41
+	g2, g3                 *big.Int
42
+	g3b, papb, qaqb, ra    *big.Int
43
+	saved                  *tlv
44
+	secret                 *big.Int
45
+	question               string
46
+}
47
+
48
+func (c *Conversation) startSMP(question string) (tlvs []tlv) {
49
+	if c.smp.state != smpState1 {
50
+		tlvs = append(tlvs, c.generateSMPAbort())
51
+	}
52
+	tlvs = append(tlvs, c.generateSMP1(question))
53
+	c.smp.question = ""
54
+	c.smp.state = smpState2
55
+	return
56
+}
57
+
58
+func (c *Conversation) resetSMP() {
59
+	c.smp.state = smpState1
60
+	c.smp.secret = nil
61
+	c.smp.question = ""
62
+}
63
+
64
+func (c *Conversation) processSMP(in tlv) (out tlv, complete bool, err error) {
65
+	data := in.data
66
+
67
+	switch in.typ {
68
+	case tlvTypeSMPAbort:
69
+		if c.smp.state != smpState1 {
70
+			err = smpFailureError
71
+		}
72
+		c.resetSMP()
73
+		return
74
+	case tlvTypeSMP1WithQuestion:
75
+		// We preprocess this into a SMP1 message.
76
+		nulPos := bytes.IndexByte(data, 0)
77
+		if nulPos == -1 {
78
+			err = errors.New("otr: SMP message with question didn't contain a NUL byte")
79
+			return
80
+		}
81
+		c.smp.question = string(data[:nulPos])
82
+		data = data[nulPos+1:]
83
+	}
84
+
85
+	numMPIs, data, ok := getU32(data)
86
+	if !ok || numMPIs > 20 {
87
+		err = errors.New("otr: corrupt SMP message")
88
+		return
89
+	}
90
+
91
+	mpis := make([]*big.Int, numMPIs)
92
+	for i := range mpis {
93
+		var ok bool
94
+		mpis[i], data, ok = getMPI(data)
95
+		if !ok {
96
+			err = errors.New("otr: corrupt SMP message")
97
+			return
98
+		}
99
+	}
100
+
101
+	switch in.typ {
102
+	case tlvTypeSMP1, tlvTypeSMP1WithQuestion:
103
+		if c.smp.state != smpState1 {
104
+			c.resetSMP()
105
+			out = c.generateSMPAbort()
106
+			return
107
+		}
108
+		if c.smp.secret == nil {
109
+			err = smpSecretMissingError
110
+			return
111
+		}
112
+		if err = c.processSMP1(mpis); err != nil {
113
+			return
114
+		}
115
+		c.smp.state = smpState3
116
+		out = c.generateSMP2()
117
+	case tlvTypeSMP2:
118
+		if c.smp.state != smpState2 {
119
+			c.resetSMP()
120
+			out = c.generateSMPAbort()
121
+			return
122
+		}
123
+		if out, err = c.processSMP2(mpis); err != nil {
124
+			out = c.generateSMPAbort()
125
+			return
126
+		}
127
+		c.smp.state = smpState4
128
+	case tlvTypeSMP3:
129
+		if c.smp.state != smpState3 {
130
+			c.resetSMP()
131
+			out = c.generateSMPAbort()
132
+			return
133
+		}
134
+		if out, err = c.processSMP3(mpis); err != nil {
135
+			return
136
+		}
137
+		c.smp.state = smpState1
138
+		c.smp.secret = nil
139
+		complete = true
140
+	case tlvTypeSMP4:
141
+		if c.smp.state != smpState4 {
142
+			c.resetSMP()
143
+			out = c.generateSMPAbort()
144
+			return
145
+		}
146
+		if err = c.processSMP4(mpis); err != nil {
147
+			out = c.generateSMPAbort()
148
+			return
149
+		}
150
+		c.smp.state = smpState1
151
+		c.smp.secret = nil
152
+		complete = true
153
+	default:
154
+		panic("unknown SMP message")
155
+	}
156
+
157
+	return
158
+}
159
+
160
+func (c *Conversation) calcSMPSecret(mutualSecret []byte, weStarted bool) {
161
+	h := sha256.New()
162
+	h.Write([]byte{smpVersion})
163
+	if weStarted {
164
+		h.Write(c.PrivateKey.PublicKey.Fingerprint())
165
+		h.Write(c.TheirPublicKey.Fingerprint())
166
+	} else {
167
+		h.Write(c.TheirPublicKey.Fingerprint())
168
+		h.Write(c.PrivateKey.PublicKey.Fingerprint())
169
+	}
170
+	h.Write(c.SSID[:])
171
+	h.Write(mutualSecret)
172
+	c.smp.secret = new(big.Int).SetBytes(h.Sum(nil))
173
+}
174
+
175
+func (c *Conversation) generateSMP1(question string) tlv {
176
+	var randBuf [16]byte
177
+	c.smp.a2 = c.randMPI(randBuf[:])
178
+	c.smp.a3 = c.randMPI(randBuf[:])
179
+	g2a := new(big.Int).Exp(g, c.smp.a2, p)
180
+	g3a := new(big.Int).Exp(g, c.smp.a3, p)
181
+	h := sha256.New()
182
+
183
+	r2 := c.randMPI(randBuf[:])
184
+	r := new(big.Int).Exp(g, r2, p)
185
+	c2 := new(big.Int).SetBytes(hashMPIs(h, 1, r))
186
+	d2 := new(big.Int).Mul(c.smp.a2, c2)
187
+	d2.Sub(r2, d2)
188
+	d2.Mod(d2, q)
189
+	if d2.Sign() < 0 {
190
+		d2.Add(d2, q)
191
+	}
192
+
193
+	r3 := c.randMPI(randBuf[:])
194
+	r.Exp(g, r3, p)
195
+	c3 := new(big.Int).SetBytes(hashMPIs(h, 2, r))
196
+	d3 := new(big.Int).Mul(c.smp.a3, c3)
197
+	d3.Sub(r3, d3)
198
+	d3.Mod(d3, q)
199
+	if d3.Sign() < 0 {
200
+		d3.Add(d3, q)
201
+	}
202
+
203
+	var ret tlv
204
+	if len(question) > 0 {
205
+		ret.typ = tlvTypeSMP1WithQuestion
206
+		ret.data = append(ret.data, question...)
207
+		ret.data = append(ret.data, 0)
208
+	} else {
209
+		ret.typ = tlvTypeSMP1
210
+	}
211
+	ret.data = appendU32(ret.data, 6)
212
+	ret.data = appendMPIs(ret.data, g2a, c2, d2, g3a, c3, d3)
213
+	return ret
214
+}
215
+
216
+func (c *Conversation) processSMP1(mpis []*big.Int) error {
217
+	if len(mpis) != 6 {
218
+		return errors.New("otr: incorrect number of arguments in SMP1 message")
219
+	}
220
+	g2a := mpis[0]
221
+	c2 := mpis[1]
222
+	d2 := mpis[2]
223
+	g3a := mpis[3]
224
+	c3 := mpis[4]
225
+	d3 := mpis[5]
226
+	h := sha256.New()
227
+
228
+	r := new(big.Int).Exp(g, d2, p)
229
+	s := new(big.Int).Exp(g2a, c2, p)
230
+	r.Mul(r, s)
231
+	r.Mod(r, p)
232
+	t := new(big.Int).SetBytes(hashMPIs(h, 1, r))
233
+	if c2.Cmp(t) != 0 {
234
+		return errors.New("otr: ZKP c2 incorrect in SMP1 message")
235
+	}
236
+	r.Exp(g, d3, p)
237
+	s.Exp(g3a, c3, p)
238
+	r.Mul(r, s)
239
+	r.Mod(r, p)
240
+	t.SetBytes(hashMPIs(h, 2, r))
241
+	if c3.Cmp(t) != 0 {
242
+		return errors.New("otr: ZKP c3 incorrect in SMP1 message")
243
+	}
244
+
245
+	c.smp.g2a = g2a
246
+	c.smp.g3a = g3a
247
+	return nil
248
+}
249
+
250
+func (c *Conversation) generateSMP2() tlv {
251
+	var randBuf [16]byte
252
+	b2 := c.randMPI(randBuf[:])
253
+	c.smp.b3 = c.randMPI(randBuf[:])
254
+	r2 := c.randMPI(randBuf[:])
255
+	r3 := c.randMPI(randBuf[:])
256
+	r4 := c.randMPI(randBuf[:])
257
+	r5 := c.randMPI(randBuf[:])
258
+	r6 := c.randMPI(randBuf[:])
259
+
260
+	g2b := new(big.Int).Exp(g, b2, p)
261
+	g3b := new(big.Int).Exp(g, c.smp.b3, p)
262
+
263
+	r := new(big.Int).Exp(g, r2, p)
264
+	h := sha256.New()
265
+	c2 := new(big.Int).SetBytes(hashMPIs(h, 3, r))
266
+	d2 := new(big.Int).Mul(b2, c2)
267
+	d2.Sub(r2, d2)
268
+	d2.Mod(d2, q)
269
+	if d2.Sign() < 0 {
270
+		d2.Add(d2, q)
271
+	}
272
+
273
+	r.Exp(g, r3, p)
274
+	c3 := new(big.Int).SetBytes(hashMPIs(h, 4, r))
275
+	d3 := new(big.Int).Mul(c.smp.b3, c3)
276
+	d3.Sub(r3, d3)
277
+	d3.Mod(d3, q)
278
+	if d3.Sign() < 0 {
279
+		d3.Add(d3, q)
280
+	}
281
+
282
+	c.smp.g2 = new(big.Int).Exp(c.smp.g2a, b2, p)
283
+	c.smp.g3 = new(big.Int).Exp(c.smp.g3a, c.smp.b3, p)
284
+	c.smp.pb = new(big.Int).Exp(c.smp.g3, r4, p)
285
+	c.smp.qb = new(big.Int).Exp(g, r4, p)
286
+	r.Exp(c.smp.g2, c.smp.secret, p)
287
+	c.smp.qb.Mul(c.smp.qb, r)
288
+	c.smp.qb.Mod(c.smp.qb, p)
289
+
290
+	s := new(big.Int)
291
+	s.Exp(c.smp.g2, r6, p)
292
+	r.Exp(g, r5, p)
293
+	s.Mul(r, s)
294
+	s.Mod(s, p)
295
+	r.Exp(c.smp.g3, r5, p)
296
+	cp := new(big.Int).SetBytes(hashMPIs(h, 5, r, s))
297
+
298
+	// D5 = r5 - r4 cP mod q and D6 = r6 - y cP mod q
299
+
300
+	s.Mul(r4, cp)
301
+	r.Sub(r5, s)
302
+	d5 := new(big.Int).Mod(r, q)
303
+	if d5.Sign() < 0 {
304
+		d5.Add(d5, q)
305
+	}
306
+
307
+	s.Mul(c.smp.secret, cp)
308
+	r.Sub(r6, s)
309
+	d6 := new(big.Int).Mod(r, q)
310
+	if d6.Sign() < 0 {
311
+		d6.Add(d6, q)
312
+	}
313
+
314
+	var ret tlv
315
+	ret.typ = tlvTypeSMP2
316
+	ret.data = appendU32(ret.data, 11)
317
+	ret.data = appendMPIs(ret.data, g2b, c2, d2, g3b, c3, d3, c.smp.pb, c.smp.qb, cp, d5, d6)
318
+	return ret
319
+}
320
+
321
+func (c *Conversation) processSMP2(mpis []*big.Int) (out tlv, err error) {
322
+	if len(mpis) != 11 {
323
+		err = errors.New("otr: incorrect number of arguments in SMP2 message")
324
+		return
325
+	}
326
+	g2b := mpis[0]
327
+	c2 := mpis[1]
328
+	d2 := mpis[2]
329
+	g3b := mpis[3]
330
+	c3 := mpis[4]
331
+	d3 := mpis[5]
332
+	pb := mpis[6]
333
+	qb := mpis[7]
334
+	cp := mpis[8]
335
+	d5 := mpis[9]
336
+	d6 := mpis[10]
337
+	h := sha256.New()
338
+
339
+	r := new(big.Int).Exp(g, d2, p)
340
+	s := new(big.Int).Exp(g2b, c2, p)
341
+	r.Mul(r, s)
342
+	r.Mod(r, p)
343
+	s.SetBytes(hashMPIs(h, 3, r))
344
+	if c2.Cmp(s) != 0 {
345
+		err = errors.New("otr: ZKP c2 failed in SMP2 message")
346
+		return
347
+	}
348
+
349
+	r.Exp(g, d3, p)
350
+	s.Exp(g3b, c3, p)
351
+	r.Mul(r, s)
352
+	r.Mod(r, p)
353
+	s.SetBytes(hashMPIs(h, 4, r))
354
+	if c3.Cmp(s) != 0 {
355
+		err = errors.New("otr: ZKP c3 failed in SMP2 message")
356
+		return
357
+	}
358
+
359
+	c.smp.g2 = new(big.Int).Exp(g2b, c.smp.a2, p)
360
+	c.smp.g3 = new(big.Int).Exp(g3b, c.smp.a3, p)
361
+
362
+	r.Exp(g, d5, p)
363
+	s.Exp(c.smp.g2, d6, p)
364
+	r.Mul(r, s)
365
+	s.Exp(qb, cp, p)
366
+	r.Mul(r, s)
367
+	r.Mod(r, p)
368
+
369
+	s.Exp(c.smp.g3, d5, p)
370
+	t := new(big.Int).Exp(pb, cp, p)
371
+	s.Mul(s, t)
372
+	s.Mod(s, p)
373
+	t.SetBytes(hashMPIs(h, 5, s, r))
374
+	if cp.Cmp(t) != 0 {
375
+		err = errors.New("otr: ZKP cP failed in SMP2 message")
376
+		return
377
+	}
378
+
379
+	var randBuf [16]byte
380
+	r4 := c.randMPI(randBuf[:])
381
+	r5 := c.randMPI(randBuf[:])
382
+	r6 := c.randMPI(randBuf[:])
383
+	r7 := c.randMPI(randBuf[:])
384
+
385
+	pa := new(big.Int).Exp(c.smp.g3, r4, p)
386
+	r.Exp(c.smp.g2, c.smp.secret, p)
387
+	qa := new(big.Int).Exp(g, r4, p)
388
+	qa.Mul(qa, r)
389
+	qa.Mod(qa, p)
390
+
391
+	r.Exp(g, r5, p)
392
+	s.Exp(c.smp.g2, r6, p)
393
+	r.Mul(r, s)
394
+	r.Mod(r, p)
395
+
396
+	s.Exp(c.smp.g3, r5, p)
397
+	cp.SetBytes(hashMPIs(h, 6, s, r))
398
+
399
+	r.Mul(r4, cp)
400
+	d5 = new(big.Int).Sub(r5, r)
401
+	d5.Mod(d5, q)
402
+	if d5.Sign() < 0 {
403
+		d5.Add(d5, q)
404
+	}
405
+
406
+	r.Mul(c.smp.secret, cp)
407
+	d6 = new(big.Int).Sub(r6, r)
408
+	d6.Mod(d6, q)
409
+	if d6.Sign() < 0 {
410
+		d6.Add(d6, q)
411
+	}
412
+
413
+	r.ModInverse(qb, p)
414
+	qaqb := new(big.Int).Mul(qa, r)
415
+	qaqb.Mod(qaqb, p)
416
+
417
+	ra := new(big.Int).Exp(qaqb, c.smp.a3, p)
418
+	r.Exp(qaqb, r7, p)
419
+	s.Exp(g, r7, p)
420
+	cr := new(big.Int).SetBytes(hashMPIs(h, 7, s, r))
421
+
422
+	r.Mul(c.smp.a3, cr)
423
+	d7 := new(big.Int).Sub(r7, r)
424
+	d7.Mod(d7, q)
425
+	if d7.Sign() < 0 {
426
+		d7.Add(d7, q)
427
+	}
428
+
429
+	c.smp.g3b = g3b
430
+	c.smp.qaqb = qaqb
431
+
432
+	r.ModInverse(pb, p)
433
+	c.smp.papb = new(big.Int).Mul(pa, r)
434
+	c.smp.papb.Mod(c.smp.papb, p)
435
+	c.smp.ra = ra
436
+
437
+	out.typ = tlvTypeSMP3
438
+	out.data = appendU32(out.data, 8)
439
+	out.data = appendMPIs(out.data, pa, qa, cp, d5, d6, ra, cr, d7)
440
+	return
441
+}
442
+
443
+func (c *Conversation) processSMP3(mpis []*big.Int) (out tlv, err error) {
444
+	if len(mpis) != 8 {
445
+		err = errors.New("otr: incorrect number of arguments in SMP3 message")
446
+		return
447
+	}
448
+	pa := mpis[0]
449
+	qa := mpis[1]
450
+	cp := mpis[2]
451
+	d5 := mpis[3]
452
+	d6 := mpis[4]
453
+	ra := mpis[5]
454
+	cr := mpis[6]
455
+	d7 := mpis[7]
456
+	h := sha256.New()
457
+
458
+	r := new(big.Int).Exp(g, d5, p)
459
+	s := new(big.Int).Exp(c.smp.g2, d6, p)
460
+	r.Mul(r, s)
461
+	s.Exp(qa, cp, p)
462
+	r.Mul(r, s)
463
+	r.Mod(r, p)
464
+
465
+	s.Exp(c.smp.g3, d5, p)
466
+	t := new(big.Int).Exp(pa, cp, p)
467
+	s.Mul(s, t)
468
+	s.Mod(s, p)
469
+	t.SetBytes(hashMPIs(h, 6, s, r))
470
+	if t.Cmp(cp) != 0 {
471
+		err = errors.New("otr: ZKP cP failed in SMP3 message")
472
+		return
473
+	}
474
+
475
+	r.ModInverse(c.smp.qb, p)
476
+	qaqb := new(big.Int).Mul(qa, r)
477
+	qaqb.Mod(qaqb, p)
478
+
479
+	r.Exp(qaqb, d7, p)
480
+	s.Exp(ra, cr, p)
481
+	r.Mul(r, s)
482
+	r.Mod(r, p)
483
+
484
+	s.Exp(g, d7, p)
485
+	t.Exp(c.smp.g3a, cr, p)
486
+	s.Mul(s, t)
487
+	s.Mod(s, p)
488
+	t.SetBytes(hashMPIs(h, 7, s, r))
489
+	if t.Cmp(cr) != 0 {
490
+		err = errors.New("otr: ZKP cR failed in SMP3 message")
491
+		return
492
+	}
493
+
494
+	var randBuf [16]byte
495
+	r7 := c.randMPI(randBuf[:])
496
+	rb := new(big.Int).Exp(qaqb, c.smp.b3, p)
497
+
498
+	r.Exp(qaqb, r7, p)
499
+	s.Exp(g, r7, p)
500
+	cr = new(big.Int).SetBytes(hashMPIs(h, 8, s, r))
501
+
502
+	r.Mul(c.smp.b3, cr)
503
+	d7 = new(big.Int).Sub(r7, r)
504
+	d7.Mod(d7, q)
505
+	if d7.Sign() < 0 {
506
+		d7.Add(d7, q)
507
+	}
508
+
509
+	out.typ = tlvTypeSMP4
510
+	out.data = appendU32(out.data, 3)
511
+	out.data = appendMPIs(out.data, rb, cr, d7)
512
+
513
+	r.ModInverse(c.smp.pb, p)
514
+	r.Mul(pa, r)
515
+	r.Mod(r, p)
516
+	s.Exp(ra, c.smp.b3, p)
517
+	if r.Cmp(s) != 0 {
518
+		err = smpFailureError
519
+	}
520
+
521
+	return
522
+}
523
+
524
+func (c *Conversation) processSMP4(mpis []*big.Int) error {
525
+	if len(mpis) != 3 {
526
+		return errors.New("otr: incorrect number of arguments in SMP4 message")
527
+	}
528
+	rb := mpis[0]
529
+	cr := mpis[1]
530
+	d7 := mpis[2]
531
+	h := sha256.New()
532
+
533
+	r := new(big.Int).Exp(c.smp.qaqb, d7, p)
534
+	s := new(big.Int).Exp(rb, cr, p)
535
+	r.Mul(r, s)
536
+	r.Mod(r, p)
537
+
538
+	s.Exp(g, d7, p)
539
+	t := new(big.Int).Exp(c.smp.g3b, cr, p)
540
+	s.Mul(s, t)
541
+	s.Mod(s, p)
542
+	t.SetBytes(hashMPIs(h, 8, s, r))
543
+	if t.Cmp(cr) != 0 {
544
+		return errors.New("otr: ZKP cR failed in SMP4 message")
545
+	}
546
+
547
+	r.Exp(rb, c.smp.a3, p)
548
+	if r.Cmp(c.smp.papb) != 0 {
549
+		return smpFailureError
550
+	}
551
+
552
+	return nil
553
+}
554
+
555
+func (c *Conversation) generateSMPAbort() tlv {
556
+	return tlv{typ: tlvTypeSMPAbort}
557
+}
558
+
559
+func hashMPIs(h hash.Hash, magic byte, mpis ...*big.Int) []byte {
560
+	if h != nil {
561
+		h.Reset()
562
+	} else {
563
+		h = sha256.New()
564
+	}
565
+
566
+	h.Write([]byte{magic})
567
+	for _, mpi := range mpis {
568
+		h.Write(appendMPI(nil, mpi))
569
+	}
570
+	return h.Sum(nil)
571
+}
0 572
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// Copyright 2012 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// Package test contains integration tests for the
5
+// golang.org/x/crypto/ssh package.
6
+package test // import "golang.org/x/crypto/ssh/test"
0 7
new file mode 100644
... ...
@@ -0,0 +1,173 @@
0
+// Copyright 2017 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// sshd_test_pw.c
5
+// Wrapper to inject test password data for sshd PAM authentication
6
+//
7
+// This wrapper implements custom versions of getpwnam, getpwnam_r,
8
+// getspnam and getspnam_r. These functions first call their real
9
+// libc versions, then check if the requested user matches test user
10
+// specified in env variable TEST_USER and if so replace the password
11
+// with crypted() value of TEST_PASSWD env variable.
12
+//
13
+// Compile:
14
+// gcc -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
15
+//
16
+// Compile with debug:
17
+// gcc -DVERBOSE -Wall -shared -o sshd_test_pw.so -fPIC sshd_test_pw.c
18
+//
19
+// Run sshd:
20
+// LD_PRELOAD="sshd_test_pw.so" TEST_USER="..." TEST_PASSWD="..." sshd ...
21
+
22
+// +build ignore
23
+
24
+#define _GNU_SOURCE
25
+#include <string.h>
26
+#include <pwd.h>
27
+#include <shadow.h>
28
+#include <dlfcn.h>
29
+#include <stdlib.h>
30
+#include <unistd.h>
31
+#include <stdio.h>
32
+
33
+#ifdef VERBOSE
34
+#define DEBUG(X...) fprintf(stderr, X)
35
+#else
36
+#define DEBUG(X...) while (0) { }
37
+#endif
38
+
39
+/* crypt() password */
40
+static char *
41
+pwhash(char *passwd) {
42
+  return strdup(crypt(passwd, "$6$"));
43
+}
44
+
45
+/* Pointers to real functions in libc */
46
+static struct passwd * (*real_getpwnam)(const char *) = NULL;
47
+static int (*real_getpwnam_r)(const char *, struct passwd *, char *, size_t, struct passwd **) = NULL;
48
+static struct spwd * (*real_getspnam)(const char *) = NULL;
49
+static int (*real_getspnam_r)(const char *, struct spwd *, char *, size_t, struct spwd **) = NULL;
50
+
51
+/* Cached test user and test password */
52
+static char *test_user = NULL;
53
+static char *test_passwd_hash = NULL;
54
+
55
+static void
56
+init(void) {
57
+  /* Fetch real libc function pointers */
58
+  real_getpwnam = dlsym(RTLD_NEXT, "getpwnam");
59
+  real_getpwnam_r = dlsym(RTLD_NEXT, "getpwnam_r");
60
+  real_getspnam = dlsym(RTLD_NEXT, "getspnam");
61
+  real_getspnam_r = dlsym(RTLD_NEXT, "getspnam_r");
62
+  
63
+  /* abort if env variables are not defined */
64
+  if (getenv("TEST_USER") == NULL || getenv("TEST_PASSWD") == NULL) {
65
+    fprintf(stderr, "env variables TEST_USER and TEST_PASSWD are missing\n");
66
+    abort();
67
+  }
68
+
69
+  /* Fetch test user and test password from env */
70
+  test_user = strdup(getenv("TEST_USER"));
71
+  test_passwd_hash = pwhash(getenv("TEST_PASSWD"));
72
+
73
+  DEBUG("sshd_test_pw init():\n");
74
+  DEBUG("\treal_getpwnam: %p\n", real_getpwnam);
75
+  DEBUG("\treal_getpwnam_r: %p\n", real_getpwnam_r);
76
+  DEBUG("\treal_getspnam: %p\n", real_getspnam);
77
+  DEBUG("\treal_getspnam_r: %p\n", real_getspnam_r);
78
+  DEBUG("\tTEST_USER: '%s'\n", test_user);
79
+  DEBUG("\tTEST_PASSWD: '%s'\n", getenv("TEST_PASSWD"));
80
+  DEBUG("\tTEST_PASSWD_HASH: '%s'\n", test_passwd_hash);
81
+}
82
+
83
+static int
84
+is_test_user(const char *name) {
85
+  if (test_user != NULL && strcmp(test_user, name) == 0)
86
+    return 1;
87
+  return 0;
88
+}
89
+
90
+/* getpwnam */
91
+
92
+struct passwd *
93
+getpwnam(const char *name) {
94
+  struct passwd *pw;
95
+
96
+  DEBUG("sshd_test_pw getpwnam(%s)\n", name);
97
+  
98
+  if (real_getpwnam == NULL)
99
+    init();
100
+  if ((pw = real_getpwnam(name)) == NULL)
101
+    return NULL;
102
+
103
+  if (is_test_user(name))
104
+    pw->pw_passwd = strdup(test_passwd_hash);
105
+      
106
+  return pw;
107
+}
108
+
109
+/* getpwnam_r */
110
+
111
+int
112
+getpwnam_r(const char *name,
113
+	   struct passwd *pwd,
114
+	   char *buf,
115
+	   size_t buflen,
116
+	   struct passwd **result) {
117
+  int r;
118
+
119
+  DEBUG("sshd_test_pw getpwnam_r(%s)\n", name);
120
+  
121
+  if (real_getpwnam_r == NULL)
122
+    init();
123
+  if ((r = real_getpwnam_r(name, pwd, buf, buflen, result)) != 0 || *result == NULL)
124
+    return r;
125
+
126
+  if (is_test_user(name))
127
+    pwd->pw_passwd = strdup(test_passwd_hash);
128
+  
129
+  return 0;
130
+}
131
+
132
+/* getspnam */
133
+
134
+struct spwd *
135
+getspnam(const char *name) {
136
+  struct spwd *sp;
137
+
138
+  DEBUG("sshd_test_pw getspnam(%s)\n", name);
139
+  
140
+  if (real_getspnam == NULL)
141
+    init();
142
+  if ((sp = real_getspnam(name)) == NULL)
143
+    return NULL;
144
+
145
+  if (is_test_user(name))
146
+    sp->sp_pwdp = strdup(test_passwd_hash);
147
+  
148
+  return sp;
149
+}
150
+
151
+/* getspnam_r */
152
+
153
+int
154
+getspnam_r(const char *name,
155
+	   struct spwd *spbuf,
156
+	   char *buf,
157
+	   size_t buflen,
158
+	   struct spwd **spbufp) {
159
+  int r;
160
+
161
+  DEBUG("sshd_test_pw getspnam_r(%s)\n", name);
162
+  
163
+  if (real_getspnam_r == NULL)
164
+    init();
165
+  if ((r = real_getspnam_r(name, spbuf, buf, buflen, spbufp)) != 0)
166
+    return r;
167
+
168
+  if (is_test_user(name))
169
+    spbuf->sp_pwdp = strdup(test_passwd_hash);
170
+  
171
+  return r;
172
+}
0 173
new file mode 100644
... ...
@@ -0,0 +1,38 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// Package cpu implements processor feature detection for
5
+// various CPU architectures.
6
+package cpu
7
+
8
+// CacheLinePad is used to pad structs to avoid false sharing.
9
+type CacheLinePad struct{ _ [cacheLineSize]byte }
10
+
11
+// X86 contains the supported CPU features of the
12
+// current X86/AMD64 platform. If the current platform
13
+// is not X86/AMD64 then all feature flags are false.
14
+//
15
+// X86 is padded to avoid false sharing. Further the HasAVX
16
+// and HasAVX2 are only set if the OS supports XMM and YMM
17
+// registers in addition to the CPUID feature bit being set.
18
+var X86 struct {
19
+	_            CacheLinePad
20
+	HasAES       bool // AES hardware implementation (AES NI)
21
+	HasADX       bool // Multi-precision add-carry instruction extensions
22
+	HasAVX       bool // Advanced vector extension
23
+	HasAVX2      bool // Advanced vector extension 2
24
+	HasBMI1      bool // Bit manipulation instruction set 1
25
+	HasBMI2      bool // Bit manipulation instruction set 2
26
+	HasERMS      bool // Enhanced REP for MOVSB and STOSB
27
+	HasFMA       bool // Fused-multiply-add instructions
28
+	HasOSXSAVE   bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
29
+	HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM
30
+	HasPOPCNT    bool // Hamming weight instruction POPCNT.
31
+	HasSSE2      bool // Streaming SIMD extension 2 (always available on amd64)
32
+	HasSSE3      bool // Streaming SIMD extension 3
33
+	HasSSSE3     bool // Supplemental streaming SIMD extension 3
34
+	HasSSE41     bool // Streaming SIMD extension 4 and 4.1
35
+	HasSSE42     bool // Streaming SIMD extension 4 and 4.2
36
+	_            CacheLinePad
37
+}
0 38
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+package cpu
5
+
6
+const cacheLineSize = 32
0 7
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+package cpu
5
+
6
+const cacheLineSize = 64
0 7
new file mode 100644
... ...
@@ -0,0 +1,16 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build 386 amd64 amd64p32
5
+// +build !gccgo
6
+
7
+package cpu
8
+
9
+// cpuid is implemented in cpu_x86.s for gc compiler
10
+// and in cpu_gccgo.c for gccgo.
11
+func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
12
+
13
+// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler
14
+// and in cpu_gccgo.c for gccgo.
15
+func xgetbv() (eax, edx uint32)
0 16
new file mode 100644
... ...
@@ -0,0 +1,43 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build 386 amd64 amd64p32
5
+// +build gccgo
6
+
7
+#include <cpuid.h>
8
+#include <stdint.h>
9
+
10
+// Need to wrap __get_cpuid_count because it's declared as static.
11
+int
12
+gccgoGetCpuidCount(uint32_t leaf, uint32_t subleaf,
13
+                   uint32_t *eax, uint32_t *ebx,
14
+                   uint32_t *ecx, uint32_t *edx)
15
+{
16
+	return __get_cpuid_count(leaf, subleaf, eax, ebx, ecx, edx);
17
+}
18
+
19
+// xgetbv reads the contents of an XCR (Extended Control Register)
20
+// specified in the ECX register into registers EDX:EAX.
21
+// Currently, the only supported value for XCR is 0.
22
+//
23
+// TODO: Replace with a better alternative:
24
+//
25
+//     #include <xsaveintrin.h>
26
+//
27
+//     #pragma GCC target("xsave")
28
+//
29
+//     void gccgoXgetbv(uint32_t *eax, uint32_t *edx) {
30
+//       unsigned long long x = _xgetbv(0);
31
+//       *eax = x & 0xffffffff;
32
+//       *edx = (x >> 32) & 0xffffffff;
33
+//     }
34
+//
35
+// Note that _xgetbv is defined starting with GCC 8.
36
+void
37
+gccgoXgetbv(uint32_t *eax, uint32_t *edx)
38
+{
39
+	__asm("  xorl %%ecx, %%ecx\n"
40
+	      "  xgetbv"
41
+	    : "=a"(*eax), "=d"(*edx));
42
+}
0 43
new file mode 100644
... ...
@@ -0,0 +1,26 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build 386 amd64 amd64p32
5
+// +build gccgo
6
+
7
+package cpu
8
+
9
+//extern gccgoGetCpuidCount
10
+func gccgoGetCpuidCount(eaxArg, ecxArg uint32, eax, ebx, ecx, edx *uint32)
11
+
12
+func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) {
13
+	var a, b, c, d uint32
14
+	gccgoGetCpuidCount(eaxArg, ecxArg, &a, &b, &c, &d)
15
+	return a, b, c, d
16
+}
17
+
18
+//extern gccgoXgetbv
19
+func gccgoXgetbv(eax, edx *uint32)
20
+
21
+func xgetbv() (eax, edx uint32) {
22
+	var a, d uint32
23
+	gccgoXgetbv(&a, &d)
24
+	return a, d
25
+}
0 26
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build mips64 mips64le
5
+
6
+package cpu
7
+
8
+const cacheLineSize = 32
0 9
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build mips mipsle
5
+
6
+package cpu
7
+
8
+const cacheLineSize = 32
0 9
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build ppc64 ppc64le
5
+
6
+package cpu
7
+
8
+const cacheLineSize = 128
0 9
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+package cpu
5
+
6
+const cacheLineSize = 256
0 7
new file mode 100644
... ...
@@ -0,0 +1,55 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build 386 amd64 amd64p32
5
+
6
+package cpu
7
+
8
+const cacheLineSize = 64
9
+
10
+func init() {
11
+	maxID, _, _, _ := cpuid(0, 0)
12
+
13
+	if maxID < 1 {
14
+		return
15
+	}
16
+
17
+	_, _, ecx1, edx1 := cpuid(1, 0)
18
+	X86.HasSSE2 = isSet(26, edx1)
19
+
20
+	X86.HasSSE3 = isSet(0, ecx1)
21
+	X86.HasPCLMULQDQ = isSet(1, ecx1)
22
+	X86.HasSSSE3 = isSet(9, ecx1)
23
+	X86.HasFMA = isSet(12, ecx1)
24
+	X86.HasSSE41 = isSet(19, ecx1)
25
+	X86.HasSSE42 = isSet(20, ecx1)
26
+	X86.HasPOPCNT = isSet(23, ecx1)
27
+	X86.HasAES = isSet(25, ecx1)
28
+	X86.HasOSXSAVE = isSet(27, ecx1)
29
+
30
+	osSupportsAVX := false
31
+	// For XGETBV, OSXSAVE bit is required and sufficient.
32
+	if X86.HasOSXSAVE {
33
+		eax, _ := xgetbv()
34
+		// Check if XMM and YMM registers have OS support.
35
+		osSupportsAVX = isSet(1, eax) && isSet(2, eax)
36
+	}
37
+
38
+	X86.HasAVX = isSet(28, ecx1) && osSupportsAVX
39
+
40
+	if maxID < 7 {
41
+		return
42
+	}
43
+
44
+	_, ebx7, _, _ := cpuid(7, 0)
45
+	X86.HasBMI1 = isSet(3, ebx7)
46
+	X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX
47
+	X86.HasBMI2 = isSet(8, ebx7)
48
+	X86.HasERMS = isSet(9, ebx7)
49
+	X86.HasADX = isSet(19, ebx7)
50
+}
51
+
52
+func isSet(bitpos uint, value uint32) bool {
53
+	return value&(1<<bitpos) != 0
54
+}
0 55
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+// Copyright 2018 The Go Authors. All rights reserved.
1
+// Use of this source code is governed by a BSD-style
2
+// license that can be found in the LICENSE file.
3
+
4
+// +build 386 amd64 amd64p32
5
+// +build !gccgo
6
+
7
+#include "textflag.h"
8
+
9
+// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
10
+TEXT ·cpuid(SB), NOSPLIT, $0-24
11
+	MOVL eaxArg+0(FP), AX
12
+	MOVL ecxArg+4(FP), CX
13
+	CPUID
14
+	MOVL AX, eax+8(FP)
15
+	MOVL BX, ebx+12(FP)
16
+	MOVL CX, ecx+16(FP)
17
+	MOVL DX, edx+20(FP)
18
+	RET
19
+
20
+// func xgetbv() (eax, edx uint32)
21
+TEXT ·xgetbv(SB),NOSPLIT,$0-8
22
+	MOVL $0, CX
23
+	XGETBV
24
+	MOVL AX, eax+0(FP)
25
+	MOVL DX, edx+4(FP)
26
+	RET