Browse code

vendor: update deps for fssession

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>

Tonis Tiigi authored on 2017/05/04 13:49:12
Showing 58 changed files
... ...
@@ -102,6 +102,8 @@ google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
102 102
 # containerd
103 103
 github.com/containerd/containerd 3addd840653146c90a254301d6c3a663c7fd6429
104 104
 github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4
105
+github.com/stevvooe/continuity cd7a8e21e2b6f84799f5dd4b65faf49c8d3ee02d
106
+github.com/tonistiigi/fsutil 0ac4c11b053b9c5c7c47558f81f96c7100ce50fb
105 107
 
106 108
 # cluster
107 109
 github.com/docker/swarmkit a4bf0135f63fb60f0e76ae81579cde87f580db6e
108 110
new file mode 100644
... ...
@@ -0,0 +1,202 @@
0
+                                 Apache License
1
+                           Version 2.0, January 2004
2
+                        http://www.apache.org/licenses/
3
+
4
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
5
+
6
+   1. Definitions.
7
+
8
+      "License" shall mean the terms and conditions for use, reproduction,
9
+      and distribution as defined by Sections 1 through 9 of this document.
10
+
11
+      "Licensor" shall mean the copyright owner or entity authorized by
12
+      the copyright owner that is granting the License.
13
+
14
+      "Legal Entity" shall mean the union of the acting entity and all
15
+      other entities that control, are controlled by, or are under common
16
+      control with that entity. For the purposes of this definition,
17
+      "control" means (i) the power, direct or indirect, to cause the
18
+      direction or management of such entity, whether by contract or
19
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
20
+      outstanding shares, or (iii) beneficial ownership of such entity.
21
+
22
+      "You" (or "Your") shall mean an individual or Legal Entity
23
+      exercising permissions granted by this License.
24
+
25
+      "Source" form shall mean the preferred form for making modifications,
26
+      including but not limited to software source code, documentation
27
+      source, and configuration files.
28
+
29
+      "Object" form shall mean any form resulting from mechanical
30
+      transformation or translation of a Source form, including but
31
+      not limited to compiled object code, generated documentation,
32
+      and conversions to other media types.
33
+
34
+      "Work" shall mean the work of authorship, whether in Source or
35
+      Object form, made available under the License, as indicated by a
36
+      copyright notice that is included in or attached to the work
37
+      (an example is provided in the Appendix below).
38
+
39
+      "Derivative Works" shall mean any work, whether in Source or Object
40
+      form, that is based on (or derived from) the Work and for which the
41
+      editorial revisions, annotations, elaborations, or other modifications
42
+      represent, as a whole, an original work of authorship. For the purposes
43
+      of this License, Derivative Works shall not include works that remain
44
+      separable from, or merely link (or bind by name) to the interfaces of,
45
+      the Work and Derivative Works thereof.
46
+
47
+      "Contribution" shall mean any work of authorship, including
48
+      the original version of the Work and any modifications or additions
49
+      to that Work or Derivative Works thereof, that is intentionally
50
+      submitted to Licensor for inclusion in the Work by the copyright owner
51
+      or by an individual or Legal Entity authorized to submit on behalf of
52
+      the copyright owner. For the purposes of this definition, "submitted"
53
+      means any form of electronic, verbal, or written communication sent
54
+      to the Licensor or its representatives, including but not limited to
55
+      communication on electronic mailing lists, source code control systems,
56
+      and issue tracking systems that are managed by, or on behalf of, the
57
+      Licensor for the purpose of discussing and improving the Work, but
58
+      excluding communication that is conspicuously marked or otherwise
59
+      designated in writing by the copyright owner as "Not a Contribution."
60
+
61
+      "Contributor" shall mean Licensor and any individual or Legal Entity
62
+      on behalf of whom a Contribution has been received by Licensor and
63
+      subsequently incorporated within the Work.
64
+
65
+   2. Grant of Copyright License. Subject to the terms and conditions of
66
+      this License, each Contributor hereby grants to You a perpetual,
67
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
68
+      copyright license to reproduce, prepare Derivative Works of,
69
+      publicly display, publicly perform, sublicense, and distribute the
70
+      Work and such Derivative Works in Source or Object form.
71
+
72
+   3. Grant of Patent License. Subject to the terms and conditions of
73
+      this License, each Contributor hereby grants to You a perpetual,
74
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
75
+      (except as stated in this section) patent license to make, have made,
76
+      use, offer to sell, sell, import, and otherwise transfer the Work,
77
+      where such license applies only to those patent claims licensable
78
+      by such Contributor that are necessarily infringed by their
79
+      Contribution(s) alone or by combination of their Contribution(s)
80
+      with the Work to which such Contribution(s) was submitted. If You
81
+      institute patent litigation against any entity (including a
82
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
83
+      or a Contribution incorporated within the Work constitutes direct
84
+      or contributory patent infringement, then any patent licenses
85
+      granted to You under this License for that Work shall terminate
86
+      as of the date such litigation is filed.
87
+
88
+   4. Redistribution. You may reproduce and distribute copies of the
89
+      Work or Derivative Works thereof in any medium, with or without
90
+      modifications, and in Source or Object form, provided that You
91
+      meet the following conditions:
92
+
93
+      (a) You must give any other recipients of the Work or
94
+          Derivative Works a copy of this License; and
95
+
96
+      (b) You must cause any modified files to carry prominent notices
97
+          stating that You changed the files; and
98
+
99
+      (c) You must retain, in the Source form of any Derivative Works
100
+          that You distribute, all copyright, patent, trademark, and
101
+          attribution notices from the Source form of the Work,
102
+          excluding those notices that do not pertain to any part of
103
+          the Derivative Works; and
104
+
105
+      (d) If the Work includes a "NOTICE" text file as part of its
106
+          distribution, then any Derivative Works that You distribute must
107
+          include a readable copy of the attribution notices contained
108
+          within such NOTICE file, excluding those notices that do not
109
+          pertain to any part of the Derivative Works, in at least one
110
+          of the following places: within a NOTICE text file distributed
111
+          as part of the Derivative Works; within the Source form or
112
+          documentation, if provided along with the Derivative Works; or,
113
+          within a display generated by the Derivative Works, if and
114
+          wherever such third-party notices normally appear. The contents
115
+          of the NOTICE file are for informational purposes only and
116
+          do not modify the License. You may add Your own attribution
117
+          notices within Derivative Works that You distribute, alongside
118
+          or as an addendum to the NOTICE text from the Work, provided
119
+          that such additional attribution notices cannot be construed
120
+          as modifying the License.
121
+
122
+      You may add Your own copyright statement to Your modifications and
123
+      may provide additional or different license terms and conditions
124
+      for use, reproduction, or distribution of Your modifications, or
125
+      for any such Derivative Works as a whole, provided Your use,
126
+      reproduction, and distribution of the Work otherwise complies with
127
+      the conditions stated in this License.
128
+
129
+   5. Submission of Contributions. Unless You explicitly state otherwise,
130
+      any Contribution intentionally submitted for inclusion in the Work
131
+      by You to the Licensor shall be under the terms and conditions of
132
+      this License, without any additional terms or conditions.
133
+      Notwithstanding the above, nothing herein shall supersede or modify
134
+      the terms of any separate license agreement you may have executed
135
+      with Licensor regarding such Contributions.
136
+
137
+   6. Trademarks. This License does not grant permission to use the trade
138
+      names, trademarks, service marks, or product names of the Licensor,
139
+      except as required for reasonable and customary use in describing the
140
+      origin of the Work and reproducing the content of the NOTICE file.
141
+
142
+   7. Disclaimer of Warranty. Unless required by applicable law or
143
+      agreed to in writing, Licensor provides the Work (and each
144
+      Contributor provides its Contributions) on an "AS IS" BASIS,
145
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
146
+      implied, including, without limitation, any warranties or conditions
147
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
148
+      PARTICULAR PURPOSE. You are solely responsible for determining the
149
+      appropriateness of using or redistributing the Work and assume any
150
+      risks associated with Your exercise of permissions under this License.
151
+
152
+   8. Limitation of Liability. In no event and under no legal theory,
153
+      whether in tort (including negligence), contract, or otherwise,
154
+      unless required by applicable law (such as deliberate and grossly
155
+      negligent acts) or agreed to in writing, shall any Contributor be
156
+      liable to You for damages, including any direct, indirect, special,
157
+      incidental, or consequential damages of any character arising as a
158
+      result of this License or out of the use or inability to use the
159
+      Work (including but not limited to damages for loss of goodwill,
160
+      work stoppage, computer failure or malfunction, or any and all
161
+      other commercial damages or losses), even if such Contributor
162
+      has been advised of the possibility of such damages.
163
+
164
+   9. Accepting Warranty or Additional Liability. While redistributing
165
+      the Work or Derivative Works thereof, You may choose to offer,
166
+      and charge a fee for, acceptance of support, warranty, indemnity,
167
+      or other liability obligations and/or rights consistent with this
168
+      License. However, in accepting such obligations, You may act only
169
+      on Your own behalf and on Your sole responsibility, not on behalf
170
+      of any other Contributor, and only if You agree to indemnify,
171
+      defend, and hold each Contributor harmless for any liability
172
+      incurred by, or claims asserted against, such Contributor by reason
173
+      of your accepting any such warranty or additional liability.
174
+
175
+   END OF TERMS AND CONDITIONS
176
+
177
+   APPENDIX: How to apply the Apache License to your work.
178
+
179
+      To apply the Apache License to your work, attach the following
180
+      boilerplate notice, with the fields enclosed by brackets "{}"
181
+      replaced with your own identifying information. (Don't include
182
+      the brackets!)  The text should be enclosed in the appropriate
183
+      comment syntax for the file format. We also recommend that a
184
+      file or class name and description of purpose be included on the
185
+      same "printed page" as the copyright notice for easier
186
+      identification within third-party archives.
187
+
188
+   Copyright {yyyy} {name of copyright owner}
189
+
190
+   Licensed under the Apache License, Version 2.0 (the "License");
191
+   you may not use this file except in compliance with the License.
192
+   You may obtain a copy of the License at
193
+
194
+       http://www.apache.org/licenses/LICENSE-2.0
195
+
196
+   Unless required by applicable law or agreed to in writing, software
197
+   distributed under the License is distributed on an "AS IS" BASIS,
198
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
199
+   See the License for the specific language governing permissions and
200
+   limitations under the License.
201
+
0 202
new file mode 100644
... ...
@@ -0,0 +1,19 @@
0
+# continuity
1
+
2
+[![GoDoc](https://godoc.org/github.com/containerd/continuity?status.svg)](https://godoc.org/github.com/containerd/continuity)
3
+[![Build Status](https://travis-ci.org/containerd/continuity.svg?branch=master)](https://travis-ci.org/containerd/continuity)
4
+
5
+A transport-agnostic, filesystem metadata manifest system
6
+
7
+This project is a staging area for experiments in providing transport agnostic
8
+metadata storage.
9
+
10
+Please see https://github.com/opencontainers/specs/issues/11 for more details.
11
+
12
+## Building Proto Package
13
+
14
+If you change the proto file you will need to rebuild the generated Go with `go generate`.
15
+
16
+```
17
+go generate ./proto
18
+```
0 19
new file mode 100644
... ...
@@ -0,0 +1,10 @@
0
+// Copyright 2014 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 !gccgo
5
+
6
+#include "textflag.h"
7
+
8
+TEXT ·use(SB),NOSPLIT,$0
9
+	RET
0 10
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+package sysx
1
+
2
+const (
3
+	// AtSymlinkNoFollow defined from AT_SYMLINK_NOFOLLOW in <sys/fcntl.h>
4
+	AtSymlinkNofollow = 0x20
5
+)
6
+
7
+const (
8
+
9
+	// SYS_FCHMODAT defined from golang.org/sys/unix
10
+	SYS_FCHMODAT = 467
11
+)
12
+
13
+// These functions will be generated by generate.sh
14
+//    $ GOOS=darwin GOARCH=386 ./generate.sh chmod
15
+//    $ GOOS=darwin GOARCH=amd64 ./generate.sh chmod
16
+
17
+//sys  Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
0 18
new file mode 100644
... ...
@@ -0,0 +1,25 @@
0
+// mksyscall.pl -l32 chmod_darwin.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
13
+	var _p0 *byte
14
+	_p0, err = syscall.BytePtrFromString(path)
15
+	if err != nil {
16
+		return
17
+	}
18
+	_, _, e1 := syscall.Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
19
+	use(unsafe.Pointer(_p0))
20
+	if e1 != 0 {
21
+		err = errnoErr(e1)
22
+	}
23
+	return
24
+}
0 25
new file mode 100644
... ...
@@ -0,0 +1,25 @@
0
+// mksyscall.pl chmod_darwin.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
13
+	var _p0 *byte
14
+	_p0, err = syscall.BytePtrFromString(path)
15
+	if err != nil {
16
+		return
17
+	}
18
+	_, _, e1 := syscall.Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
19
+	use(unsafe.Pointer(_p0))
20
+	if e1 != 0 {
21
+		err = errnoErr(e1)
22
+	}
23
+	return
24
+}
0 25
new file mode 100644
... ...
@@ -0,0 +1,17 @@
0
+package sysx
1
+
2
+const (
3
+	// AtSymlinkNoFollow defined from AT_SYMLINK_NOFOLLOW in <sys/fcntl.h>
4
+	AtSymlinkNofollow = 0x200
5
+)
6
+
7
+const (
8
+
9
+	// SYS_FCHMODAT defined from golang.org/sys/unix
10
+	SYS_FCHMODAT = 490
11
+)
12
+
13
+// These functions will be generated by generate.sh
14
+//    $ GOOS=freebsd GOARCH=amd64 ./generate.sh chmod
15
+
16
+//sys  Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
0 17
new file mode 100644
... ...
@@ -0,0 +1,25 @@
0
+// mksyscall.pl chmod_freebsd.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
13
+	var _p0 *byte
14
+	_p0, err = syscall.BytePtrFromString(path)
15
+	if err != nil {
16
+		return
17
+	}
18
+	_, _, e1 := syscall.Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
19
+	use(unsafe.Pointer(_p0))
20
+	if e1 != 0 {
21
+		err = errnoErr(e1)
22
+	}
23
+	return
24
+}
0 25
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+package sysx
1
+
2
+import "syscall"
3
+
4
+const (
5
+	// AtSymlinkNoFollow defined from AT_SYMLINK_NOFOLLOW in /usr/include/linux/fcntl.h
6
+	AtSymlinkNofollow = 0x100
7
+)
8
+
9
+func Fchmodat(dirfd int, path string, mode uint32, flags int) error {
10
+	return syscall.Fchmodat(dirfd, path, mode, flags)
11
+}
0 12
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+package sysx
1
+
2
+// These functions will be generated by generate.sh
3
+//    $ GOOS=linux GOARCH=386 ./generate.sh copy
4
+//    $ GOOS=linux GOARCH=amd64 ./generate.sh copy
5
+//    $ GOOS=linux GOARCH=arm ./generate.sh copy
6
+//    $ GOOS=linux GOARCH=arm64 ./generate.sh copy
7
+
8
+//sys CopyFileRange(fdin uintptr, offin *int64, fdout uintptr, offout *int64, len int, flags int) (n int, err error)
0 9
new file mode 100644
... ...
@@ -0,0 +1,20 @@
0
+// mksyscall.pl -l32 copy_linux.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func CopyFileRange(fdin uintptr, offin *int64, fdout uintptr, offout *int64, len int, flags int) (n int, err error) {
13
+	r0, _, e1 := syscall.Syscall6(SYS_COPY_FILE_RANGE, uintptr(fdin), uintptr(unsafe.Pointer(offin)), uintptr(fdout), uintptr(unsafe.Pointer(offout)), uintptr(len), uintptr(flags))
14
+	n = int(r0)
15
+	if e1 != 0 {
16
+		err = errnoErr(e1)
17
+	}
18
+	return
19
+}
0 20
new file mode 100644
... ...
@@ -0,0 +1,20 @@
0
+// mksyscall.pl copy_linux.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func CopyFileRange(fdin uintptr, offin *int64, fdout uintptr, offout *int64, len int, flags int) (n int, err error) {
13
+	r0, _, e1 := syscall.Syscall6(SYS_COPY_FILE_RANGE, uintptr(fdin), uintptr(unsafe.Pointer(offin)), uintptr(fdout), uintptr(unsafe.Pointer(offout)), uintptr(len), uintptr(flags))
14
+	n = int(r0)
15
+	if e1 != 0 {
16
+		err = errnoErr(e1)
17
+	}
18
+	return
19
+}
0 20
new file mode 100644
... ...
@@ -0,0 +1,20 @@
0
+// mksyscall.pl -l32 copy_linux.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func CopyFileRange(fdin uintptr, offin *int64, fdout uintptr, offout *int64, len int, flags int) (n int, err error) {
13
+	r0, _, e1 := syscall.Syscall6(SYS_COPY_FILE_RANGE, uintptr(fdin), uintptr(unsafe.Pointer(offin)), uintptr(fdout), uintptr(unsafe.Pointer(offout)), uintptr(len), uintptr(flags))
14
+	n = int(r0)
15
+	if e1 != 0 {
16
+		err = errnoErr(e1)
17
+	}
18
+	return
19
+}
0 20
new file mode 100644
... ...
@@ -0,0 +1,20 @@
0
+// mksyscall.pl copy_linux.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func CopyFileRange(fdin uintptr, offin *int64, fdout uintptr, offout *int64, len int, flags int) (n int, err error) {
13
+	r0, _, e1 := syscall.Syscall6(SYS_COPY_FILE_RANGE, uintptr(fdin), uintptr(unsafe.Pointer(offin)), uintptr(fdout), uintptr(unsafe.Pointer(offout)), uintptr(len), uintptr(flags))
14
+	n = int(r0)
15
+	if e1 != 0 {
16
+		err = errnoErr(e1)
17
+	}
18
+	return
19
+}
0 20
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+package sysx
1
+
2
+import (
3
+	"syscall"
4
+)
5
+
6
+const ENODATA = syscall.ENODATA
0 7
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+// +build darwin freebsd
1
+
2
+package sysx
3
+
4
+import (
5
+	"syscall"
6
+)
7
+
8
+const ENODATA = syscall.ENOATTR
0 9
new file mode 100644
... ...
@@ -0,0 +1,37 @@
0
+package sysx
1
+
2
+import (
3
+	"syscall"
4
+	"unsafe"
5
+)
6
+
7
+var _zero uintptr
8
+
9
+// use is a no-op, but the compiler cannot see that it is.
10
+// Calling use(p) ensures that p is kept live until that point.
11
+//go:noescape
12
+func use(p unsafe.Pointer)
13
+
14
+// Do the interface allocations only once for common
15
+// Errno values.
16
+var (
17
+	errEAGAIN error = syscall.EAGAIN
18
+	errEINVAL error = syscall.EINVAL
19
+	errENOENT error = syscall.ENOENT
20
+)
21
+
22
+// errnoErr returns common boxed Errno values, to prevent
23
+// allocations at runtime.
24
+func errnoErr(e syscall.Errno) error {
25
+	switch e {
26
+	case 0:
27
+		return nil
28
+	case syscall.EAGAIN:
29
+		return errEAGAIN
30
+	case syscall.EINVAL:
31
+		return errEINVAL
32
+	case syscall.ENOENT:
33
+		return errENOENT
34
+	}
35
+	return e
36
+}
0 37
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+package sysx
1
+
2
+const (
3
+	// SYS_COPYFILERANGE defined in Kernel 4.5+
4
+	// Number defined in /usr/include/asm/unistd_32.h
5
+	SYS_COPY_FILE_RANGE = 377
6
+)
0 7
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+package sysx
1
+
2
+const (
3
+	// SYS_COPYFILERANGE defined in Kernel 4.5+
4
+	// Number defined in /usr/include/asm/unistd_64.h
5
+	SYS_COPY_FILE_RANGE = 326
6
+)
0 7
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+package sysx
1
+
2
+const (
3
+	// SYS_COPY_FILE_RANGE defined in Kernel 4.5+
4
+	// Number defined in /usr/include/arm-linux-gnueabihf/asm/unistd.h
5
+	SYS_COPY_FILE_RANGE = 391
6
+)
0 7
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+package sysx
1
+
2
+const (
3
+	// SYS_COPY_FILE_RANGE defined in Kernel 4.5+
4
+	// Number defined in /usr/include/asm-generic/unistd.h
5
+	SYS_COPY_FILE_RANGE = 285
6
+)
0 7
new file mode 100644
... ...
@@ -0,0 +1,67 @@
0
+package sysx
1
+
2
+import (
3
+	"bytes"
4
+	"fmt"
5
+	"syscall"
6
+)
7
+
8
+const defaultXattrBufferSize = 5
9
+
10
+var ErrNotSupported = fmt.Errorf("not supported")
11
+
12
+type listxattrFunc func(path string, dest []byte) (int, error)
13
+
14
+func listxattrAll(path string, listFunc listxattrFunc) ([]string, error) {
15
+	var p []byte // nil on first execution
16
+
17
+	for {
18
+		n, err := listFunc(path, p) // first call gets buffer size.
19
+		if err != nil {
20
+			return nil, err
21
+		}
22
+
23
+		if n > len(p) {
24
+			p = make([]byte, n)
25
+			continue
26
+		}
27
+
28
+		p = p[:n]
29
+
30
+		ps := bytes.Split(bytes.TrimSuffix(p, []byte{0}), []byte{0})
31
+		var entries []string
32
+		for _, p := range ps {
33
+			s := string(p)
34
+			if s != "" {
35
+				entries = append(entries, s)
36
+			}
37
+		}
38
+
39
+		return entries, nil
40
+	}
41
+}
42
+
43
+type getxattrFunc func(string, string, []byte) (int, error)
44
+
45
+func getxattrAll(path, attr string, getFunc getxattrFunc) ([]byte, error) {
46
+	p := make([]byte, defaultXattrBufferSize)
47
+	for {
48
+		n, err := getFunc(path, attr, p)
49
+		if err != nil {
50
+			if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERANGE {
51
+				p = make([]byte, len(p)*2) // this can't be ideal.
52
+				continue                   // try again!
53
+			}
54
+
55
+			return nil, err
56
+		}
57
+
58
+		// realloc to correct size and repeat
59
+		if n > len(p) {
60
+			p = make([]byte, n)
61
+			continue
62
+		}
63
+
64
+		return p[:n], nil
65
+	}
66
+}
0 67
new file mode 100644
... ...
@@ -0,0 +1,71 @@
0
+package sysx
1
+
2
+// These functions will be generated by generate.sh
3
+//    $ GOOS=darwin GOARCH=386 ./generate.sh xattr
4
+//    $ GOOS=darwin GOARCH=amd64 ./generate.sh xattr
5
+
6
+//sys  getxattr(path string, attr string, dest []byte, pos int, options int) (sz int, err error)
7
+//sys  setxattr(path string, attr string, data []byte, flags int) (err error)
8
+//sys  removexattr(path string, attr string, options int) (err error)
9
+//sys  listxattr(path string, dest []byte, options int) (sz int, err error)
10
+//sys  Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
11
+
12
+const (
13
+	xattrNoFollow = 0x01
14
+)
15
+
16
+func listxattrFollow(path string, dest []byte) (sz int, err error) {
17
+	return listxattr(path, dest, 0)
18
+}
19
+
20
+// Listxattr calls syscall getxattr
21
+func Listxattr(path string) ([]string, error) {
22
+	return listxattrAll(path, listxattrFollow)
23
+}
24
+
25
+// Removexattr calls syscall getxattr
26
+func Removexattr(path string, attr string) (err error) {
27
+	return removexattr(path, attr, 0)
28
+}
29
+
30
+// Setxattr calls syscall setxattr
31
+func Setxattr(path string, attr string, data []byte, flags int) (err error) {
32
+	return setxattr(path, attr, data, flags)
33
+}
34
+
35
+func getxattrFollow(path, attr string, dest []byte) (sz int, err error) {
36
+	return getxattr(path, attr, dest, 0, 0)
37
+}
38
+
39
+// Getxattr calls syscall getxattr
40
+func Getxattr(path, attr string) ([]byte, error) {
41
+	return getxattrAll(path, attr, getxattrFollow)
42
+}
43
+
44
+func listxattrNoFollow(path string, dest []byte) (sz int, err error) {
45
+	return listxattr(path, dest, xattrNoFollow)
46
+}
47
+
48
+// LListxattr calls syscall listxattr with XATTR_NOFOLLOW
49
+func LListxattr(path string) ([]string, error) {
50
+	return listxattrAll(path, listxattrNoFollow)
51
+}
52
+
53
+// LRemovexattr calls syscall removexattr with XATTR_NOFOLLOW
54
+func LRemovexattr(path string, attr string) (err error) {
55
+	return removexattr(path, attr, xattrNoFollow)
56
+}
57
+
58
+// Setxattr calls syscall setxattr with XATTR_NOFOLLOW
59
+func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
60
+	return setxattr(path, attr, data, flags|xattrNoFollow)
61
+}
62
+
63
+func getxattrNoFollow(path, attr string, dest []byte) (sz int, err error) {
64
+	return getxattr(path, attr, dest, 0, xattrNoFollow)
65
+}
66
+
67
+// LGetxattr calls syscall getxattr with XATTR_NOFOLLOW
68
+func LGetxattr(path, attr string) ([]byte, error) {
69
+	return getxattrAll(path, attr, getxattrNoFollow)
70
+}
0 71
new file mode 100644
... ...
@@ -0,0 +1,111 @@
0
+// mksyscall.pl -l32 xattr_darwin.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func getxattr(path string, attr string, dest []byte, pos int, options int) (sz int, err error) {
13
+	var _p0 *byte
14
+	_p0, err = syscall.BytePtrFromString(path)
15
+	if err != nil {
16
+		return
17
+	}
18
+	var _p1 *byte
19
+	_p1, err = syscall.BytePtrFromString(attr)
20
+	if err != nil {
21
+		return
22
+	}
23
+	var _p2 unsafe.Pointer
24
+	if len(dest) > 0 {
25
+		_p2 = unsafe.Pointer(&dest[0])
26
+	} else {
27
+		_p2 = unsafe.Pointer(&_zero)
28
+	}
29
+	r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), uintptr(pos), uintptr(options))
30
+	use(unsafe.Pointer(_p0))
31
+	use(unsafe.Pointer(_p1))
32
+	sz = int(r0)
33
+	if e1 != 0 {
34
+		err = errnoErr(e1)
35
+	}
36
+	return
37
+}
38
+
39
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
40
+
41
+func setxattr(path string, attr string, data []byte, flags int) (err error) {
42
+	var _p0 *byte
43
+	_p0, err = syscall.BytePtrFromString(path)
44
+	if err != nil {
45
+		return
46
+	}
47
+	var _p1 *byte
48
+	_p1, err = syscall.BytePtrFromString(attr)
49
+	if err != nil {
50
+		return
51
+	}
52
+	var _p2 unsafe.Pointer
53
+	if len(data) > 0 {
54
+		_p2 = unsafe.Pointer(&data[0])
55
+	} else {
56
+		_p2 = unsafe.Pointer(&_zero)
57
+	}
58
+	_, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
59
+	use(unsafe.Pointer(_p0))
60
+	use(unsafe.Pointer(_p1))
61
+	if e1 != 0 {
62
+		err = errnoErr(e1)
63
+	}
64
+	return
65
+}
66
+
67
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
68
+
69
+func removexattr(path string, attr string, options int) (err error) {
70
+	var _p0 *byte
71
+	_p0, err = syscall.BytePtrFromString(path)
72
+	if err != nil {
73
+		return
74
+	}
75
+	var _p1 *byte
76
+	_p1, err = syscall.BytePtrFromString(attr)
77
+	if err != nil {
78
+		return
79
+	}
80
+	_, _, e1 := syscall.Syscall(syscall.SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options))
81
+	use(unsafe.Pointer(_p0))
82
+	use(unsafe.Pointer(_p1))
83
+	if e1 != 0 {
84
+		err = errnoErr(e1)
85
+	}
86
+	return
87
+}
88
+
89
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
90
+
91
+func listxattr(path string, dest []byte, options int) (sz int, err error) {
92
+	var _p0 *byte
93
+	_p0, err = syscall.BytePtrFromString(path)
94
+	if err != nil {
95
+		return
96
+	}
97
+	var _p1 unsafe.Pointer
98
+	if len(dest) > 0 {
99
+		_p1 = unsafe.Pointer(&dest[0])
100
+	} else {
101
+		_p1 = unsafe.Pointer(&_zero)
102
+	}
103
+	r0, _, e1 := syscall.Syscall6(syscall.SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(options), 0, 0)
104
+	use(unsafe.Pointer(_p0))
105
+	sz = int(r0)
106
+	if e1 != 0 {
107
+		err = errnoErr(e1)
108
+	}
109
+	return
110
+}
0 111
new file mode 100644
... ...
@@ -0,0 +1,111 @@
0
+// mksyscall.pl xattr_darwin.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func getxattr(path string, attr string, dest []byte, pos int, options int) (sz int, err error) {
13
+	var _p0 *byte
14
+	_p0, err = syscall.BytePtrFromString(path)
15
+	if err != nil {
16
+		return
17
+	}
18
+	var _p1 *byte
19
+	_p1, err = syscall.BytePtrFromString(attr)
20
+	if err != nil {
21
+		return
22
+	}
23
+	var _p2 unsafe.Pointer
24
+	if len(dest) > 0 {
25
+		_p2 = unsafe.Pointer(&dest[0])
26
+	} else {
27
+		_p2 = unsafe.Pointer(&_zero)
28
+	}
29
+	r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), uintptr(pos), uintptr(options))
30
+	use(unsafe.Pointer(_p0))
31
+	use(unsafe.Pointer(_p1))
32
+	sz = int(r0)
33
+	if e1 != 0 {
34
+		err = errnoErr(e1)
35
+	}
36
+	return
37
+}
38
+
39
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
40
+
41
+func setxattr(path string, attr string, data []byte, flags int) (err error) {
42
+	var _p0 *byte
43
+	_p0, err = syscall.BytePtrFromString(path)
44
+	if err != nil {
45
+		return
46
+	}
47
+	var _p1 *byte
48
+	_p1, err = syscall.BytePtrFromString(attr)
49
+	if err != nil {
50
+		return
51
+	}
52
+	var _p2 unsafe.Pointer
53
+	if len(data) > 0 {
54
+		_p2 = unsafe.Pointer(&data[0])
55
+	} else {
56
+		_p2 = unsafe.Pointer(&_zero)
57
+	}
58
+	_, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
59
+	use(unsafe.Pointer(_p0))
60
+	use(unsafe.Pointer(_p1))
61
+	if e1 != 0 {
62
+		err = errnoErr(e1)
63
+	}
64
+	return
65
+}
66
+
67
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
68
+
69
+func removexattr(path string, attr string, options int) (err error) {
70
+	var _p0 *byte
71
+	_p0, err = syscall.BytePtrFromString(path)
72
+	if err != nil {
73
+		return
74
+	}
75
+	var _p1 *byte
76
+	_p1, err = syscall.BytePtrFromString(attr)
77
+	if err != nil {
78
+		return
79
+	}
80
+	_, _, e1 := syscall.Syscall(syscall.SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options))
81
+	use(unsafe.Pointer(_p0))
82
+	use(unsafe.Pointer(_p1))
83
+	if e1 != 0 {
84
+		err = errnoErr(e1)
85
+	}
86
+	return
87
+}
88
+
89
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
90
+
91
+func listxattr(path string, dest []byte, options int) (sz int, err error) {
92
+	var _p0 *byte
93
+	_p0, err = syscall.BytePtrFromString(path)
94
+	if err != nil {
95
+		return
96
+	}
97
+	var _p1 unsafe.Pointer
98
+	if len(dest) > 0 {
99
+		_p1 = unsafe.Pointer(&dest[0])
100
+	} else {
101
+		_p1 = unsafe.Pointer(&_zero)
102
+	}
103
+	r0, _, e1 := syscall.Syscall6(syscall.SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)), uintptr(options), 0, 0)
104
+	use(unsafe.Pointer(_p0))
105
+	sz = int(r0)
106
+	if e1 != 0 {
107
+		err = errnoErr(e1)
108
+	}
109
+	return
110
+}
0 111
new file mode 100644
... ...
@@ -0,0 +1,53 @@
0
+package sysx
1
+
2
+import (
3
+	"errors"
4
+)
5
+
6
+// Initial stub version for FreeBSD. FreeBSD has a different
7
+// syscall API from Darwin and Linux for extended attributes;
8
+// it is also not widely used. It is not exposed at all by the
9
+// Go syscall package, so we need to implement directly eventually.
10
+
11
+var unsupported error = errors.New("extended attributes unsupported on FreeBSD")
12
+
13
+// Listxattr calls syscall listxattr and reads all content
14
+// and returns a string array
15
+func Listxattr(path string) ([]string, error) {
16
+	return []string{}, nil
17
+}
18
+
19
+// Removexattr calls syscall removexattr
20
+func Removexattr(path string, attr string) (err error) {
21
+	return unsupported
22
+}
23
+
24
+// Setxattr calls syscall setxattr
25
+func Setxattr(path string, attr string, data []byte, flags int) (err error) {
26
+	return unsupported
27
+}
28
+
29
+// Getxattr calls syscall getxattr
30
+func Getxattr(path, attr string) ([]byte, error) {
31
+	return []byte{}, nil
32
+}
33
+
34
+// LListxattr lists xattrs, not following symlinks
35
+func LListxattr(path string) ([]string, error) {
36
+	return []string{}, nil
37
+}
38
+
39
+// LRemovexattr removes an xattr, not following symlinks
40
+func LRemovexattr(path string, attr string) (err error) {
41
+	return unsupported
42
+}
43
+
44
+// LSetxattr sets an xattr, not following symlinks
45
+func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
46
+	return unsupported
47
+}
48
+
49
+// LGetxattr gets an xattr, not following symlinks
50
+func LGetxattr(path, attr string) ([]byte, error) {
51
+	return []byte{}, nil
52
+}
0 53
new file mode 100644
... ...
@@ -0,0 +1,61 @@
0
+package sysx
1
+
2
+import "syscall"
3
+
4
+// These functions will be generated by generate.sh
5
+//    $ GOOS=linux GOARCH=386 ./generate.sh xattr
6
+//    $ GOOS=linux GOARCH=amd64 ./generate.sh xattr
7
+//    $ GOOS=linux GOARCH=arm ./generate.sh xattr
8
+//    $ GOOS=linux GOARCH=arm64 ./generate.sh xattr
9
+//    $ GOOS=linux GOARCH=ppc64 ./generate.sh xattr
10
+//    $ GOOS=linux GOARCH=ppc64le ./generate.sh xattr
11
+//    $ GOOS=linux GOARCH=s390x ./generate.sh xattr
12
+
13
+// Listxattr calls syscall listxattr and reads all content
14
+// and returns a string array
15
+func Listxattr(path string) ([]string, error) {
16
+	return listxattrAll(path, syscall.Listxattr)
17
+}
18
+
19
+// Removexattr calls syscall removexattr
20
+func Removexattr(path string, attr string) (err error) {
21
+	return syscall.Removexattr(path, attr)
22
+}
23
+
24
+// Setxattr calls syscall setxattr
25
+func Setxattr(path string, attr string, data []byte, flags int) (err error) {
26
+	return syscall.Setxattr(path, attr, data, flags)
27
+}
28
+
29
+// Getxattr calls syscall getxattr
30
+func Getxattr(path, attr string) ([]byte, error) {
31
+	return getxattrAll(path, attr, syscall.Getxattr)
32
+}
33
+
34
+//sys llistxattr(path string, dest []byte) (sz int, err error)
35
+
36
+// LListxattr lists xattrs, not following symlinks
37
+func LListxattr(path string) ([]string, error) {
38
+	return listxattrAll(path, llistxattr)
39
+}
40
+
41
+//sys lremovexattr(path string, attr string) (err error)
42
+
43
+// LRemovexattr removes an xattr, not following symlinks
44
+func LRemovexattr(path string, attr string) (err error) {
45
+	return lremovexattr(path, attr)
46
+}
47
+
48
+//sys lsetxattr(path string, attr string, data []byte, flags int) (err error)
49
+
50
+// LSetxattr sets an xattr, not following symlinks
51
+func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
52
+	return lsetxattr(path, attr, data, flags)
53
+}
54
+
55
+//sys lgetxattr(path string, attr string, dest []byte) (sz int, err error)
56
+
57
+// LGetxattr gets an xattr, not following symlinks
58
+func LGetxattr(path, attr string) ([]byte, error) {
59
+	return getxattrAll(path, attr, lgetxattr)
60
+}
0 61
new file mode 100644
... ...
@@ -0,0 +1,111 @@
0
+// mksyscall.pl -l32 xattr_linux.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func llistxattr(path string, dest []byte) (sz int, err error) {
13
+	var _p0 *byte
14
+	_p0, err = syscall.BytePtrFromString(path)
15
+	if err != nil {
16
+		return
17
+	}
18
+	var _p1 unsafe.Pointer
19
+	if len(dest) > 0 {
20
+		_p1 = unsafe.Pointer(&dest[0])
21
+	} else {
22
+		_p1 = unsafe.Pointer(&_zero)
23
+	}
24
+	r0, _, e1 := syscall.Syscall(syscall.SYS_LLISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)))
25
+	use(unsafe.Pointer(_p0))
26
+	sz = int(r0)
27
+	if e1 != 0 {
28
+		err = errnoErr(e1)
29
+	}
30
+	return
31
+}
32
+
33
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
34
+
35
+func lremovexattr(path string, attr string) (err error) {
36
+	var _p0 *byte
37
+	_p0, err = syscall.BytePtrFromString(path)
38
+	if err != nil {
39
+		return
40
+	}
41
+	var _p1 *byte
42
+	_p1, err = syscall.BytePtrFromString(attr)
43
+	if err != nil {
44
+		return
45
+	}
46
+	_, _, e1 := syscall.Syscall(syscall.SYS_LREMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
47
+	use(unsafe.Pointer(_p0))
48
+	use(unsafe.Pointer(_p1))
49
+	if e1 != 0 {
50
+		err = errnoErr(e1)
51
+	}
52
+	return
53
+}
54
+
55
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
56
+
57
+func lsetxattr(path string, attr string, data []byte, flags int) (err error) {
58
+	var _p0 *byte
59
+	_p0, err = syscall.BytePtrFromString(path)
60
+	if err != nil {
61
+		return
62
+	}
63
+	var _p1 *byte
64
+	_p1, err = syscall.BytePtrFromString(attr)
65
+	if err != nil {
66
+		return
67
+	}
68
+	var _p2 unsafe.Pointer
69
+	if len(data) > 0 {
70
+		_p2 = unsafe.Pointer(&data[0])
71
+	} else {
72
+		_p2 = unsafe.Pointer(&_zero)
73
+	}
74
+	_, _, e1 := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
75
+	use(unsafe.Pointer(_p0))
76
+	use(unsafe.Pointer(_p1))
77
+	if e1 != 0 {
78
+		err = errnoErr(e1)
79
+	}
80
+	return
81
+}
82
+
83
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
84
+
85
+func lgetxattr(path string, attr string, dest []byte) (sz int, err error) {
86
+	var _p0 *byte
87
+	_p0, err = syscall.BytePtrFromString(path)
88
+	if err != nil {
89
+		return
90
+	}
91
+	var _p1 *byte
92
+	_p1, err = syscall.BytePtrFromString(attr)
93
+	if err != nil {
94
+		return
95
+	}
96
+	var _p2 unsafe.Pointer
97
+	if len(dest) > 0 {
98
+		_p2 = unsafe.Pointer(&dest[0])
99
+	} else {
100
+		_p2 = unsafe.Pointer(&_zero)
101
+	}
102
+	r0, _, e1 := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0)
103
+	use(unsafe.Pointer(_p0))
104
+	use(unsafe.Pointer(_p1))
105
+	sz = int(r0)
106
+	if e1 != 0 {
107
+		err = errnoErr(e1)
108
+	}
109
+	return
110
+}
0 111
new file mode 100644
... ...
@@ -0,0 +1,111 @@
0
+// mksyscall.pl xattr_linux.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func llistxattr(path string, dest []byte) (sz int, err error) {
13
+	var _p0 *byte
14
+	_p0, err = syscall.BytePtrFromString(path)
15
+	if err != nil {
16
+		return
17
+	}
18
+	var _p1 unsafe.Pointer
19
+	if len(dest) > 0 {
20
+		_p1 = unsafe.Pointer(&dest[0])
21
+	} else {
22
+		_p1 = unsafe.Pointer(&_zero)
23
+	}
24
+	r0, _, e1 := syscall.Syscall(syscall.SYS_LLISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)))
25
+	use(unsafe.Pointer(_p0))
26
+	sz = int(r0)
27
+	if e1 != 0 {
28
+		err = errnoErr(e1)
29
+	}
30
+	return
31
+}
32
+
33
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
34
+
35
+func lremovexattr(path string, attr string) (err error) {
36
+	var _p0 *byte
37
+	_p0, err = syscall.BytePtrFromString(path)
38
+	if err != nil {
39
+		return
40
+	}
41
+	var _p1 *byte
42
+	_p1, err = syscall.BytePtrFromString(attr)
43
+	if err != nil {
44
+		return
45
+	}
46
+	_, _, e1 := syscall.Syscall(syscall.SYS_LREMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
47
+	use(unsafe.Pointer(_p0))
48
+	use(unsafe.Pointer(_p1))
49
+	if e1 != 0 {
50
+		err = errnoErr(e1)
51
+	}
52
+	return
53
+}
54
+
55
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
56
+
57
+func lsetxattr(path string, attr string, data []byte, flags int) (err error) {
58
+	var _p0 *byte
59
+	_p0, err = syscall.BytePtrFromString(path)
60
+	if err != nil {
61
+		return
62
+	}
63
+	var _p1 *byte
64
+	_p1, err = syscall.BytePtrFromString(attr)
65
+	if err != nil {
66
+		return
67
+	}
68
+	var _p2 unsafe.Pointer
69
+	if len(data) > 0 {
70
+		_p2 = unsafe.Pointer(&data[0])
71
+	} else {
72
+		_p2 = unsafe.Pointer(&_zero)
73
+	}
74
+	_, _, e1 := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
75
+	use(unsafe.Pointer(_p0))
76
+	use(unsafe.Pointer(_p1))
77
+	if e1 != 0 {
78
+		err = errnoErr(e1)
79
+	}
80
+	return
81
+}
82
+
83
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
84
+
85
+func lgetxattr(path string, attr string, dest []byte) (sz int, err error) {
86
+	var _p0 *byte
87
+	_p0, err = syscall.BytePtrFromString(path)
88
+	if err != nil {
89
+		return
90
+	}
91
+	var _p1 *byte
92
+	_p1, err = syscall.BytePtrFromString(attr)
93
+	if err != nil {
94
+		return
95
+	}
96
+	var _p2 unsafe.Pointer
97
+	if len(dest) > 0 {
98
+		_p2 = unsafe.Pointer(&dest[0])
99
+	} else {
100
+		_p2 = unsafe.Pointer(&_zero)
101
+	}
102
+	r0, _, e1 := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0)
103
+	use(unsafe.Pointer(_p0))
104
+	use(unsafe.Pointer(_p1))
105
+	sz = int(r0)
106
+	if e1 != 0 {
107
+		err = errnoErr(e1)
108
+	}
109
+	return
110
+}
0 111
new file mode 100644
... ...
@@ -0,0 +1,111 @@
0
+// mksyscall.pl -l32 xattr_linux.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func llistxattr(path string, dest []byte) (sz int, err error) {
13
+	var _p0 *byte
14
+	_p0, err = syscall.BytePtrFromString(path)
15
+	if err != nil {
16
+		return
17
+	}
18
+	var _p1 unsafe.Pointer
19
+	if len(dest) > 0 {
20
+		_p1 = unsafe.Pointer(&dest[0])
21
+	} else {
22
+		_p1 = unsafe.Pointer(&_zero)
23
+	}
24
+	r0, _, e1 := syscall.Syscall(syscall.SYS_LLISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)))
25
+	use(unsafe.Pointer(_p0))
26
+	sz = int(r0)
27
+	if e1 != 0 {
28
+		err = errnoErr(e1)
29
+	}
30
+	return
31
+}
32
+
33
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
34
+
35
+func lremovexattr(path string, attr string) (err error) {
36
+	var _p0 *byte
37
+	_p0, err = syscall.BytePtrFromString(path)
38
+	if err != nil {
39
+		return
40
+	}
41
+	var _p1 *byte
42
+	_p1, err = syscall.BytePtrFromString(attr)
43
+	if err != nil {
44
+		return
45
+	}
46
+	_, _, e1 := syscall.Syscall(syscall.SYS_LREMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
47
+	use(unsafe.Pointer(_p0))
48
+	use(unsafe.Pointer(_p1))
49
+	if e1 != 0 {
50
+		err = errnoErr(e1)
51
+	}
52
+	return
53
+}
54
+
55
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
56
+
57
+func lsetxattr(path string, attr string, data []byte, flags int) (err error) {
58
+	var _p0 *byte
59
+	_p0, err = syscall.BytePtrFromString(path)
60
+	if err != nil {
61
+		return
62
+	}
63
+	var _p1 *byte
64
+	_p1, err = syscall.BytePtrFromString(attr)
65
+	if err != nil {
66
+		return
67
+	}
68
+	var _p2 unsafe.Pointer
69
+	if len(data) > 0 {
70
+		_p2 = unsafe.Pointer(&data[0])
71
+	} else {
72
+		_p2 = unsafe.Pointer(&_zero)
73
+	}
74
+	_, _, e1 := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
75
+	use(unsafe.Pointer(_p0))
76
+	use(unsafe.Pointer(_p1))
77
+	if e1 != 0 {
78
+		err = errnoErr(e1)
79
+	}
80
+	return
81
+}
82
+
83
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
84
+
85
+func lgetxattr(path string, attr string, dest []byte) (sz int, err error) {
86
+	var _p0 *byte
87
+	_p0, err = syscall.BytePtrFromString(path)
88
+	if err != nil {
89
+		return
90
+	}
91
+	var _p1 *byte
92
+	_p1, err = syscall.BytePtrFromString(attr)
93
+	if err != nil {
94
+		return
95
+	}
96
+	var _p2 unsafe.Pointer
97
+	if len(dest) > 0 {
98
+		_p2 = unsafe.Pointer(&dest[0])
99
+	} else {
100
+		_p2 = unsafe.Pointer(&_zero)
101
+	}
102
+	r0, _, e1 := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0)
103
+	use(unsafe.Pointer(_p0))
104
+	use(unsafe.Pointer(_p1))
105
+	sz = int(r0)
106
+	if e1 != 0 {
107
+		err = errnoErr(e1)
108
+	}
109
+	return
110
+}
0 111
new file mode 100644
... ...
@@ -0,0 +1,111 @@
0
+// mksyscall.pl xattr_linux.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func llistxattr(path string, dest []byte) (sz int, err error) {
13
+	var _p0 *byte
14
+	_p0, err = syscall.BytePtrFromString(path)
15
+	if err != nil {
16
+		return
17
+	}
18
+	var _p1 unsafe.Pointer
19
+	if len(dest) > 0 {
20
+		_p1 = unsafe.Pointer(&dest[0])
21
+	} else {
22
+		_p1 = unsafe.Pointer(&_zero)
23
+	}
24
+	r0, _, e1 := syscall.Syscall(syscall.SYS_LLISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)))
25
+	use(unsafe.Pointer(_p0))
26
+	sz = int(r0)
27
+	if e1 != 0 {
28
+		err = errnoErr(e1)
29
+	}
30
+	return
31
+}
32
+
33
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
34
+
35
+func lremovexattr(path string, attr string) (err error) {
36
+	var _p0 *byte
37
+	_p0, err = syscall.BytePtrFromString(path)
38
+	if err != nil {
39
+		return
40
+	}
41
+	var _p1 *byte
42
+	_p1, err = syscall.BytePtrFromString(attr)
43
+	if err != nil {
44
+		return
45
+	}
46
+	_, _, e1 := syscall.Syscall(syscall.SYS_LREMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
47
+	use(unsafe.Pointer(_p0))
48
+	use(unsafe.Pointer(_p1))
49
+	if e1 != 0 {
50
+		err = errnoErr(e1)
51
+	}
52
+	return
53
+}
54
+
55
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
56
+
57
+func lsetxattr(path string, attr string, data []byte, flags int) (err error) {
58
+	var _p0 *byte
59
+	_p0, err = syscall.BytePtrFromString(path)
60
+	if err != nil {
61
+		return
62
+	}
63
+	var _p1 *byte
64
+	_p1, err = syscall.BytePtrFromString(attr)
65
+	if err != nil {
66
+		return
67
+	}
68
+	var _p2 unsafe.Pointer
69
+	if len(data) > 0 {
70
+		_p2 = unsafe.Pointer(&data[0])
71
+	} else {
72
+		_p2 = unsafe.Pointer(&_zero)
73
+	}
74
+	_, _, e1 := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
75
+	use(unsafe.Pointer(_p0))
76
+	use(unsafe.Pointer(_p1))
77
+	if e1 != 0 {
78
+		err = errnoErr(e1)
79
+	}
80
+	return
81
+}
82
+
83
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
84
+
85
+func lgetxattr(path string, attr string, dest []byte) (sz int, err error) {
86
+	var _p0 *byte
87
+	_p0, err = syscall.BytePtrFromString(path)
88
+	if err != nil {
89
+		return
90
+	}
91
+	var _p1 *byte
92
+	_p1, err = syscall.BytePtrFromString(attr)
93
+	if err != nil {
94
+		return
95
+	}
96
+	var _p2 unsafe.Pointer
97
+	if len(dest) > 0 {
98
+		_p2 = unsafe.Pointer(&dest[0])
99
+	} else {
100
+		_p2 = unsafe.Pointer(&_zero)
101
+	}
102
+	r0, _, e1 := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0)
103
+	use(unsafe.Pointer(_p0))
104
+	use(unsafe.Pointer(_p1))
105
+	sz = int(r0)
106
+	if e1 != 0 {
107
+		err = errnoErr(e1)
108
+	}
109
+	return
110
+}
0 111
new file mode 100644
... ...
@@ -0,0 +1,111 @@
0
+// mksyscall.pl xattr_linux.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func llistxattr(path string, dest []byte) (sz int, err error) {
13
+	var _p0 *byte
14
+	_p0, err = syscall.BytePtrFromString(path)
15
+	if err != nil {
16
+		return
17
+	}
18
+	var _p1 unsafe.Pointer
19
+	if len(dest) > 0 {
20
+		_p1 = unsafe.Pointer(&dest[0])
21
+	} else {
22
+		_p1 = unsafe.Pointer(&_zero)
23
+	}
24
+	r0, _, e1 := syscall.Syscall(syscall.SYS_LLISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)))
25
+	use(unsafe.Pointer(_p0))
26
+	sz = int(r0)
27
+	if e1 != 0 {
28
+		err = errnoErr(e1)
29
+	}
30
+	return
31
+}
32
+
33
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
34
+
35
+func lremovexattr(path string, attr string) (err error) {
36
+	var _p0 *byte
37
+	_p0, err = syscall.BytePtrFromString(path)
38
+	if err != nil {
39
+		return
40
+	}
41
+	var _p1 *byte
42
+	_p1, err = syscall.BytePtrFromString(attr)
43
+	if err != nil {
44
+		return
45
+	}
46
+	_, _, e1 := syscall.Syscall(syscall.SYS_LREMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
47
+	use(unsafe.Pointer(_p0))
48
+	use(unsafe.Pointer(_p1))
49
+	if e1 != 0 {
50
+		err = errnoErr(e1)
51
+	}
52
+	return
53
+}
54
+
55
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
56
+
57
+func lsetxattr(path string, attr string, data []byte, flags int) (err error) {
58
+	var _p0 *byte
59
+	_p0, err = syscall.BytePtrFromString(path)
60
+	if err != nil {
61
+		return
62
+	}
63
+	var _p1 *byte
64
+	_p1, err = syscall.BytePtrFromString(attr)
65
+	if err != nil {
66
+		return
67
+	}
68
+	var _p2 unsafe.Pointer
69
+	if len(data) > 0 {
70
+		_p2 = unsafe.Pointer(&data[0])
71
+	} else {
72
+		_p2 = unsafe.Pointer(&_zero)
73
+	}
74
+	_, _, e1 := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
75
+	use(unsafe.Pointer(_p0))
76
+	use(unsafe.Pointer(_p1))
77
+	if e1 != 0 {
78
+		err = errnoErr(e1)
79
+	}
80
+	return
81
+}
82
+
83
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
84
+
85
+func lgetxattr(path string, attr string, dest []byte) (sz int, err error) {
86
+	var _p0 *byte
87
+	_p0, err = syscall.BytePtrFromString(path)
88
+	if err != nil {
89
+		return
90
+	}
91
+	var _p1 *byte
92
+	_p1, err = syscall.BytePtrFromString(attr)
93
+	if err != nil {
94
+		return
95
+	}
96
+	var _p2 unsafe.Pointer
97
+	if len(dest) > 0 {
98
+		_p2 = unsafe.Pointer(&dest[0])
99
+	} else {
100
+		_p2 = unsafe.Pointer(&_zero)
101
+	}
102
+	r0, _, e1 := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0)
103
+	use(unsafe.Pointer(_p0))
104
+	use(unsafe.Pointer(_p1))
105
+	sz = int(r0)
106
+	if e1 != 0 {
107
+		err = errnoErr(e1)
108
+	}
109
+	return
110
+}
0 111
new file mode 100644
... ...
@@ -0,0 +1,111 @@
0
+// mksyscall.pl xattr_linux.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func llistxattr(path string, dest []byte) (sz int, err error) {
13
+	var _p0 *byte
14
+	_p0, err = syscall.BytePtrFromString(path)
15
+	if err != nil {
16
+		return
17
+	}
18
+	var _p1 unsafe.Pointer
19
+	if len(dest) > 0 {
20
+		_p1 = unsafe.Pointer(&dest[0])
21
+	} else {
22
+		_p1 = unsafe.Pointer(&_zero)
23
+	}
24
+	r0, _, e1 := syscall.Syscall(syscall.SYS_LLISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)))
25
+	use(unsafe.Pointer(_p0))
26
+	sz = int(r0)
27
+	if e1 != 0 {
28
+		err = errnoErr(e1)
29
+	}
30
+	return
31
+}
32
+
33
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
34
+
35
+func lremovexattr(path string, attr string) (err error) {
36
+	var _p0 *byte
37
+	_p0, err = syscall.BytePtrFromString(path)
38
+	if err != nil {
39
+		return
40
+	}
41
+	var _p1 *byte
42
+	_p1, err = syscall.BytePtrFromString(attr)
43
+	if err != nil {
44
+		return
45
+	}
46
+	_, _, e1 := syscall.Syscall(syscall.SYS_LREMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
47
+	use(unsafe.Pointer(_p0))
48
+	use(unsafe.Pointer(_p1))
49
+	if e1 != 0 {
50
+		err = errnoErr(e1)
51
+	}
52
+	return
53
+}
54
+
55
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
56
+
57
+func lsetxattr(path string, attr string, data []byte, flags int) (err error) {
58
+	var _p0 *byte
59
+	_p0, err = syscall.BytePtrFromString(path)
60
+	if err != nil {
61
+		return
62
+	}
63
+	var _p1 *byte
64
+	_p1, err = syscall.BytePtrFromString(attr)
65
+	if err != nil {
66
+		return
67
+	}
68
+	var _p2 unsafe.Pointer
69
+	if len(data) > 0 {
70
+		_p2 = unsafe.Pointer(&data[0])
71
+	} else {
72
+		_p2 = unsafe.Pointer(&_zero)
73
+	}
74
+	_, _, e1 := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
75
+	use(unsafe.Pointer(_p0))
76
+	use(unsafe.Pointer(_p1))
77
+	if e1 != 0 {
78
+		err = errnoErr(e1)
79
+	}
80
+	return
81
+}
82
+
83
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
84
+
85
+func lgetxattr(path string, attr string, dest []byte) (sz int, err error) {
86
+	var _p0 *byte
87
+	_p0, err = syscall.BytePtrFromString(path)
88
+	if err != nil {
89
+		return
90
+	}
91
+	var _p1 *byte
92
+	_p1, err = syscall.BytePtrFromString(attr)
93
+	if err != nil {
94
+		return
95
+	}
96
+	var _p2 unsafe.Pointer
97
+	if len(dest) > 0 {
98
+		_p2 = unsafe.Pointer(&dest[0])
99
+	} else {
100
+		_p2 = unsafe.Pointer(&_zero)
101
+	}
102
+	r0, _, e1 := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0)
103
+	use(unsafe.Pointer(_p0))
104
+	use(unsafe.Pointer(_p1))
105
+	sz = int(r0)
106
+	if e1 != 0 {
107
+		err = errnoErr(e1)
108
+	}
109
+	return
110
+}
0 111
new file mode 100644
... ...
@@ -0,0 +1,111 @@
0
+// mksyscall.pl xattr_linux.go
1
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
2
+
3
+package sysx
4
+
5
+import (
6
+	"syscall"
7
+	"unsafe"
8
+)
9
+
10
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
11
+
12
+func llistxattr(path string, dest []byte) (sz int, err error) {
13
+	var _p0 *byte
14
+	_p0, err = syscall.BytePtrFromString(path)
15
+	if err != nil {
16
+		return
17
+	}
18
+	var _p1 unsafe.Pointer
19
+	if len(dest) > 0 {
20
+		_p1 = unsafe.Pointer(&dest[0])
21
+	} else {
22
+		_p1 = unsafe.Pointer(&_zero)
23
+	}
24
+	r0, _, e1 := syscall.Syscall(syscall.SYS_LLISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)))
25
+	use(unsafe.Pointer(_p0))
26
+	sz = int(r0)
27
+	if e1 != 0 {
28
+		err = errnoErr(e1)
29
+	}
30
+	return
31
+}
32
+
33
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
34
+
35
+func lremovexattr(path string, attr string) (err error) {
36
+	var _p0 *byte
37
+	_p0, err = syscall.BytePtrFromString(path)
38
+	if err != nil {
39
+		return
40
+	}
41
+	var _p1 *byte
42
+	_p1, err = syscall.BytePtrFromString(attr)
43
+	if err != nil {
44
+		return
45
+	}
46
+	_, _, e1 := syscall.Syscall(syscall.SYS_LREMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
47
+	use(unsafe.Pointer(_p0))
48
+	use(unsafe.Pointer(_p1))
49
+	if e1 != 0 {
50
+		err = errnoErr(e1)
51
+	}
52
+	return
53
+}
54
+
55
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
56
+
57
+func lsetxattr(path string, attr string, data []byte, flags int) (err error) {
58
+	var _p0 *byte
59
+	_p0, err = syscall.BytePtrFromString(path)
60
+	if err != nil {
61
+		return
62
+	}
63
+	var _p1 *byte
64
+	_p1, err = syscall.BytePtrFromString(attr)
65
+	if err != nil {
66
+		return
67
+	}
68
+	var _p2 unsafe.Pointer
69
+	if len(data) > 0 {
70
+		_p2 = unsafe.Pointer(&data[0])
71
+	} else {
72
+		_p2 = unsafe.Pointer(&_zero)
73
+	}
74
+	_, _, e1 := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
75
+	use(unsafe.Pointer(_p0))
76
+	use(unsafe.Pointer(_p1))
77
+	if e1 != 0 {
78
+		err = errnoErr(e1)
79
+	}
80
+	return
81
+}
82
+
83
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
84
+
85
+func lgetxattr(path string, attr string, dest []byte) (sz int, err error) {
86
+	var _p0 *byte
87
+	_p0, err = syscall.BytePtrFromString(path)
88
+	if err != nil {
89
+		return
90
+	}
91
+	var _p1 *byte
92
+	_p1, err = syscall.BytePtrFromString(attr)
93
+	if err != nil {
94
+		return
95
+	}
96
+	var _p2 unsafe.Pointer
97
+	if len(dest) > 0 {
98
+		_p2 = unsafe.Pointer(&dest[0])
99
+	} else {
100
+		_p2 = unsafe.Pointer(&_zero)
101
+	}
102
+	r0, _, e1 := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0)
103
+	use(unsafe.Pointer(_p0))
104
+	use(unsafe.Pointer(_p1))
105
+	sz = int(r0)
106
+	if e1 != 0 {
107
+		err = errnoErr(e1)
108
+	}
109
+	return
110
+}
0 111
new file mode 100644
... ...
@@ -0,0 +1,22 @@
0
+MIT
1
+
2
+Copyright 2017 Tõnis Tiigi <tonistiigi@gmail.com>
3
+
4
+Permission is hereby granted, free of charge, to any person obtaining
5
+a copy of this software and associated documentation files (the
6
+"Software"), to deal in the Software without restriction, including
7
+without limitation the rights to use, copy, modify, merge, publish,
8
+distribute, sublicense, and/or sell copies of the Software, and to
9
+permit persons to whom the Software is furnished to do so, subject to
10
+the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be
13
+included in all copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0 22
\ No newline at end of file
1 23
new file mode 100644
... ...
@@ -0,0 +1,37 @@
0
+package fsutil
1
+
2
+import (
3
+	"os"
4
+
5
+	"golang.org/x/net/context"
6
+)
7
+
8
+type walkerFn func(ctx context.Context, pathC chan<- *currentPath) error
9
+
10
+func Changes(ctx context.Context, a, b walkerFn, changeFn ChangeFunc) error {
11
+	return nil
12
+}
13
+
14
+type HandleChangeFn func(ChangeKind, string, os.FileInfo, error) error
15
+
16
+func GetWalkerFn(root string) walkerFn {
17
+	return func(ctx context.Context, pathC chan<- *currentPath) error {
18
+		return Walk(ctx, root, nil, func(path string, f os.FileInfo, err error) error {
19
+			if err != nil {
20
+				return err
21
+			}
22
+
23
+			p := &currentPath{
24
+				path: path,
25
+				f:    f,
26
+			}
27
+
28
+			select {
29
+			case <-ctx.Done():
30
+				return ctx.Err()
31
+			case pathC <- p:
32
+				return nil
33
+			}
34
+		})
35
+	}
36
+}
0 37
new file mode 100644
... ...
@@ -0,0 +1,199 @@
0
+package fsutil
1
+
2
+import (
3
+	"os"
4
+	"strings"
5
+
6
+	"golang.org/x/net/context"
7
+	"golang.org/x/sync/errgroup"
8
+)
9
+
10
+// Everything below is copied from containerd/fs. TODO: remove duplication @dmcgowan
11
+
12
+// Const redefined because containerd/fs doesn't build on !linux
13
+
14
+// ChangeKind is the type of modification that
15
+// a change is making.
16
+type ChangeKind int
17
+
18
+const (
19
+	// ChangeKindAdd represents an addition of
20
+	// a file
21
+	ChangeKindAdd ChangeKind = iota
22
+
23
+	// ChangeKindModify represents a change to
24
+	// an existing file
25
+	ChangeKindModify
26
+
27
+	// ChangeKindDelete represents a delete of
28
+	// a file
29
+	ChangeKindDelete
30
+)
31
+
32
+// ChangeFunc is the type of function called for each change
33
+// computed during a directory changes calculation.
34
+type ChangeFunc func(ChangeKind, string, os.FileInfo, error) error
35
+
36
+type currentPath struct {
37
+	path string
38
+	f    os.FileInfo
39
+	//	fullPath string
40
+}
41
+
42
+// doubleWalkDiff walks both directories to create a diff
43
+func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b walkerFn) (err error) {
44
+	g, ctx := errgroup.WithContext(ctx)
45
+
46
+	var (
47
+		c1 = make(chan *currentPath, 128)
48
+		c2 = make(chan *currentPath, 128)
49
+
50
+		f1, f2 *currentPath
51
+		rmdir  string
52
+	)
53
+	g.Go(func() error {
54
+		defer close(c1)
55
+		return a(ctx, c1)
56
+	})
57
+	g.Go(func() error {
58
+		defer close(c2)
59
+		return b(ctx, c2)
60
+	})
61
+	g.Go(func() error {
62
+	loop0:
63
+		for c1 != nil || c2 != nil {
64
+			if f1 == nil && c1 != nil {
65
+				f1, err = nextPath(ctx, c1)
66
+				if err != nil {
67
+					return err
68
+				}
69
+				if f1 == nil {
70
+					c1 = nil
71
+				}
72
+			}
73
+
74
+			if f2 == nil && c2 != nil {
75
+				f2, err = nextPath(ctx, c2)
76
+				if err != nil {
77
+					return err
78
+				}
79
+				if f2 == nil {
80
+					c2 = nil
81
+				}
82
+			}
83
+			if f1 == nil && f2 == nil {
84
+				continue
85
+			}
86
+
87
+			var f os.FileInfo
88
+			k, p := pathChange(f1, f2)
89
+			switch k {
90
+			case ChangeKindAdd:
91
+				if rmdir != "" {
92
+					rmdir = ""
93
+				}
94
+				f = f2.f
95
+				f2 = nil
96
+			case ChangeKindDelete:
97
+				// Check if this file is already removed by being
98
+				// under of a removed directory
99
+				if rmdir != "" && strings.HasPrefix(f1.path, rmdir) {
100
+					f1 = nil
101
+					continue
102
+				} else if rmdir == "" && f1.f.IsDir() {
103
+					rmdir = f1.path + string(os.PathSeparator)
104
+				} else if rmdir != "" {
105
+					rmdir = ""
106
+				}
107
+				f1 = nil
108
+			case ChangeKindModify:
109
+				same, err := sameFile(f1, f2)
110
+				if err != nil {
111
+					return err
112
+				}
113
+				if f1.f.IsDir() && !f2.f.IsDir() {
114
+					rmdir = f1.path + string(os.PathSeparator)
115
+				} else if rmdir != "" {
116
+					rmdir = ""
117
+				}
118
+				f = f2.f
119
+				f1 = nil
120
+				f2 = nil
121
+				if same {
122
+					continue loop0
123
+				}
124
+			}
125
+			if err := changeFn(k, p, f, nil); err != nil {
126
+				return err
127
+			}
128
+		}
129
+		return nil
130
+	})
131
+
132
+	return g.Wait()
133
+}
134
+
135
+func pathChange(lower, upper *currentPath) (ChangeKind, string) {
136
+	if lower == nil {
137
+		if upper == nil {
138
+			panic("cannot compare nil paths")
139
+		}
140
+		return ChangeKindAdd, upper.path
141
+	}
142
+	if upper == nil {
143
+		return ChangeKindDelete, lower.path
144
+	}
145
+
146
+	switch i := ComparePath(lower.path, upper.path); {
147
+	case i < 0:
148
+		// File in lower that is not in upper
149
+		return ChangeKindDelete, lower.path
150
+	case i > 0:
151
+		// File in upper that is not in lower
152
+		return ChangeKindAdd, upper.path
153
+	default:
154
+		return ChangeKindModify, upper.path
155
+	}
156
+}
157
+
158
+func sameFile(f1, f2 *currentPath) (same bool, retErr error) {
159
+	// If not a directory also check size, modtime, and content
160
+	if !f1.f.IsDir() {
161
+		if f1.f.Size() != f2.f.Size() {
162
+			return false, nil
163
+		}
164
+
165
+		t1 := f1.f.ModTime()
166
+		t2 := f2.f.ModTime()
167
+		if t1.UnixNano() != t2.UnixNano() {
168
+			return false, nil
169
+		}
170
+	}
171
+
172
+	ls1, ok := f1.f.Sys().(*Stat)
173
+	if !ok {
174
+		return false, nil
175
+	}
176
+	ls2, ok := f1.f.Sys().(*Stat)
177
+	if !ok {
178
+		return false, nil
179
+	}
180
+
181
+	return compareStat(ls1, ls2)
182
+}
183
+
184
+// compareStat returns whether the stats are equivalent,
185
+// whether the files are considered the same file, and
186
+// an error
187
+func compareStat(ls1, ls2 *Stat) (bool, error) {
188
+	return ls1.Mode == ls2.Mode && ls1.Uid == ls2.Uid && ls1.Gid == ls2.Gid && ls1.Devmajor == ls2.Devmajor && ls1.Devminor == ls2.Devminor && ls1.Linkname == ls2.Linkname, nil
189
+}
190
+
191
+func nextPath(ctx context.Context, pathC <-chan *currentPath) (*currentPath, error) {
192
+	select {
193
+	case <-ctx.Done():
194
+		return nil, ctx.Err()
195
+	case p := <-pathC:
196
+		return p, nil
197
+	}
198
+}
0 199
new file mode 100644
... ...
@@ -0,0 +1,37 @@
0
+package fsutil
1
+
2
+import (
3
+	"bytes"
4
+	"syscall"
5
+
6
+	"github.com/pkg/errors"
7
+	"github.com/stevvooe/continuity/sysx"
8
+)
9
+
10
+// compareSysStat returns whether the stats are equivalent,
11
+// whether the files are considered the same file, and
12
+// an error
13
+func compareSysStat(s1, s2 interface{}) (bool, error) {
14
+	ls1, ok := s1.(*syscall.Stat_t)
15
+	if !ok {
16
+		return false, nil
17
+	}
18
+	ls2, ok := s2.(*syscall.Stat_t)
19
+	if !ok {
20
+		return false, nil
21
+	}
22
+
23
+	return ls1.Mode == ls2.Mode && ls1.Uid == ls2.Uid && ls1.Gid == ls2.Gid && ls1.Rdev == ls2.Rdev, nil
24
+}
25
+
26
+func compareCapabilities(p1, p2 string) (bool, error) {
27
+	c1, err := sysx.LGetxattr(p1, "security.capability")
28
+	if err != nil && err != syscall.ENODATA {
29
+		return false, errors.Wrapf(err, "failed to get xattr for %s", p1)
30
+	}
31
+	c2, err := sysx.LGetxattr(p2, "security.capability")
32
+	if err != nil && err != syscall.ENODATA {
33
+		return false, errors.Wrapf(err, "failed to get xattr for %s", p2)
34
+	}
35
+	return bytes.Equal(c1, c2), nil
36
+}
0 37
new file mode 100644
... ...
@@ -0,0 +1,353 @@
0
+// +build linux windows
1
+
2
+package fsutil
3
+
4
+import (
5
+	"archive/tar"
6
+	"crypto/sha256"
7
+	"encoding/hex"
8
+	"hash"
9
+	"io"
10
+	"os"
11
+	"path/filepath"
12
+	"strconv"
13
+	"sync"
14
+	"time"
15
+
16
+	"github.com/docker/docker/pkg/archive"
17
+	"github.com/docker/docker/pkg/tarsum"
18
+	"github.com/pkg/errors"
19
+	"golang.org/x/net/context"
20
+	"golang.org/x/sync/errgroup"
21
+)
22
+
23
+type WriteToFunc func(context.Context, string, io.WriteCloser) error
24
+
25
+type DiskWriterOpt struct {
26
+	AsyncDataCb WriteToFunc
27
+	SyncDataCb  WriteToFunc
28
+	NotifyCb    func(ChangeKind, string, os.FileInfo, error) error
29
+}
30
+
31
+type DiskWriter struct {
32
+	opt  DiskWriterOpt
33
+	dest string
34
+
35
+	wg     sync.WaitGroup
36
+	ctx    context.Context
37
+	cancel func()
38
+	eg     *errgroup.Group
39
+}
40
+
41
+func NewDiskWriter(ctx context.Context, dest string, opt DiskWriterOpt) (*DiskWriter, error) {
42
+	if opt.SyncDataCb == nil && opt.AsyncDataCb == nil {
43
+		return nil, errors.New("no data callback specified")
44
+	}
45
+	if opt.SyncDataCb != nil && opt.AsyncDataCb != nil {
46
+		return nil, errors.New("can't specify both sync and async data callbacks")
47
+	}
48
+
49
+	ctx, cancel := context.WithCancel(ctx)
50
+	eg, ctx := errgroup.WithContext(ctx)
51
+
52
+	return &DiskWriter{
53
+		opt:    opt,
54
+		dest:   dest,
55
+		eg:     eg,
56
+		ctx:    ctx,
57
+		cancel: cancel,
58
+	}, nil
59
+}
60
+
61
+func (dw *DiskWriter) Wait(ctx context.Context) error {
62
+	return dw.eg.Wait()
63
+}
64
+
65
+func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err error) (retErr error) {
66
+	if err != nil {
67
+		return err
68
+	}
69
+
70
+	select {
71
+	case <-dw.ctx.Done():
72
+		return dw.ctx.Err()
73
+	default:
74
+	}
75
+
76
+	defer func() {
77
+		if retErr != nil {
78
+			dw.cancel()
79
+		}
80
+	}()
81
+
82
+	p = filepath.FromSlash(p)
83
+
84
+	destPath := filepath.Join(dw.dest, p)
85
+
86
+	if kind == ChangeKindDelete {
87
+		// todo: no need to validate if diff is trusted but is it always?
88
+		if err := os.RemoveAll(destPath); err != nil {
89
+			return errors.Wrapf(err, "failed to remove: %s", destPath)
90
+		}
91
+		if dw.opt.NotifyCb != nil {
92
+			if err := dw.opt.NotifyCb(kind, p, nil, nil); err != nil {
93
+				return err
94
+			}
95
+		}
96
+		return nil
97
+	}
98
+
99
+	stat, ok := fi.Sys().(*Stat)
100
+	if !ok {
101
+		return errors.Errorf("%s invalid change without stat information", p)
102
+	}
103
+
104
+	rename := true
105
+	oldFi, err := os.Lstat(destPath)
106
+	if err != nil {
107
+		if os.IsNotExist(err) {
108
+			if kind != ChangeKindAdd {
109
+				return errors.Wrapf(err, "invalid addition: %s", destPath)
110
+			}
111
+			rename = false
112
+		} else {
113
+			return errors.Wrapf(err, "failed to stat %s", destPath)
114
+		}
115
+	}
116
+
117
+	if oldFi != nil && fi.IsDir() && oldFi.IsDir() {
118
+		if err := rewriteMetadata(destPath, stat); err != nil {
119
+			return errors.Wrapf(err, "error setting dir metadata for %s", destPath)
120
+		}
121
+		return nil
122
+	}
123
+
124
+	newPath := destPath
125
+	if rename {
126
+		newPath = filepath.Join(filepath.Dir(destPath), ".tmp."+nextSuffix())
127
+	}
128
+
129
+	isRegularFile := false
130
+
131
+	switch {
132
+	case fi.IsDir():
133
+		if err := os.Mkdir(newPath, fi.Mode()); err != nil {
134
+			return errors.Wrapf(err, "failed to create dir %s", newPath)
135
+		}
136
+	case fi.Mode()&os.ModeDevice != 0 || fi.Mode()&os.ModeNamedPipe != 0:
137
+		if err := handleTarTypeBlockCharFifo(newPath, stat); err != nil {
138
+			return errors.Wrapf(err, "failed to create device %s", newPath)
139
+		}
140
+	case fi.Mode()&os.ModeSymlink != 0:
141
+		if err := os.Symlink(stat.Linkname, newPath); err != nil {
142
+			return errors.Wrapf(err, "failed to symlink %s", newPath)
143
+		}
144
+	case stat.Linkname != "":
145
+		if err := os.Link(filepath.Join(dw.dest, stat.Linkname), newPath); err != nil {
146
+			return errors.Wrapf(err, "failed to link %s to %s", newPath, stat.Linkname)
147
+		}
148
+	default:
149
+		isRegularFile = true
150
+		file, err := os.OpenFile(newPath, os.O_CREATE|os.O_WRONLY, fi.Mode()) //todo: windows
151
+		if err != nil {
152
+			return errors.Wrapf(err, "failed to create %s", newPath)
153
+		}
154
+		if dw.opt.SyncDataCb != nil {
155
+			if err := dw.processChange(ChangeKindAdd, p, fi, file); err != nil {
156
+				file.Close()
157
+				return err
158
+			}
159
+			break
160
+		}
161
+		if err := file.Close(); err != nil {
162
+			return errors.Wrapf(err, "failed to close %s", newPath)
163
+		}
164
+	}
165
+
166
+	if err := rewriteMetadata(newPath, stat); err != nil {
167
+		return errors.Wrapf(err, "error setting metadata for %s", newPath)
168
+	}
169
+
170
+	if rename {
171
+		if err := os.Rename(newPath, destPath); err != nil {
172
+			return errors.Wrapf(err, "failed to rename %s to %s", newPath, destPath)
173
+		}
174
+	}
175
+
176
+	if isRegularFile {
177
+		if dw.opt.AsyncDataCb != nil {
178
+			dw.requestAsyncFileData(p, destPath, fi)
179
+		}
180
+	} else {
181
+		return dw.processChange(kind, p, fi, nil)
182
+	}
183
+
184
+	return nil
185
+}
186
+
187
+func (dw *DiskWriter) requestAsyncFileData(p, dest string, fi os.FileInfo) {
188
+	// todo: limit worker threads
189
+	dw.eg.Go(func() error {
190
+		if err := dw.processChange(ChangeKindAdd, p, fi, &lazyFileWriter{
191
+			dest: dest,
192
+		}); err != nil {
193
+			return err
194
+		}
195
+		return chtimes(dest, fi.ModTime().UnixNano()) // TODO: parent dirs
196
+	})
197
+}
198
+
199
+func (dw *DiskWriter) processChange(kind ChangeKind, p string, fi os.FileInfo, w io.WriteCloser) error {
200
+	origw := w
201
+	var hw *hashedWriter
202
+	if dw.opt.NotifyCb != nil {
203
+		var err error
204
+		if hw, err = newHashWriter(p, fi, w); err != nil {
205
+			return err
206
+		}
207
+		w = hw
208
+	}
209
+	if origw != nil {
210
+		fn := dw.opt.SyncDataCb
211
+		if fn == nil && dw.opt.AsyncDataCb != nil {
212
+			fn = dw.opt.AsyncDataCb
213
+		}
214
+		if err := fn(dw.ctx, p, w); err != nil {
215
+			return err
216
+		}
217
+	} else {
218
+		if hw != nil {
219
+			hw.Close()
220
+		}
221
+	}
222
+	if hw != nil {
223
+		return dw.opt.NotifyCb(kind, p, hw, nil)
224
+	}
225
+	return nil
226
+}
227
+
228
+type hashedWriter struct {
229
+	os.FileInfo
230
+	io.Writer
231
+	h   hash.Hash
232
+	w   io.WriteCloser
233
+	sum string
234
+}
235
+
236
+func newHashWriter(p string, fi os.FileInfo, w io.WriteCloser) (*hashedWriter, error) {
237
+	h, err := NewTarsumHash(p, fi)
238
+	if err != nil {
239
+		return nil, err
240
+	}
241
+	hw := &hashedWriter{
242
+		FileInfo: fi,
243
+		Writer:   io.MultiWriter(w, h),
244
+		h:        h,
245
+		w:        w,
246
+	}
247
+	return hw, nil
248
+}
249
+
250
+func (hw *hashedWriter) Close() error {
251
+	hw.sum = string(hex.EncodeToString(hw.h.Sum(nil)))
252
+	if hw.w != nil {
253
+		return hw.w.Close()
254
+	}
255
+	return nil
256
+}
257
+
258
+func (hw *hashedWriter) Hash() string {
259
+	return hw.sum
260
+}
261
+
262
+type lazyFileWriter struct {
263
+	dest string
264
+	ctx  context.Context
265
+	f    *os.File
266
+}
267
+
268
+func (lfw *lazyFileWriter) Write(dt []byte) (int, error) {
269
+	if lfw.f == nil {
270
+		file, err := os.OpenFile(lfw.dest, os.O_WRONLY, 0) //todo: windows
271
+		if err != nil {
272
+			return 0, errors.Wrapf(err, "failed to open %s", lfw.dest)
273
+		}
274
+		lfw.f = file
275
+	}
276
+	return lfw.f.Write(dt)
277
+}
278
+
279
+func (lfw *lazyFileWriter) Close() error {
280
+	if lfw.f != nil {
281
+		return lfw.f.Close()
282
+	}
283
+	return nil
284
+}
285
+
286
+func mkdev(major int64, minor int64) uint32 {
287
+	return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff))
288
+}
289
+
290
+// Random number state.
291
+// We generate random temporary file names so that there's a good
292
+// chance the file doesn't exist yet - keeps the number of tries in
293
+// TempFile to a minimum.
294
+var rand uint32
295
+var randmu sync.Mutex
296
+
297
+func reseed() uint32 {
298
+	return uint32(time.Now().UnixNano() + int64(os.Getpid()))
299
+}
300
+
301
+func nextSuffix() string {
302
+	randmu.Lock()
303
+	r := rand
304
+	if r == 0 {
305
+		r = reseed()
306
+	}
307
+	r = r*1664525 + 1013904223 // constants from Numerical Recipes
308
+	rand = r
309
+	randmu.Unlock()
310
+	return strconv.Itoa(int(1e9 + r%1e9))[1:]
311
+}
312
+
313
+func NewTarsumHash(p string, fi os.FileInfo) (hash.Hash, error) {
314
+	stat, ok := fi.Sys().(*Stat)
315
+	link := ""
316
+	if ok {
317
+		link = stat.Linkname
318
+	}
319
+	if fi.IsDir() {
320
+		p += string(os.PathSeparator)
321
+	}
322
+	h, err := archive.FileInfoHeader(p, fi, link)
323
+	if err != nil {
324
+		return nil, err
325
+	}
326
+	h.Name = p
327
+	if ok {
328
+		h.Uid = int(stat.Uid)
329
+		h.Gid = int(stat.Gid)
330
+		h.Linkname = stat.Linkname
331
+		if stat.Xattrs != nil {
332
+			h.Xattrs = make(map[string]string)
333
+			for k, v := range stat.Xattrs {
334
+				h.Xattrs[k] = string(v)
335
+			}
336
+		}
337
+	}
338
+	tsh := &tarsumHash{h: h, Hash: sha256.New()}
339
+	tsh.Reset()
340
+	return tsh, nil
341
+}
342
+
343
+// Reset resets the Hash to its initial state.
344
+func (tsh *tarsumHash) Reset() {
345
+	tsh.Hash.Reset()
346
+	tarsum.WriteV1Header(tsh.h, tsh.Hash)
347
+}
348
+
349
+type tarsumHash struct {
350
+	hash.Hash
351
+	h *tar.Header
352
+}
0 353
new file mode 100644
... ...
@@ -0,0 +1,64 @@
0
+// +build linux
1
+
2
+package fsutil
3
+
4
+import (
5
+	"os"
6
+	"syscall"
7
+
8
+	"github.com/pkg/errors"
9
+	"github.com/stevvooe/continuity/sysx"
10
+	"golang.org/x/sys/unix"
11
+)
12
+
13
+func rewriteMetadata(p string, stat *Stat) error {
14
+	for key, value := range stat.Xattrs {
15
+		sysx.Setxattr(p, key, value, 0)
16
+	}
17
+
18
+	if err := os.Lchown(p, int(stat.Uid), int(stat.Gid)); err != nil {
19
+		return errors.Wrapf(err, "failed to lchown %s", p)
20
+	}
21
+
22
+	if os.FileMode(stat.Mode)&os.ModeSymlink == 0 {
23
+		if err := os.Chmod(p, os.FileMode(stat.Mode)); err != nil {
24
+			return errors.Wrapf(err, "failed to chown %s", p)
25
+		}
26
+	}
27
+
28
+	if err := chtimes(p, stat.ModTime); err != nil {
29
+		return errors.Wrapf(err, "failed to chtimes %s", p)
30
+	}
31
+
32
+	return nil
33
+}
34
+
35
+func chtimes(path string, un int64) error {
36
+	var utimes [2]unix.Timespec
37
+	utimes[0] = unix.NsecToTimespec(un)
38
+	utimes[1] = utimes[0]
39
+
40
+	if err := unix.UtimesNanoAt(unix.AT_FDCWD, path, utimes[0:], unix.AT_SYMLINK_NOFOLLOW); err != nil {
41
+		return errors.Wrap(err, "failed call to UtimesNanoAt")
42
+	}
43
+
44
+	return nil
45
+}
46
+
47
+// handleTarTypeBlockCharFifo is an OS-specific helper function used by
48
+// createTarFile to handle the following types of header: Block; Char; Fifo
49
+func handleTarTypeBlockCharFifo(path string, stat *Stat) error {
50
+	mode := uint32(stat.Mode & 07777)
51
+	if os.FileMode(stat.Mode)&os.ModeCharDevice != 0 {
52
+		mode |= syscall.S_IFCHR
53
+	} else if os.FileMode(stat.Mode)&os.ModeNamedPipe != 0 {
54
+		mode |= syscall.S_IFIFO
55
+	} else {
56
+		mode |= syscall.S_IFBLK
57
+	}
58
+
59
+	if err := syscall.Mknod(path, mode, int(mkdev(stat.Devmajor, stat.Devminor))); err != nil {
60
+		return err
61
+	}
62
+	return nil
63
+}
0 64
new file mode 100644
... ...
@@ -0,0 +1,25 @@
0
+// +build windows
1
+
2
+package fsutil
3
+
4
+import (
5
+	"os"
6
+	"time"
7
+
8
+	"github.com/pkg/errors"
9
+)
10
+
11
+func rewriteMetadata(p string, stat *Stat) error {
12
+	return chtimes(p, stat.ModTime)
13
+}
14
+
15
+func chtimes(path string, un int64) error {
16
+	mtime := time.Unix(0, un)
17
+	return os.Chtimes(path, mtime, mtime)
18
+}
19
+
20
+// handleTarTypeBlockCharFifo is an OS-specific helper function used by
21
+// createTarFile to handle the following types of header: Block; Char; Fifo
22
+func handleTarTypeBlockCharFifo(path string, stat *Stat) error {
23
+	return errors.New("Not implemented on windows")
24
+}
0 25
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+package fsutil
1
+
2
+//go:generate protoc --gogoslick_out=. stat.proto wire.proto
0 3
new file mode 100644
... ...
@@ -0,0 +1,46 @@
0
+package fsutil
1
+
2
+import (
3
+	"os"
4
+
5
+	"github.com/pkg/errors"
6
+)
7
+
8
+// Hardlinks validates that all targets for links were part of the changes
9
+
10
+type Hardlinks struct {
11
+	seenFiles map[string]struct{}
12
+}
13
+
14
+func (v *Hardlinks) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err error) error {
15
+	if err != nil {
16
+		return err
17
+	}
18
+
19
+	if v.seenFiles == nil {
20
+		v.seenFiles = make(map[string]struct{})
21
+	}
22
+
23
+	if kind == ChangeKindDelete {
24
+		return nil
25
+	}
26
+
27
+	stat, ok := fi.Sys().(*Stat)
28
+	if !ok {
29
+		return errors.Errorf("invalid change without stat info: %s", p)
30
+	}
31
+
32
+	if fi.IsDir() || fi.Mode()&os.ModeSymlink != 0 {
33
+		return nil
34
+	}
35
+
36
+	if len(stat.Linkname) > 0 {
37
+		if _, ok := v.seenFiles[stat.Linkname]; !ok {
38
+			return errors.Errorf("invalid link %s to unknown path: %q", p, stat.Linkname)
39
+		}
40
+	} else {
41
+		v.seenFiles[p] = struct{}{}
42
+	}
43
+
44
+	return nil
45
+}
0 46
new file mode 100644
... ...
@@ -0,0 +1,45 @@
0
+Incremental file directory sync tools in golang.
1
+
2
+```
3
+BENCH_FILE_SIZE=10000 ./bench.test --test.bench .
4
+BenchmarkCopyWithTar10-4                	    2000	    995242 ns/op
5
+BenchmarkCopyWithTar50-4                	     300	   4710021 ns/op
6
+BenchmarkCopyWithTar200-4               	     100	  16627260 ns/op
7
+BenchmarkCopyWithTar1000-4              	      20	  60031459 ns/op
8
+BenchmarkCPA10-4                        	    1000	   1678367 ns/op
9
+BenchmarkCPA50-4                        	     500	   3690306 ns/op
10
+BenchmarkCPA200-4                       	     200	   9495066 ns/op
11
+BenchmarkCPA1000-4                      	      50	  29769289 ns/op
12
+BenchmarkDiffCopy10-4                   	    2000	    943889 ns/op
13
+BenchmarkDiffCopy50-4                   	     500	   3285950 ns/op
14
+BenchmarkDiffCopy200-4                  	     200	   8563792 ns/op
15
+BenchmarkDiffCopy1000-4                 	      50	  29511340 ns/op
16
+BenchmarkDiffCopyProto10-4              	    2000	    944615 ns/op
17
+BenchmarkDiffCopyProto50-4              	     500	   3334940 ns/op
18
+BenchmarkDiffCopyProto200-4             	     200	   9420038 ns/op
19
+BenchmarkDiffCopyProto1000-4            	      50	  30632429 ns/op
20
+BenchmarkIncrementalDiffCopy10-4        	    2000	    691993 ns/op
21
+BenchmarkIncrementalDiffCopy50-4        	    1000	   1304253 ns/op
22
+BenchmarkIncrementalDiffCopy200-4       	     500	   3306519 ns/op
23
+BenchmarkIncrementalDiffCopy1000-4      	     200	  10211343 ns/op
24
+BenchmarkIncrementalDiffCopy5000-4      	      20	  55194427 ns/op
25
+BenchmarkIncrementalDiffCopy10000-4     	      20	  91759289 ns/op
26
+BenchmarkIncrementalCopyWithTar10-4     	    2000	   1020258 ns/op
27
+BenchmarkIncrementalCopyWithTar50-4     	     300	   5348786 ns/op
28
+BenchmarkIncrementalCopyWithTar200-4    	     100	  19495000 ns/op
29
+BenchmarkIncrementalCopyWithTar1000-4   	      20	  70338507 ns/op
30
+BenchmarkIncrementalRsync10-4           	      30	  45215754 ns/op
31
+BenchmarkIncrementalRsync50-4           	      30	  45837260 ns/op
32
+BenchmarkIncrementalRsync200-4          	      30	  48780614 ns/op
33
+BenchmarkIncrementalRsync1000-4         	      20	  54801892 ns/op
34
+BenchmarkIncrementalRsync5000-4         	      20	  84782542 ns/op
35
+BenchmarkIncrementalRsync10000-4        	      10	 103355108 ns/op
36
+BenchmarkRsync10-4                      	      30	  46776470 ns/op
37
+BenchmarkRsync50-4                      	      30	  48601555 ns/op
38
+BenchmarkRsync200-4                     	      20	  59642691 ns/op
39
+BenchmarkRsync1000-4                    	      20	 101343010 ns/op
40
+BenchmarkGnuTar10-4                     	     500	   3171448 ns/op
41
+BenchmarkGnuTar50-4                     	     300	   5030296 ns/op
42
+BenchmarkGnuTar200-4                    	     100	  10464313 ns/op
43
+BenchmarkGnuTar1000-4                   	      50	  30375257 ns/op
44
+```
0 45
\ No newline at end of file
1 46
new file mode 100644
... ...
@@ -0,0 +1,210 @@
0
+// +build linux windows
1
+
2
+package fsutil
3
+
4
+import (
5
+	"io"
6
+	"os"
7
+	"sync"
8
+
9
+	"github.com/pkg/errors"
10
+	"golang.org/x/net/context"
11
+	"golang.org/x/sync/errgroup"
12
+)
13
+
14
+func Receive(ctx context.Context, conn Stream, dest string, notifyHashed ChangeFunc) error {
15
+	ctx, cancel := context.WithCancel(context.Background())
16
+	defer cancel()
17
+
18
+	r := &receiver{
19
+		conn:         &syncStream{Stream: conn},
20
+		dest:         dest,
21
+		files:        make(map[string]uint32),
22
+		pipes:        make(map[uint32]io.WriteCloser),
23
+		notifyHashed: notifyHashed,
24
+	}
25
+	return r.run(ctx)
26
+}
27
+
28
+type receiver struct {
29
+	dest    string
30
+	conn    Stream
31
+	files   map[string]uint32
32
+	pipes   map[uint32]io.WriteCloser
33
+	mu      sync.RWMutex
34
+	muPipes sync.RWMutex
35
+
36
+	notifyHashed   ChangeFunc
37
+	orderValidator Validator
38
+	hlValidator    Hardlinks
39
+}
40
+
41
+type dynamicWalker struct {
42
+	walkChan chan *currentPath
43
+	closed   bool
44
+}
45
+
46
+func newDynamicWalker() *dynamicWalker {
47
+	return &dynamicWalker{
48
+		walkChan: make(chan *currentPath, 128),
49
+	}
50
+}
51
+
52
+func (w *dynamicWalker) update(p *currentPath) error {
53
+	if w.closed {
54
+		return errors.New("walker is closed")
55
+	}
56
+	if p == nil {
57
+		close(w.walkChan)
58
+		return nil
59
+	}
60
+	w.walkChan <- p
61
+	return nil
62
+}
63
+
64
+func (w *dynamicWalker) fill(ctx context.Context, pathC chan<- *currentPath) error {
65
+	for {
66
+		select {
67
+		case p, ok := <-w.walkChan:
68
+			if !ok {
69
+				return nil
70
+			}
71
+			pathC <- p
72
+		case <-ctx.Done():
73
+			return ctx.Err()
74
+		}
75
+	}
76
+	return nil
77
+}
78
+
79
+func (r *receiver) run(ctx context.Context) error {
80
+	g, ctx := errgroup.WithContext(ctx)
81
+
82
+	dw, err := NewDiskWriter(ctx, r.dest, DiskWriterOpt{
83
+		AsyncDataCb: r.asyncDataFunc,
84
+		NotifyCb:    r.notifyHashed,
85
+	})
86
+	if err != nil {
87
+		return err
88
+	}
89
+
90
+	w := newDynamicWalker()
91
+
92
+	g.Go(func() error {
93
+		err := doubleWalkDiff(ctx, dw.HandleChange, GetWalkerFn(r.dest), w.fill)
94
+		if err != nil {
95
+			return err
96
+		}
97
+		if err := dw.Wait(ctx); err != nil {
98
+			return err
99
+		}
100
+		r.conn.SendMsg(&Packet{Type: PACKET_FIN})
101
+		return nil
102
+	})
103
+
104
+	g.Go(func() error {
105
+		var i uint32 = 0
106
+
107
+		var p Packet
108
+		for {
109
+			p = Packet{Data: p.Data[:0]}
110
+			if err := r.conn.RecvMsg(&p); err != nil {
111
+				return err
112
+			}
113
+			switch p.Type {
114
+			case PACKET_STAT:
115
+				if p.Stat == nil {
116
+					if err := w.update(nil); err != nil {
117
+						return err
118
+					}
119
+					break
120
+				}
121
+				if fileCanRequestData(os.FileMode(p.Stat.Mode)) {
122
+					r.mu.Lock()
123
+					r.files[p.Stat.Path] = i
124
+					r.mu.Unlock()
125
+				}
126
+				i++
127
+				cp := &currentPath{path: p.Stat.Path, f: &StatInfo{p.Stat}}
128
+				if err := r.orderValidator.HandleChange(ChangeKindAdd, cp.path, cp.f, nil); err != nil {
129
+					return err
130
+				}
131
+				if err := r.hlValidator.HandleChange(ChangeKindAdd, cp.path, cp.f, nil); err != nil {
132
+					return err
133
+				}
134
+				if err := w.update(cp); err != nil {
135
+					return err
136
+				}
137
+			case PACKET_DATA:
138
+				r.muPipes.Lock()
139
+				pw, ok := r.pipes[p.ID]
140
+				r.muPipes.Unlock()
141
+				if !ok {
142
+					return errors.Errorf("invalid file request %s", p.ID)
143
+				}
144
+				if len(p.Data) == 0 {
145
+					if err := pw.Close(); err != nil {
146
+						return err
147
+					}
148
+				} else {
149
+					if _, err := pw.Write(p.Data); err != nil {
150
+						return err
151
+					}
152
+				}
153
+			case PACKET_FIN:
154
+				return nil
155
+			}
156
+		}
157
+	})
158
+	return g.Wait()
159
+}
160
+
161
+func (r *receiver) asyncDataFunc(ctx context.Context, p string, wc io.WriteCloser) error {
162
+	r.mu.Lock()
163
+	id, ok := r.files[p]
164
+	if !ok {
165
+		r.mu.Unlock()
166
+		return errors.Errorf("invalid file request %s", p)
167
+	}
168
+	delete(r.files, p)
169
+	r.mu.Unlock()
170
+
171
+	wwc := newWrappedWriteCloser(wc)
172
+	r.muPipes.Lock()
173
+	r.pipes[id] = wwc
174
+	r.muPipes.Unlock()
175
+	if err := r.conn.SendMsg(&Packet{Type: PACKET_REQ, ID: id}); err != nil {
176
+		return err
177
+	}
178
+	err := wwc.Wait(ctx)
179
+	r.muPipes.Lock()
180
+	delete(r.pipes, id)
181
+	r.muPipes.Unlock()
182
+	return err
183
+}
184
+
185
+type wrappedWriteCloser struct {
186
+	io.WriteCloser
187
+	err  error
188
+	once sync.Once
189
+	done chan struct{}
190
+}
191
+
192
+func newWrappedWriteCloser(wc io.WriteCloser) *wrappedWriteCloser {
193
+	return &wrappedWriteCloser{WriteCloser: wc, done: make(chan struct{})}
194
+}
195
+
196
+func (w *wrappedWriteCloser) Close() error {
197
+	w.err = w.WriteCloser.Close()
198
+	w.once.Do(func() { close(w.done) })
199
+	return w.err
200
+}
201
+
202
+func (w *wrappedWriteCloser) Wait(ctx context.Context) error {
203
+	select {
204
+	case <-ctx.Done():
205
+		return ctx.Err()
206
+	case <-w.done:
207
+		return w.err
208
+	}
209
+}
0 210
new file mode 100644
... ...
@@ -0,0 +1,14 @@
0
+// +build !linux,!windows
1
+
2
+package fsutil
3
+
4
+import (
5
+	"runtime"
6
+
7
+	"github.com/pkg/errors"
8
+	"golang.org/x/net/context"
9
+)
10
+
11
+func Receive(ctx context.Context, conn Stream, dest string, notifyHashed ChangeFunc) error {
12
+	return errors.Errorf("receive is unsupported in %s", runtime.GOOS)
13
+}
0 14
new file mode 100644
... ...
@@ -0,0 +1,201 @@
0
+package fsutil
1
+
2
+import (
3
+	"io"
4
+	"os"
5
+	"path/filepath"
6
+	"sync"
7
+
8
+	"github.com/pkg/errors"
9
+	"golang.org/x/net/context"
10
+	"golang.org/x/sync/errgroup"
11
+)
12
+
13
+var bufPool = sync.Pool{
14
+	New: func() interface{} {
15
+		return make([]byte, 32*1<<10)
16
+	},
17
+}
18
+
19
+type Stream interface {
20
+	RecvMsg(interface{}) error
21
+	SendMsg(m interface{}) error
22
+	Context() context.Context
23
+}
24
+
25
+func Send(ctx context.Context, conn Stream, root string, opt *WalkOpt, progressCb func(int, bool)) error {
26
+	s := &sender{
27
+		conn:         &syncStream{Stream: conn},
28
+		root:         root,
29
+		opt:          opt,
30
+		files:        make(map[uint32]string),
31
+		progressCb:   progressCb,
32
+		sendpipeline: make(chan *sendHandle, 128),
33
+	}
34
+	return s.run(ctx)
35
+}
36
+
37
+type sendHandle struct {
38
+	id   uint32
39
+	path string
40
+}
41
+
42
+type sender struct {
43
+	conn            Stream
44
+	opt             *WalkOpt
45
+	root            string
46
+	files           map[uint32]string
47
+	mu              sync.RWMutex
48
+	progressCb      func(int, bool)
49
+	progressCurrent int
50
+	sendpipeline    chan *sendHandle
51
+}
52
+
53
+func (s *sender) run(ctx context.Context) error {
54
+	g, ctx := errgroup.WithContext(ctx)
55
+
56
+	defer s.updateProgress(0, true)
57
+
58
+	g.Go(func() error {
59
+		return s.walk(ctx)
60
+	})
61
+
62
+	for i := 0; i < 4; i++ {
63
+		g.Go(func() error {
64
+			for h := range s.sendpipeline {
65
+				select {
66
+				case <-ctx.Done():
67
+					return ctx.Err()
68
+				default:
69
+				}
70
+				if err := s.sendFile(h); err != nil {
71
+					return err
72
+				}
73
+			}
74
+			return nil
75
+		})
76
+	}
77
+
78
+	g.Go(func() error {
79
+		defer close(s.sendpipeline)
80
+
81
+		for {
82
+			select {
83
+			case <-ctx.Done():
84
+				return ctx.Err()
85
+			default:
86
+			}
87
+			var p Packet
88
+			if err := s.conn.RecvMsg(&p); err != nil {
89
+				return err
90
+			}
91
+			switch p.Type {
92
+			case PACKET_REQ:
93
+				if err := s.queue(p.ID); err != nil {
94
+					return err
95
+				}
96
+			case PACKET_FIN:
97
+				return s.conn.SendMsg(&Packet{Type: PACKET_FIN})
98
+			}
99
+		}
100
+	})
101
+
102
+	return g.Wait()
103
+}
104
+
105
+func (s *sender) updateProgress(size int, last bool) {
106
+	if s.progressCb != nil {
107
+		s.progressCurrent += size
108
+		s.progressCb(s.progressCurrent, last)
109
+	}
110
+}
111
+
112
+func (s *sender) queue(id uint32) error {
113
+	s.mu.Lock()
114
+	p, ok := s.files[id]
115
+	if !ok {
116
+		s.mu.Unlock()
117
+		return errors.Errorf("invalid file id %d", id)
118
+	}
119
+	delete(s.files, id)
120
+	s.mu.Unlock()
121
+	s.sendpipeline <- &sendHandle{id, p}
122
+	return nil
123
+}
124
+
125
+func (s *sender) sendFile(h *sendHandle) error {
126
+	f, err := os.Open(filepath.Join(s.root, h.path))
127
+	if err == nil {
128
+		buf := bufPool.Get().([]byte)
129
+		defer bufPool.Put(buf)
130
+		if _, err := io.CopyBuffer(&fileSender{sender: s, id: h.id}, f, buf); err != nil {
131
+			return err
132
+		}
133
+	}
134
+	return s.conn.SendMsg(&Packet{ID: h.id, Type: PACKET_DATA})
135
+}
136
+
137
+func (s *sender) walk(ctx context.Context) error {
138
+	var i uint32 = 0
139
+	err := Walk(ctx, s.root, s.opt, func(path string, fi os.FileInfo, err error) error {
140
+		if err != nil {
141
+			return err
142
+		}
143
+		stat, ok := fi.Sys().(*Stat)
144
+		if !ok {
145
+			return errors.Wrapf(err, "invalid fileinfo without stat info: %s", path)
146
+		}
147
+
148
+		p := &Packet{
149
+			Type: PACKET_STAT,
150
+			Stat: stat,
151
+		}
152
+		if fileCanRequestData(os.FileMode(stat.Mode)) {
153
+			s.mu.Lock()
154
+			s.files[i] = stat.Path
155
+			s.mu.Unlock()
156
+		}
157
+		i++
158
+		s.updateProgress(p.Size(), false)
159
+		return errors.Wrapf(s.conn.SendMsg(p), "failed to send stat %s", path)
160
+	})
161
+	if err != nil {
162
+		return err
163
+	}
164
+	return errors.Wrapf(s.conn.SendMsg(&Packet{Type: PACKET_STAT}), "failed to send last stat")
165
+}
166
+
167
+func fileCanRequestData(m os.FileMode) bool {
168
+	// avoid updating this function as it needs to match between sender/receiver.
169
+	// version if needed
170
+	return m&os.ModeType == 0
171
+}
172
+
173
+type fileSender struct {
174
+	sender *sender
175
+	id     uint32
176
+}
177
+
178
+func (fs *fileSender) Write(dt []byte) (int, error) {
179
+	if len(dt) == 0 {
180
+		return 0, nil
181
+	}
182
+	p := &Packet{Type: PACKET_DATA, ID: fs.id, Data: dt}
183
+	if err := fs.sender.conn.SendMsg(p); err != nil {
184
+		return 0, err
185
+	}
186
+	fs.sender.updateProgress(p.Size(), false)
187
+	return len(dt), nil
188
+}
189
+
190
+type syncStream struct {
191
+	Stream
192
+	mu sync.Mutex
193
+}
194
+
195
+func (ss *syncStream) SendMsg(m interface{}) error {
196
+	ss.mu.Lock()
197
+	err := ss.Stream.SendMsg(m)
198
+	ss.mu.Unlock()
199
+	return err
200
+}
0 201
new file mode 100644
... ...
@@ -0,0 +1,931 @@
0
+// Code generated by protoc-gen-gogo.
1
+// source: stat.proto
2
+// DO NOT EDIT!
3
+
4
+/*
5
+	Package fsutil is a generated protocol buffer package.
6
+
7
+	It is generated from these files:
8
+		stat.proto
9
+		wire.proto
10
+
11
+	It has these top-level messages:
12
+		Stat
13
+		Packet
14
+*/
15
+package fsutil
16
+
17
+import proto "github.com/gogo/protobuf/proto"
18
+import fmt "fmt"
19
+import math "math"
20
+
21
+import bytes "bytes"
22
+
23
+import strings "strings"
24
+import reflect "reflect"
25
+import github_com_gogo_protobuf_sortkeys "github.com/gogo/protobuf/sortkeys"
26
+
27
+import io "io"
28
+
29
+// Reference imports to suppress errors if they are not otherwise used.
30
+var _ = proto.Marshal
31
+var _ = fmt.Errorf
32
+var _ = math.Inf
33
+
34
+// This is a compile-time assertion to ensure that this generated file
35
+// is compatible with the proto package it is being compiled against.
36
+// A compilation error at this line likely means your copy of the
37
+// proto package needs to be updated.
38
+const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
39
+
40
+type Stat struct {
41
+	Path    string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
42
+	Mode    uint32 `protobuf:"varint,2,opt,name=mode,proto3" json:"mode,omitempty"`
43
+	Uid     uint32 `protobuf:"varint,3,opt,name=uid,proto3" json:"uid,omitempty"`
44
+	Gid     uint32 `protobuf:"varint,4,opt,name=gid,proto3" json:"gid,omitempty"`
45
+	Size_   int64  `protobuf:"varint,5,opt,name=size,proto3" json:"size,omitempty"`
46
+	ModTime int64  `protobuf:"varint,6,opt,name=modTime,proto3" json:"modTime,omitempty"`
47
+	// int32 typeflag = 7;
48
+	Linkname string            `protobuf:"bytes,7,opt,name=linkname,proto3" json:"linkname,omitempty"`
49
+	Devmajor int64             `protobuf:"varint,8,opt,name=devmajor,proto3" json:"devmajor,omitempty"`
50
+	Devminor int64             `protobuf:"varint,9,opt,name=devminor,proto3" json:"devminor,omitempty"`
51
+	Xattrs   map[string][]byte `protobuf:"bytes,10,rep,name=xattrs" json:"xattrs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
52
+}
53
+
54
+func (m *Stat) Reset()                    { *m = Stat{} }
55
+func (*Stat) ProtoMessage()               {}
56
+func (*Stat) Descriptor() ([]byte, []int) { return fileDescriptorStat, []int{0} }
57
+
58
+func (m *Stat) GetPath() string {
59
+	if m != nil {
60
+		return m.Path
61
+	}
62
+	return ""
63
+}
64
+
65
+func (m *Stat) GetMode() uint32 {
66
+	if m != nil {
67
+		return m.Mode
68
+	}
69
+	return 0
70
+}
71
+
72
+func (m *Stat) GetUid() uint32 {
73
+	if m != nil {
74
+		return m.Uid
75
+	}
76
+	return 0
77
+}
78
+
79
+func (m *Stat) GetGid() uint32 {
80
+	if m != nil {
81
+		return m.Gid
82
+	}
83
+	return 0
84
+}
85
+
86
+func (m *Stat) GetSize_() int64 {
87
+	if m != nil {
88
+		return m.Size_
89
+	}
90
+	return 0
91
+}
92
+
93
+func (m *Stat) GetModTime() int64 {
94
+	if m != nil {
95
+		return m.ModTime
96
+	}
97
+	return 0
98
+}
99
+
100
+func (m *Stat) GetLinkname() string {
101
+	if m != nil {
102
+		return m.Linkname
103
+	}
104
+	return ""
105
+}
106
+
107
+func (m *Stat) GetDevmajor() int64 {
108
+	if m != nil {
109
+		return m.Devmajor
110
+	}
111
+	return 0
112
+}
113
+
114
+func (m *Stat) GetDevminor() int64 {
115
+	if m != nil {
116
+		return m.Devminor
117
+	}
118
+	return 0
119
+}
120
+
121
+func (m *Stat) GetXattrs() map[string][]byte {
122
+	if m != nil {
123
+		return m.Xattrs
124
+	}
125
+	return nil
126
+}
127
+
128
+func init() {
129
+	proto.RegisterType((*Stat)(nil), "fsutil.Stat")
130
+}
131
+func (this *Stat) Equal(that interface{}) bool {
132
+	if that == nil {
133
+		if this == nil {
134
+			return true
135
+		}
136
+		return false
137
+	}
138
+
139
+	that1, ok := that.(*Stat)
140
+	if !ok {
141
+		that2, ok := that.(Stat)
142
+		if ok {
143
+			that1 = &that2
144
+		} else {
145
+			return false
146
+		}
147
+	}
148
+	if that1 == nil {
149
+		if this == nil {
150
+			return true
151
+		}
152
+		return false
153
+	} else if this == nil {
154
+		return false
155
+	}
156
+	if this.Path != that1.Path {
157
+		return false
158
+	}
159
+	if this.Mode != that1.Mode {
160
+		return false
161
+	}
162
+	if this.Uid != that1.Uid {
163
+		return false
164
+	}
165
+	if this.Gid != that1.Gid {
166
+		return false
167
+	}
168
+	if this.Size_ != that1.Size_ {
169
+		return false
170
+	}
171
+	if this.ModTime != that1.ModTime {
172
+		return false
173
+	}
174
+	if this.Linkname != that1.Linkname {
175
+		return false
176
+	}
177
+	if this.Devmajor != that1.Devmajor {
178
+		return false
179
+	}
180
+	if this.Devminor != that1.Devminor {
181
+		return false
182
+	}
183
+	if len(this.Xattrs) != len(that1.Xattrs) {
184
+		return false
185
+	}
186
+	for i := range this.Xattrs {
187
+		if !bytes.Equal(this.Xattrs[i], that1.Xattrs[i]) {
188
+			return false
189
+		}
190
+	}
191
+	return true
192
+}
193
+func (this *Stat) GoString() string {
194
+	if this == nil {
195
+		return "nil"
196
+	}
197
+	s := make([]string, 0, 14)
198
+	s = append(s, "&fsutil.Stat{")
199
+	s = append(s, "Path: "+fmt.Sprintf("%#v", this.Path)+",\n")
200
+	s = append(s, "Mode: "+fmt.Sprintf("%#v", this.Mode)+",\n")
201
+	s = append(s, "Uid: "+fmt.Sprintf("%#v", this.Uid)+",\n")
202
+	s = append(s, "Gid: "+fmt.Sprintf("%#v", this.Gid)+",\n")
203
+	s = append(s, "Size_: "+fmt.Sprintf("%#v", this.Size_)+",\n")
204
+	s = append(s, "ModTime: "+fmt.Sprintf("%#v", this.ModTime)+",\n")
205
+	s = append(s, "Linkname: "+fmt.Sprintf("%#v", this.Linkname)+",\n")
206
+	s = append(s, "Devmajor: "+fmt.Sprintf("%#v", this.Devmajor)+",\n")
207
+	s = append(s, "Devminor: "+fmt.Sprintf("%#v", this.Devminor)+",\n")
208
+	keysForXattrs := make([]string, 0, len(this.Xattrs))
209
+	for k, _ := range this.Xattrs {
210
+		keysForXattrs = append(keysForXattrs, k)
211
+	}
212
+	github_com_gogo_protobuf_sortkeys.Strings(keysForXattrs)
213
+	mapStringForXattrs := "map[string][]byte{"
214
+	for _, k := range keysForXattrs {
215
+		mapStringForXattrs += fmt.Sprintf("%#v: %#v,", k, this.Xattrs[k])
216
+	}
217
+	mapStringForXattrs += "}"
218
+	if this.Xattrs != nil {
219
+		s = append(s, "Xattrs: "+mapStringForXattrs+",\n")
220
+	}
221
+	s = append(s, "}")
222
+	return strings.Join(s, "")
223
+}
224
+func valueToGoStringStat(v interface{}, typ string) string {
225
+	rv := reflect.ValueOf(v)
226
+	if rv.IsNil() {
227
+		return "nil"
228
+	}
229
+	pv := reflect.Indirect(rv).Interface()
230
+	return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv)
231
+}
232
+func (m *Stat) Marshal() (dAtA []byte, err error) {
233
+	size := m.Size()
234
+	dAtA = make([]byte, size)
235
+	n, err := m.MarshalTo(dAtA)
236
+	if err != nil {
237
+		return nil, err
238
+	}
239
+	return dAtA[:n], nil
240
+}
241
+
242
+func (m *Stat) MarshalTo(dAtA []byte) (int, error) {
243
+	var i int
244
+	_ = i
245
+	var l int
246
+	_ = l
247
+	if len(m.Path) > 0 {
248
+		dAtA[i] = 0xa
249
+		i++
250
+		i = encodeVarintStat(dAtA, i, uint64(len(m.Path)))
251
+		i += copy(dAtA[i:], m.Path)
252
+	}
253
+	if m.Mode != 0 {
254
+		dAtA[i] = 0x10
255
+		i++
256
+		i = encodeVarintStat(dAtA, i, uint64(m.Mode))
257
+	}
258
+	if m.Uid != 0 {
259
+		dAtA[i] = 0x18
260
+		i++
261
+		i = encodeVarintStat(dAtA, i, uint64(m.Uid))
262
+	}
263
+	if m.Gid != 0 {
264
+		dAtA[i] = 0x20
265
+		i++
266
+		i = encodeVarintStat(dAtA, i, uint64(m.Gid))
267
+	}
268
+	if m.Size_ != 0 {
269
+		dAtA[i] = 0x28
270
+		i++
271
+		i = encodeVarintStat(dAtA, i, uint64(m.Size_))
272
+	}
273
+	if m.ModTime != 0 {
274
+		dAtA[i] = 0x30
275
+		i++
276
+		i = encodeVarintStat(dAtA, i, uint64(m.ModTime))
277
+	}
278
+	if len(m.Linkname) > 0 {
279
+		dAtA[i] = 0x3a
280
+		i++
281
+		i = encodeVarintStat(dAtA, i, uint64(len(m.Linkname)))
282
+		i += copy(dAtA[i:], m.Linkname)
283
+	}
284
+	if m.Devmajor != 0 {
285
+		dAtA[i] = 0x40
286
+		i++
287
+		i = encodeVarintStat(dAtA, i, uint64(m.Devmajor))
288
+	}
289
+	if m.Devminor != 0 {
290
+		dAtA[i] = 0x48
291
+		i++
292
+		i = encodeVarintStat(dAtA, i, uint64(m.Devminor))
293
+	}
294
+	if len(m.Xattrs) > 0 {
295
+		for k, _ := range m.Xattrs {
296
+			dAtA[i] = 0x52
297
+			i++
298
+			v := m.Xattrs[k]
299
+			byteSize := 0
300
+			if len(v) > 0 {
301
+				byteSize = 1 + len(v) + sovStat(uint64(len(v)))
302
+			}
303
+			mapSize := 1 + len(k) + sovStat(uint64(len(k))) + byteSize
304
+			i = encodeVarintStat(dAtA, i, uint64(mapSize))
305
+			dAtA[i] = 0xa
306
+			i++
307
+			i = encodeVarintStat(dAtA, i, uint64(len(k)))
308
+			i += copy(dAtA[i:], k)
309
+			if len(v) > 0 {
310
+				dAtA[i] = 0x12
311
+				i++
312
+				i = encodeVarintStat(dAtA, i, uint64(len(v)))
313
+				i += copy(dAtA[i:], v)
314
+			}
315
+		}
316
+	}
317
+	return i, nil
318
+}
319
+
320
+func encodeFixed64Stat(dAtA []byte, offset int, v uint64) int {
321
+	dAtA[offset] = uint8(v)
322
+	dAtA[offset+1] = uint8(v >> 8)
323
+	dAtA[offset+2] = uint8(v >> 16)
324
+	dAtA[offset+3] = uint8(v >> 24)
325
+	dAtA[offset+4] = uint8(v >> 32)
326
+	dAtA[offset+5] = uint8(v >> 40)
327
+	dAtA[offset+6] = uint8(v >> 48)
328
+	dAtA[offset+7] = uint8(v >> 56)
329
+	return offset + 8
330
+}
331
+func encodeFixed32Stat(dAtA []byte, offset int, v uint32) int {
332
+	dAtA[offset] = uint8(v)
333
+	dAtA[offset+1] = uint8(v >> 8)
334
+	dAtA[offset+2] = uint8(v >> 16)
335
+	dAtA[offset+3] = uint8(v >> 24)
336
+	return offset + 4
337
+}
338
+func encodeVarintStat(dAtA []byte, offset int, v uint64) int {
339
+	for v >= 1<<7 {
340
+		dAtA[offset] = uint8(v&0x7f | 0x80)
341
+		v >>= 7
342
+		offset++
343
+	}
344
+	dAtA[offset] = uint8(v)
345
+	return offset + 1
346
+}
347
+func (m *Stat) Size() (n int) {
348
+	var l int
349
+	_ = l
350
+	l = len(m.Path)
351
+	if l > 0 {
352
+		n += 1 + l + sovStat(uint64(l))
353
+	}
354
+	if m.Mode != 0 {
355
+		n += 1 + sovStat(uint64(m.Mode))
356
+	}
357
+	if m.Uid != 0 {
358
+		n += 1 + sovStat(uint64(m.Uid))
359
+	}
360
+	if m.Gid != 0 {
361
+		n += 1 + sovStat(uint64(m.Gid))
362
+	}
363
+	if m.Size_ != 0 {
364
+		n += 1 + sovStat(uint64(m.Size_))
365
+	}
366
+	if m.ModTime != 0 {
367
+		n += 1 + sovStat(uint64(m.ModTime))
368
+	}
369
+	l = len(m.Linkname)
370
+	if l > 0 {
371
+		n += 1 + l + sovStat(uint64(l))
372
+	}
373
+	if m.Devmajor != 0 {
374
+		n += 1 + sovStat(uint64(m.Devmajor))
375
+	}
376
+	if m.Devminor != 0 {
377
+		n += 1 + sovStat(uint64(m.Devminor))
378
+	}
379
+	if len(m.Xattrs) > 0 {
380
+		for k, v := range m.Xattrs {
381
+			_ = k
382
+			_ = v
383
+			l = 0
384
+			if len(v) > 0 {
385
+				l = 1 + len(v) + sovStat(uint64(len(v)))
386
+			}
387
+			mapEntrySize := 1 + len(k) + sovStat(uint64(len(k))) + l
388
+			n += mapEntrySize + 1 + sovStat(uint64(mapEntrySize))
389
+		}
390
+	}
391
+	return n
392
+}
393
+
394
+func sovStat(x uint64) (n int) {
395
+	for {
396
+		n++
397
+		x >>= 7
398
+		if x == 0 {
399
+			break
400
+		}
401
+	}
402
+	return n
403
+}
404
+func sozStat(x uint64) (n int) {
405
+	return sovStat(uint64((x << 1) ^ uint64((int64(x) >> 63))))
406
+}
407
+func (this *Stat) String() string {
408
+	if this == nil {
409
+		return "nil"
410
+	}
411
+	keysForXattrs := make([]string, 0, len(this.Xattrs))
412
+	for k, _ := range this.Xattrs {
413
+		keysForXattrs = append(keysForXattrs, k)
414
+	}
415
+	github_com_gogo_protobuf_sortkeys.Strings(keysForXattrs)
416
+	mapStringForXattrs := "map[string][]byte{"
417
+	for _, k := range keysForXattrs {
418
+		mapStringForXattrs += fmt.Sprintf("%v: %v,", k, this.Xattrs[k])
419
+	}
420
+	mapStringForXattrs += "}"
421
+	s := strings.Join([]string{`&Stat{`,
422
+		`Path:` + fmt.Sprintf("%v", this.Path) + `,`,
423
+		`Mode:` + fmt.Sprintf("%v", this.Mode) + `,`,
424
+		`Uid:` + fmt.Sprintf("%v", this.Uid) + `,`,
425
+		`Gid:` + fmt.Sprintf("%v", this.Gid) + `,`,
426
+		`Size_:` + fmt.Sprintf("%v", this.Size_) + `,`,
427
+		`ModTime:` + fmt.Sprintf("%v", this.ModTime) + `,`,
428
+		`Linkname:` + fmt.Sprintf("%v", this.Linkname) + `,`,
429
+		`Devmajor:` + fmt.Sprintf("%v", this.Devmajor) + `,`,
430
+		`Devminor:` + fmt.Sprintf("%v", this.Devminor) + `,`,
431
+		`Xattrs:` + mapStringForXattrs + `,`,
432
+		`}`,
433
+	}, "")
434
+	return s
435
+}
436
+func valueToStringStat(v interface{}) string {
437
+	rv := reflect.ValueOf(v)
438
+	if rv.IsNil() {
439
+		return "nil"
440
+	}
441
+	pv := reflect.Indirect(rv).Interface()
442
+	return fmt.Sprintf("*%v", pv)
443
+}
444
+func (m *Stat) Unmarshal(dAtA []byte) error {
445
+	l := len(dAtA)
446
+	iNdEx := 0
447
+	for iNdEx < l {
448
+		preIndex := iNdEx
449
+		var wire uint64
450
+		for shift := uint(0); ; shift += 7 {
451
+			if shift >= 64 {
452
+				return ErrIntOverflowStat
453
+			}
454
+			if iNdEx >= l {
455
+				return io.ErrUnexpectedEOF
456
+			}
457
+			b := dAtA[iNdEx]
458
+			iNdEx++
459
+			wire |= (uint64(b) & 0x7F) << shift
460
+			if b < 0x80 {
461
+				break
462
+			}
463
+		}
464
+		fieldNum := int32(wire >> 3)
465
+		wireType := int(wire & 0x7)
466
+		if wireType == 4 {
467
+			return fmt.Errorf("proto: Stat: wiretype end group for non-group")
468
+		}
469
+		if fieldNum <= 0 {
470
+			return fmt.Errorf("proto: Stat: illegal tag %d (wire type %d)", fieldNum, wire)
471
+		}
472
+		switch fieldNum {
473
+		case 1:
474
+			if wireType != 2 {
475
+				return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType)
476
+			}
477
+			var stringLen uint64
478
+			for shift := uint(0); ; shift += 7 {
479
+				if shift >= 64 {
480
+					return ErrIntOverflowStat
481
+				}
482
+				if iNdEx >= l {
483
+					return io.ErrUnexpectedEOF
484
+				}
485
+				b := dAtA[iNdEx]
486
+				iNdEx++
487
+				stringLen |= (uint64(b) & 0x7F) << shift
488
+				if b < 0x80 {
489
+					break
490
+				}
491
+			}
492
+			intStringLen := int(stringLen)
493
+			if intStringLen < 0 {
494
+				return ErrInvalidLengthStat
495
+			}
496
+			postIndex := iNdEx + intStringLen
497
+			if postIndex > l {
498
+				return io.ErrUnexpectedEOF
499
+			}
500
+			m.Path = string(dAtA[iNdEx:postIndex])
501
+			iNdEx = postIndex
502
+		case 2:
503
+			if wireType != 0 {
504
+				return fmt.Errorf("proto: wrong wireType = %d for field Mode", wireType)
505
+			}
506
+			m.Mode = 0
507
+			for shift := uint(0); ; shift += 7 {
508
+				if shift >= 64 {
509
+					return ErrIntOverflowStat
510
+				}
511
+				if iNdEx >= l {
512
+					return io.ErrUnexpectedEOF
513
+				}
514
+				b := dAtA[iNdEx]
515
+				iNdEx++
516
+				m.Mode |= (uint32(b) & 0x7F) << shift
517
+				if b < 0x80 {
518
+					break
519
+				}
520
+			}
521
+		case 3:
522
+			if wireType != 0 {
523
+				return fmt.Errorf("proto: wrong wireType = %d for field Uid", wireType)
524
+			}
525
+			m.Uid = 0
526
+			for shift := uint(0); ; shift += 7 {
527
+				if shift >= 64 {
528
+					return ErrIntOverflowStat
529
+				}
530
+				if iNdEx >= l {
531
+					return io.ErrUnexpectedEOF
532
+				}
533
+				b := dAtA[iNdEx]
534
+				iNdEx++
535
+				m.Uid |= (uint32(b) & 0x7F) << shift
536
+				if b < 0x80 {
537
+					break
538
+				}
539
+			}
540
+		case 4:
541
+			if wireType != 0 {
542
+				return fmt.Errorf("proto: wrong wireType = %d for field Gid", wireType)
543
+			}
544
+			m.Gid = 0
545
+			for shift := uint(0); ; shift += 7 {
546
+				if shift >= 64 {
547
+					return ErrIntOverflowStat
548
+				}
549
+				if iNdEx >= l {
550
+					return io.ErrUnexpectedEOF
551
+				}
552
+				b := dAtA[iNdEx]
553
+				iNdEx++
554
+				m.Gid |= (uint32(b) & 0x7F) << shift
555
+				if b < 0x80 {
556
+					break
557
+				}
558
+			}
559
+		case 5:
560
+			if wireType != 0 {
561
+				return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType)
562
+			}
563
+			m.Size_ = 0
564
+			for shift := uint(0); ; shift += 7 {
565
+				if shift >= 64 {
566
+					return ErrIntOverflowStat
567
+				}
568
+				if iNdEx >= l {
569
+					return io.ErrUnexpectedEOF
570
+				}
571
+				b := dAtA[iNdEx]
572
+				iNdEx++
573
+				m.Size_ |= (int64(b) & 0x7F) << shift
574
+				if b < 0x80 {
575
+					break
576
+				}
577
+			}
578
+		case 6:
579
+			if wireType != 0 {
580
+				return fmt.Errorf("proto: wrong wireType = %d for field ModTime", wireType)
581
+			}
582
+			m.ModTime = 0
583
+			for shift := uint(0); ; shift += 7 {
584
+				if shift >= 64 {
585
+					return ErrIntOverflowStat
586
+				}
587
+				if iNdEx >= l {
588
+					return io.ErrUnexpectedEOF
589
+				}
590
+				b := dAtA[iNdEx]
591
+				iNdEx++
592
+				m.ModTime |= (int64(b) & 0x7F) << shift
593
+				if b < 0x80 {
594
+					break
595
+				}
596
+			}
597
+		case 7:
598
+			if wireType != 2 {
599
+				return fmt.Errorf("proto: wrong wireType = %d for field Linkname", wireType)
600
+			}
601
+			var stringLen uint64
602
+			for shift := uint(0); ; shift += 7 {
603
+				if shift >= 64 {
604
+					return ErrIntOverflowStat
605
+				}
606
+				if iNdEx >= l {
607
+					return io.ErrUnexpectedEOF
608
+				}
609
+				b := dAtA[iNdEx]
610
+				iNdEx++
611
+				stringLen |= (uint64(b) & 0x7F) << shift
612
+				if b < 0x80 {
613
+					break
614
+				}
615
+			}
616
+			intStringLen := int(stringLen)
617
+			if intStringLen < 0 {
618
+				return ErrInvalidLengthStat
619
+			}
620
+			postIndex := iNdEx + intStringLen
621
+			if postIndex > l {
622
+				return io.ErrUnexpectedEOF
623
+			}
624
+			m.Linkname = string(dAtA[iNdEx:postIndex])
625
+			iNdEx = postIndex
626
+		case 8:
627
+			if wireType != 0 {
628
+				return fmt.Errorf("proto: wrong wireType = %d for field Devmajor", wireType)
629
+			}
630
+			m.Devmajor = 0
631
+			for shift := uint(0); ; shift += 7 {
632
+				if shift >= 64 {
633
+					return ErrIntOverflowStat
634
+				}
635
+				if iNdEx >= l {
636
+					return io.ErrUnexpectedEOF
637
+				}
638
+				b := dAtA[iNdEx]
639
+				iNdEx++
640
+				m.Devmajor |= (int64(b) & 0x7F) << shift
641
+				if b < 0x80 {
642
+					break
643
+				}
644
+			}
645
+		case 9:
646
+			if wireType != 0 {
647
+				return fmt.Errorf("proto: wrong wireType = %d for field Devminor", wireType)
648
+			}
649
+			m.Devminor = 0
650
+			for shift := uint(0); ; shift += 7 {
651
+				if shift >= 64 {
652
+					return ErrIntOverflowStat
653
+				}
654
+				if iNdEx >= l {
655
+					return io.ErrUnexpectedEOF
656
+				}
657
+				b := dAtA[iNdEx]
658
+				iNdEx++
659
+				m.Devminor |= (int64(b) & 0x7F) << shift
660
+				if b < 0x80 {
661
+					break
662
+				}
663
+			}
664
+		case 10:
665
+			if wireType != 2 {
666
+				return fmt.Errorf("proto: wrong wireType = %d for field Xattrs", wireType)
667
+			}
668
+			var msglen int
669
+			for shift := uint(0); ; shift += 7 {
670
+				if shift >= 64 {
671
+					return ErrIntOverflowStat
672
+				}
673
+				if iNdEx >= l {
674
+					return io.ErrUnexpectedEOF
675
+				}
676
+				b := dAtA[iNdEx]
677
+				iNdEx++
678
+				msglen |= (int(b) & 0x7F) << shift
679
+				if b < 0x80 {
680
+					break
681
+				}
682
+			}
683
+			if msglen < 0 {
684
+				return ErrInvalidLengthStat
685
+			}
686
+			postIndex := iNdEx + msglen
687
+			if postIndex > l {
688
+				return io.ErrUnexpectedEOF
689
+			}
690
+			var keykey uint64
691
+			for shift := uint(0); ; shift += 7 {
692
+				if shift >= 64 {
693
+					return ErrIntOverflowStat
694
+				}
695
+				if iNdEx >= l {
696
+					return io.ErrUnexpectedEOF
697
+				}
698
+				b := dAtA[iNdEx]
699
+				iNdEx++
700
+				keykey |= (uint64(b) & 0x7F) << shift
701
+				if b < 0x80 {
702
+					break
703
+				}
704
+			}
705
+			var stringLenmapkey uint64
706
+			for shift := uint(0); ; shift += 7 {
707
+				if shift >= 64 {
708
+					return ErrIntOverflowStat
709
+				}
710
+				if iNdEx >= l {
711
+					return io.ErrUnexpectedEOF
712
+				}
713
+				b := dAtA[iNdEx]
714
+				iNdEx++
715
+				stringLenmapkey |= (uint64(b) & 0x7F) << shift
716
+				if b < 0x80 {
717
+					break
718
+				}
719
+			}
720
+			intStringLenmapkey := int(stringLenmapkey)
721
+			if intStringLenmapkey < 0 {
722
+				return ErrInvalidLengthStat
723
+			}
724
+			postStringIndexmapkey := iNdEx + intStringLenmapkey
725
+			if postStringIndexmapkey > l {
726
+				return io.ErrUnexpectedEOF
727
+			}
728
+			mapkey := string(dAtA[iNdEx:postStringIndexmapkey])
729
+			iNdEx = postStringIndexmapkey
730
+			if m.Xattrs == nil {
731
+				m.Xattrs = make(map[string][]byte)
732
+			}
733
+			if iNdEx < postIndex {
734
+				var valuekey uint64
735
+				for shift := uint(0); ; shift += 7 {
736
+					if shift >= 64 {
737
+						return ErrIntOverflowStat
738
+					}
739
+					if iNdEx >= l {
740
+						return io.ErrUnexpectedEOF
741
+					}
742
+					b := dAtA[iNdEx]
743
+					iNdEx++
744
+					valuekey |= (uint64(b) & 0x7F) << shift
745
+					if b < 0x80 {
746
+						break
747
+					}
748
+				}
749
+				var mapbyteLen uint64
750
+				for shift := uint(0); ; shift += 7 {
751
+					if shift >= 64 {
752
+						return ErrIntOverflowStat
753
+					}
754
+					if iNdEx >= l {
755
+						return io.ErrUnexpectedEOF
756
+					}
757
+					b := dAtA[iNdEx]
758
+					iNdEx++
759
+					mapbyteLen |= (uint64(b) & 0x7F) << shift
760
+					if b < 0x80 {
761
+						break
762
+					}
763
+				}
764
+				intMapbyteLen := int(mapbyteLen)
765
+				if intMapbyteLen < 0 {
766
+					return ErrInvalidLengthStat
767
+				}
768
+				postbytesIndex := iNdEx + intMapbyteLen
769
+				if postbytesIndex > l {
770
+					return io.ErrUnexpectedEOF
771
+				}
772
+				mapvalue := make([]byte, mapbyteLen)
773
+				copy(mapvalue, dAtA[iNdEx:postbytesIndex])
774
+				iNdEx = postbytesIndex
775
+				m.Xattrs[mapkey] = mapvalue
776
+			} else {
777
+				var mapvalue []byte
778
+				m.Xattrs[mapkey] = mapvalue
779
+			}
780
+			iNdEx = postIndex
781
+		default:
782
+			iNdEx = preIndex
783
+			skippy, err := skipStat(dAtA[iNdEx:])
784
+			if err != nil {
785
+				return err
786
+			}
787
+			if skippy < 0 {
788
+				return ErrInvalidLengthStat
789
+			}
790
+			if (iNdEx + skippy) > l {
791
+				return io.ErrUnexpectedEOF
792
+			}
793
+			iNdEx += skippy
794
+		}
795
+	}
796
+
797
+	if iNdEx > l {
798
+		return io.ErrUnexpectedEOF
799
+	}
800
+	return nil
801
+}
802
+func skipStat(dAtA []byte) (n int, err error) {
803
+	l := len(dAtA)
804
+	iNdEx := 0
805
+	for iNdEx < l {
806
+		var wire uint64
807
+		for shift := uint(0); ; shift += 7 {
808
+			if shift >= 64 {
809
+				return 0, ErrIntOverflowStat
810
+			}
811
+			if iNdEx >= l {
812
+				return 0, io.ErrUnexpectedEOF
813
+			}
814
+			b := dAtA[iNdEx]
815
+			iNdEx++
816
+			wire |= (uint64(b) & 0x7F) << shift
817
+			if b < 0x80 {
818
+				break
819
+			}
820
+		}
821
+		wireType := int(wire & 0x7)
822
+		switch wireType {
823
+		case 0:
824
+			for shift := uint(0); ; shift += 7 {
825
+				if shift >= 64 {
826
+					return 0, ErrIntOverflowStat
827
+				}
828
+				if iNdEx >= l {
829
+					return 0, io.ErrUnexpectedEOF
830
+				}
831
+				iNdEx++
832
+				if dAtA[iNdEx-1] < 0x80 {
833
+					break
834
+				}
835
+			}
836
+			return iNdEx, nil
837
+		case 1:
838
+			iNdEx += 8
839
+			return iNdEx, nil
840
+		case 2:
841
+			var length int
842
+			for shift := uint(0); ; shift += 7 {
843
+				if shift >= 64 {
844
+					return 0, ErrIntOverflowStat
845
+				}
846
+				if iNdEx >= l {
847
+					return 0, io.ErrUnexpectedEOF
848
+				}
849
+				b := dAtA[iNdEx]
850
+				iNdEx++
851
+				length |= (int(b) & 0x7F) << shift
852
+				if b < 0x80 {
853
+					break
854
+				}
855
+			}
856
+			iNdEx += length
857
+			if length < 0 {
858
+				return 0, ErrInvalidLengthStat
859
+			}
860
+			return iNdEx, nil
861
+		case 3:
862
+			for {
863
+				var innerWire uint64
864
+				var start int = iNdEx
865
+				for shift := uint(0); ; shift += 7 {
866
+					if shift >= 64 {
867
+						return 0, ErrIntOverflowStat
868
+					}
869
+					if iNdEx >= l {
870
+						return 0, io.ErrUnexpectedEOF
871
+					}
872
+					b := dAtA[iNdEx]
873
+					iNdEx++
874
+					innerWire |= (uint64(b) & 0x7F) << shift
875
+					if b < 0x80 {
876
+						break
877
+					}
878
+				}
879
+				innerWireType := int(innerWire & 0x7)
880
+				if innerWireType == 4 {
881
+					break
882
+				}
883
+				next, err := skipStat(dAtA[start:])
884
+				if err != nil {
885
+					return 0, err
886
+				}
887
+				iNdEx = start + next
888
+			}
889
+			return iNdEx, nil
890
+		case 4:
891
+			return iNdEx, nil
892
+		case 5:
893
+			iNdEx += 4
894
+			return iNdEx, nil
895
+		default:
896
+			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
897
+		}
898
+	}
899
+	panic("unreachable")
900
+}
901
+
902
+var (
903
+	ErrInvalidLengthStat = fmt.Errorf("proto: negative length found during unmarshaling")
904
+	ErrIntOverflowStat   = fmt.Errorf("proto: integer overflow")
905
+)
906
+
907
+func init() { proto.RegisterFile("stat.proto", fileDescriptorStat) }
908
+
909
+var fileDescriptorStat = []byte{
910
+	// 303 bytes of a gzipped FileDescriptorProto
911
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x4c, 0x91, 0xb1, 0x4e, 0xf3, 0x30,
912
+	0x14, 0x85, 0x73, 0x9b, 0x36, 0x6d, 0xdd, 0xff, 0x97, 0x90, 0xc5, 0x70, 0xd5, 0xc1, 0x8a, 0x98,
913
+	0x32, 0xa0, 0x08, 0xc1, 0x02, 0x8c, 0x48, 0xbc, 0x40, 0x60, 0x60, 0x35, 0xb2, 0x29, 0xa6, 0x4d,
914
+	0x5c, 0x25, 0x4e, 0x45, 0x99, 0x78, 0x04, 0x1e, 0x83, 0xd7, 0x60, 0x63, 0xec, 0xc8, 0x48, 0xcc,
915
+	0xc2, 0xd8, 0x47, 0x40, 0x76, 0xda, 0xc2, 0x76, 0xce, 0x77, 0x7c, 0x65, 0x9d, 0x7b, 0x09, 0xa9,
916
+	0x0c, 0x37, 0xe9, 0xbc, 0xd4, 0x46, 0xd3, 0xe8, 0xae, 0xaa, 0x8d, 0x9a, 0x1d, 0xbc, 0x75, 0x48,
917
+	0xf7, 0xca, 0x70, 0x43, 0x29, 0xe9, 0xce, 0xb9, 0xb9, 0x47, 0x88, 0x21, 0x19, 0x66, 0x5e, 0x3b,
918
+	0x96, 0x6b, 0x21, 0xb1, 0x13, 0x43, 0xf2, 0x3f, 0xf3, 0x9a, 0xee, 0x91, 0xb0, 0x56, 0x02, 0x43,
919
+	0x8f, 0x9c, 0x74, 0x64, 0xa2, 0x04, 0x76, 0x5b, 0x32, 0x51, 0xc2, 0xcd, 0x55, 0xea, 0x49, 0x62,
920
+	0x2f, 0x86, 0x24, 0xcc, 0xbc, 0xa6, 0x48, 0xfa, 0xb9, 0x16, 0xd7, 0x2a, 0x97, 0x18, 0x79, 0xbc,
921
+	0xb5, 0x74, 0x4c, 0x06, 0x33, 0x55, 0x4c, 0x0b, 0x9e, 0x4b, 0xec, 0xfb, 0xdf, 0x77, 0xde, 0x65,
922
+	0x42, 0x2e, 0x72, 0xfe, 0xa0, 0x4b, 0x1c, 0xf8, 0xb1, 0x9d, 0xdf, 0x66, 0xaa, 0xd0, 0x25, 0x0e,
923
+	0x7f, 0x33, 0xe7, 0xe9, 0x11, 0x89, 0x1e, 0xb9, 0x31, 0x65, 0x85, 0x24, 0x0e, 0x93, 0xd1, 0x31,
924
+	0xa6, 0x6d, 0xdf, 0xd4, 0x75, 0x4d, 0x6f, 0x7c, 0x74, 0x59, 0x98, 0x72, 0x99, 0x6d, 0xde, 0x8d,
925
+	0xcf, 0xc8, 0xe8, 0x0f, 0x76, 0xa5, 0xa6, 0x72, 0xb9, 0xd9, 0x86, 0x93, 0x74, 0x9f, 0xf4, 0x16,
926
+	0x7c, 0x56, 0xb7, 0xdb, 0xf8, 0x97, 0xb5, 0xe6, 0xbc, 0x73, 0x0a, 0x17, 0x87, 0xab, 0x86, 0x05,
927
+	0x1f, 0x0d, 0x0b, 0xd6, 0x0d, 0x83, 0x67, 0xcb, 0xe0, 0xd5, 0x32, 0x78, 0xb7, 0x0c, 0x56, 0x96,
928
+	0xc1, 0xa7, 0x65, 0xf0, 0x6d, 0x59, 0xb0, 0xb6, 0x0c, 0x5e, 0xbe, 0x58, 0x70, 0x1b, 0xf9, 0x03,
929
+	0x9c, 0xfc, 0x04, 0x00, 0x00, 0xff, 0xff, 0x19, 0x97, 0x14, 0xf4, 0x8e, 0x01, 0x00, 0x00,
930
+}
0 931
new file mode 100644
... ...
@@ -0,0 +1,17 @@
0
+syntax = "proto3";
1
+
2
+package fsutil;
3
+
4
+message Stat {
5
+  string path = 1;
6
+  uint32 mode = 2;
7
+  uint32 uid = 3;
8
+  uint32 gid = 4;
9
+  int64 size = 5;
10
+  int64 modTime = 6;
11
+  // int32 typeflag = 7;
12
+  string linkname = 7;
13
+  int64 devmajor = 8;
14
+  int64 devminor = 9;
15
+  map<string, bytes> xattrs = 10;
16
+}
0 17
\ No newline at end of file
1 18
new file mode 100644
... ...
@@ -0,0 +1,88 @@
0
+package fsutil
1
+
2
+import (
3
+	"os"
4
+	"path/filepath"
5
+	"sort"
6
+	"strings"
7
+
8
+	"github.com/pkg/errors"
9
+)
10
+
11
+type parent struct {
12
+	dir  string
13
+	last string
14
+}
15
+
16
+type Validator struct {
17
+	parentDirs []parent
18
+}
19
+
20
+func (v *Validator) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err error) (retErr error) {
21
+	if err != nil {
22
+		return err
23
+	}
24
+	// test that all paths are in order and all parent dirs were present
25
+	if v.parentDirs == nil {
26
+		v.parentDirs = make([]parent, 1, 10)
27
+	}
28
+	if p != filepath.Clean(p) {
29
+		return errors.Errorf("invalid unclean path %s", p)
30
+	}
31
+	if filepath.IsAbs(p) {
32
+		return errors.Errorf("abolute path %s not allowed", p)
33
+	}
34
+	dir := filepath.Dir(p)
35
+	base := filepath.Base(p)
36
+	if dir == "." {
37
+		dir = ""
38
+	}
39
+	if dir == ".." || strings.HasPrefix(p, "../") {
40
+		return errors.Errorf("invalid path: %s", p)
41
+	}
42
+
43
+	// find a parent dir from saved records
44
+	i := sort.Search(len(v.parentDirs), func(i int) bool {
45
+		return ComparePath(v.parentDirs[len(v.parentDirs)-1-i].dir, dir) <= 0
46
+	})
47
+	i = len(v.parentDirs) - 1 - i
48
+	if i != len(v.parentDirs)-1 { // skipping back to grandparent
49
+		v.parentDirs = v.parentDirs[:i+1]
50
+	}
51
+
52
+	if dir != v.parentDirs[len(v.parentDirs)-1].dir || v.parentDirs[i].last >= base {
53
+		return errors.Errorf("changes out of order: %q %q", p, filepath.Join(v.parentDirs[i].dir, v.parentDirs[i].last))
54
+	}
55
+	v.parentDirs[i].last = base
56
+	if kind != ChangeKindDelete && fi.IsDir() {
57
+		v.parentDirs = append(v.parentDirs, parent{
58
+			dir:  filepath.Join(dir, base),
59
+			last: "",
60
+		})
61
+	}
62
+	// todo: validate invalid mode combinations
63
+	return err
64
+}
65
+
66
+func ComparePath(p1, p2 string) int {
67
+	// byte-by-byte comparison to be compatible with str<>str
68
+	min := min(len(p1), len(p2))
69
+	for i := 0; i < min; i++ {
70
+		switch {
71
+		case p1[i] == p2[i]:
72
+			continue
73
+		case p2[i] != '/' && p1[i] < p2[i] || p1[i] == '/':
74
+			return -1
75
+		default:
76
+			return 1
77
+		}
78
+	}
79
+	return len(p1) - len(p2)
80
+}
81
+
82
+func min(x, y int) int {
83
+	if x < y {
84
+		return x
85
+	}
86
+	return y
87
+}
0 88
new file mode 100644
... ...
@@ -0,0 +1,170 @@
0
+package fsutil
1
+
2
+import (
3
+	"os"
4
+	"path/filepath"
5
+	"runtime"
6
+	"strings"
7
+	"time"
8
+
9
+	"github.com/docker/docker/pkg/fileutils"
10
+	"github.com/pkg/errors"
11
+	"golang.org/x/net/context"
12
+)
13
+
14
+type WalkOpt struct {
15
+	IncludePaths    []string // todo: remove?
16
+	ExcludePatterns []string
17
+}
18
+
19
+func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) error {
20
+	root, err := filepath.EvalSymlinks(p)
21
+	if err != nil {
22
+		return errors.Wrapf(err, "failed to resolve %s", root)
23
+	}
24
+	fi, err := os.Stat(root)
25
+	if err != nil {
26
+		return errors.Wrapf(err, "failed to stat: %s", root)
27
+	}
28
+	if !fi.IsDir() {
29
+		return errors.Errorf("%s is not a directory", root)
30
+	}
31
+
32
+	var pm *fileutils.PatternMatcher
33
+	if opt != nil && opt.ExcludePatterns != nil {
34
+		pm, err = fileutils.NewPatternMatcher(opt.ExcludePatterns)
35
+		if err != nil {
36
+			return errors.Wrapf(err, "invalid excludepaths %s", opt.ExcludePatterns)
37
+		}
38
+	}
39
+
40
+	seenFiles := make(map[uint64]string)
41
+	return filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
42
+		if err != nil {
43
+			if os.IsNotExist(err) {
44
+				return filepath.SkipDir
45
+			}
46
+			return err
47
+		}
48
+		origpath := path
49
+		path, err = filepath.Rel(root, path)
50
+		if err != nil {
51
+			return err
52
+		}
53
+		// Skip root
54
+		if path == "." {
55
+			return nil
56
+		}
57
+
58
+		if opt != nil {
59
+			if opt.IncludePaths != nil {
60
+				matched := false
61
+				for _, p := range opt.IncludePaths {
62
+					if m, _ := filepath.Match(p, path); m {
63
+						matched = true
64
+						break
65
+					}
66
+				}
67
+				if !matched {
68
+					if fi.IsDir() {
69
+						return filepath.SkipDir
70
+					}
71
+					return nil
72
+				}
73
+			}
74
+			if pm != nil {
75
+				m, err := pm.Matches(path)
76
+				if err != nil {
77
+					return errors.Wrap(err, "failed to match excludepatterns")
78
+				}
79
+
80
+				if m {
81
+					if fi.IsDir() {
82
+						if !pm.Exclusions() {
83
+							return filepath.SkipDir
84
+						}
85
+						dirSlash := path + string(filepath.Separator)
86
+						for _, pat := range pm.Patterns() {
87
+							if !pat.Exclusion() {
88
+								continue
89
+							}
90
+							patStr := pat.String() + string(filepath.Separator)
91
+							if strings.HasPrefix(patStr, dirSlash) {
92
+								goto passedFilter
93
+							}
94
+						}
95
+						return filepath.SkipDir
96
+					}
97
+					return nil
98
+				}
99
+			}
100
+		}
101
+
102
+	passedFilter:
103
+		path = filepath.ToSlash(path)
104
+
105
+		stat := &Stat{
106
+			Path:    path,
107
+			Mode:    uint32(fi.Mode()),
108
+			Size_:   fi.Size(),
109
+			ModTime: fi.ModTime().UnixNano(),
110
+		}
111
+
112
+		setUnixOpt(fi, stat, path, seenFiles)
113
+
114
+		if !fi.IsDir() {
115
+			if fi.Mode()&os.ModeSymlink != 0 {
116
+				link, err := os.Readlink(origpath)
117
+				if err != nil {
118
+					return errors.Wrapf(err, "failed to readlink %s", origpath)
119
+				}
120
+				stat.Linkname = link
121
+			}
122
+		}
123
+		if err := loadXattr(origpath, stat); err != nil {
124
+			return errors.Wrapf(err, "failed to xattr %s", path)
125
+		}
126
+
127
+		if runtime.GOOS == "windows" {
128
+			permPart := stat.Mode & uint32(os.ModePerm)
129
+			noPermPart := stat.Mode &^ uint32(os.ModePerm)
130
+			// Add the x bit: make everything +x from windows
131
+			permPart |= 0111
132
+			permPart &= 0755
133
+			stat.Mode = noPermPart | permPart
134
+		}
135
+
136
+		select {
137
+		case <-ctx.Done():
138
+			return ctx.Err()
139
+		default:
140
+			if err := fn(path, &StatInfo{stat}, nil); err != nil {
141
+				return err
142
+			}
143
+		}
144
+		return nil
145
+	})
146
+}
147
+
148
+type StatInfo struct {
149
+	*Stat
150
+}
151
+
152
+func (s *StatInfo) Name() string {
153
+	return filepath.Base(s.Stat.Path)
154
+}
155
+func (s *StatInfo) Size() int64 {
156
+	return s.Stat.Size_
157
+}
158
+func (s *StatInfo) Mode() os.FileMode {
159
+	return os.FileMode(s.Stat.Mode)
160
+}
161
+func (s *StatInfo) ModTime() time.Time {
162
+	return time.Unix(s.Stat.ModTime/1e9, s.Stat.ModTime%1e9)
163
+}
164
+func (s *StatInfo) IsDir() bool {
165
+	return s.Mode().IsDir()
166
+}
167
+func (s *StatInfo) Sys() interface{} {
168
+	return s.Stat
169
+}
0 170
new file mode 100644
... ...
@@ -0,0 +1,61 @@
0
+// +build !windows
1
+
2
+package fsutil
3
+
4
+import (
5
+	"os"
6
+	"syscall"
7
+
8
+	"github.com/pkg/errors"
9
+	"github.com/stevvooe/continuity/sysx"
10
+)
11
+
12
+func loadXattr(origpath string, stat *Stat) error {
13
+	xattrs, err := sysx.LListxattr(origpath)
14
+	if err != nil {
15
+		return errors.Wrapf(err, "failed to xattr %s", origpath)
16
+	}
17
+	if len(xattrs) > 0 {
18
+		m := make(map[string][]byte)
19
+		for _, key := range xattrs {
20
+			v, err := sysx.LGetxattr(origpath, key)
21
+			if err == nil {
22
+				m[key] = v
23
+			}
24
+		}
25
+		stat.Xattrs = m
26
+	}
27
+	return nil
28
+}
29
+
30
+func setUnixOpt(fi os.FileInfo, stat *Stat, path string, seenFiles map[uint64]string) {
31
+	s := fi.Sys().(*syscall.Stat_t)
32
+
33
+	stat.Uid = s.Uid
34
+	stat.Gid = s.Gid
35
+
36
+	if !fi.IsDir() {
37
+		if s.Mode&syscall.S_IFBLK != 0 ||
38
+			s.Mode&syscall.S_IFCHR != 0 {
39
+			stat.Devmajor = int64(major(uint64(s.Rdev)))
40
+			stat.Devminor = int64(minor(uint64(s.Rdev)))
41
+		}
42
+
43
+		ino := s.Ino
44
+		if s.Nlink > 1 {
45
+			if oldpath, ok := seenFiles[ino]; ok {
46
+				stat.Linkname = oldpath
47
+				stat.Size_ = 0
48
+			}
49
+		}
50
+		seenFiles[ino] = path
51
+	}
52
+}
53
+
54
+func major(device uint64) uint64 {
55
+	return (device >> 8) & 0xfff
56
+}
57
+
58
+func minor(device uint64) uint64 {
59
+	return (device & 0xff) | ((device >> 12) & 0xfff00)
60
+}
0 61
new file mode 100644
... ...
@@ -0,0 +1,14 @@
0
+// +build windows
1
+
2
+package fsutil
3
+
4
+import (
5
+	"os"
6
+)
7
+
8
+func loadXattr(_ string, _ *Stat) error {
9
+	return nil
10
+}
11
+
12
+func setUnixOpt(_ os.FileInfo, _ *Stat, _ string, _ map[uint64]string) {
13
+}
0 14
new file mode 100644
... ...
@@ -0,0 +1,563 @@
0
+// Code generated by protoc-gen-gogo.
1
+// source: wire.proto
2
+// DO NOT EDIT!
3
+
4
+package fsutil
5
+
6
+import proto "github.com/gogo/protobuf/proto"
7
+import fmt "fmt"
8
+import math "math"
9
+
10
+import strconv "strconv"
11
+
12
+import bytes "bytes"
13
+
14
+import strings "strings"
15
+import reflect "reflect"
16
+
17
+import io "io"
18
+
19
+// Reference imports to suppress errors if they are not otherwise used.
20
+var _ = proto.Marshal
21
+var _ = fmt.Errorf
22
+var _ = math.Inf
23
+
24
+type Packet_PacketType int32
25
+
26
+const (
27
+	PACKET_STAT Packet_PacketType = 0
28
+	PACKET_REQ  Packet_PacketType = 1
29
+	PACKET_DATA Packet_PacketType = 2
30
+	PACKET_FIN  Packet_PacketType = 3
31
+)
32
+
33
+var Packet_PacketType_name = map[int32]string{
34
+	0: "PACKET_STAT",
35
+	1: "PACKET_REQ",
36
+	2: "PACKET_DATA",
37
+	3: "PACKET_FIN",
38
+}
39
+var Packet_PacketType_value = map[string]int32{
40
+	"PACKET_STAT": 0,
41
+	"PACKET_REQ":  1,
42
+	"PACKET_DATA": 2,
43
+	"PACKET_FIN":  3,
44
+}
45
+
46
+func (Packet_PacketType) EnumDescriptor() ([]byte, []int) { return fileDescriptorWire, []int{0, 0} }
47
+
48
+type Packet struct {
49
+	Type Packet_PacketType `protobuf:"varint,1,opt,name=type,proto3,enum=fsutil.Packet_PacketType" json:"type,omitempty"`
50
+	Stat *Stat             `protobuf:"bytes,2,opt,name=stat" json:"stat,omitempty"`
51
+	ID   uint32            `protobuf:"varint,3,opt,name=ID,proto3" json:"ID,omitempty"`
52
+	Data []byte            `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
53
+}
54
+
55
+func (m *Packet) Reset()                    { *m = Packet{} }
56
+func (*Packet) ProtoMessage()               {}
57
+func (*Packet) Descriptor() ([]byte, []int) { return fileDescriptorWire, []int{0} }
58
+
59
+func (m *Packet) GetType() Packet_PacketType {
60
+	if m != nil {
61
+		return m.Type
62
+	}
63
+	return PACKET_STAT
64
+}
65
+
66
+func (m *Packet) GetStat() *Stat {
67
+	if m != nil {
68
+		return m.Stat
69
+	}
70
+	return nil
71
+}
72
+
73
+func (m *Packet) GetID() uint32 {
74
+	if m != nil {
75
+		return m.ID
76
+	}
77
+	return 0
78
+}
79
+
80
+func (m *Packet) GetData() []byte {
81
+	if m != nil {
82
+		return m.Data
83
+	}
84
+	return nil
85
+}
86
+
87
+func init() {
88
+	proto.RegisterType((*Packet)(nil), "fsutil.Packet")
89
+	proto.RegisterEnum("fsutil.Packet_PacketType", Packet_PacketType_name, Packet_PacketType_value)
90
+}
91
+func (x Packet_PacketType) String() string {
92
+	s, ok := Packet_PacketType_name[int32(x)]
93
+	if ok {
94
+		return s
95
+	}
96
+	return strconv.Itoa(int(x))
97
+}
98
+func (this *Packet) Equal(that interface{}) bool {
99
+	if that == nil {
100
+		if this == nil {
101
+			return true
102
+		}
103
+		return false
104
+	}
105
+
106
+	that1, ok := that.(*Packet)
107
+	if !ok {
108
+		that2, ok := that.(Packet)
109
+		if ok {
110
+			that1 = &that2
111
+		} else {
112
+			return false
113
+		}
114
+	}
115
+	if that1 == nil {
116
+		if this == nil {
117
+			return true
118
+		}
119
+		return false
120
+	} else if this == nil {
121
+		return false
122
+	}
123
+	if this.Type != that1.Type {
124
+		return false
125
+	}
126
+	if !this.Stat.Equal(that1.Stat) {
127
+		return false
128
+	}
129
+	if this.ID != that1.ID {
130
+		return false
131
+	}
132
+	if !bytes.Equal(this.Data, that1.Data) {
133
+		return false
134
+	}
135
+	return true
136
+}
137
+func (this *Packet) GoString() string {
138
+	if this == nil {
139
+		return "nil"
140
+	}
141
+	s := make([]string, 0, 8)
142
+	s = append(s, "&fsutil.Packet{")
143
+	s = append(s, "Type: "+fmt.Sprintf("%#v", this.Type)+",\n")
144
+	if this.Stat != nil {
145
+		s = append(s, "Stat: "+fmt.Sprintf("%#v", this.Stat)+",\n")
146
+	}
147
+	s = append(s, "ID: "+fmt.Sprintf("%#v", this.ID)+",\n")
148
+	s = append(s, "Data: "+fmt.Sprintf("%#v", this.Data)+",\n")
149
+	s = append(s, "}")
150
+	return strings.Join(s, "")
151
+}
152
+func valueToGoStringWire(v interface{}, typ string) string {
153
+	rv := reflect.ValueOf(v)
154
+	if rv.IsNil() {
155
+		return "nil"
156
+	}
157
+	pv := reflect.Indirect(rv).Interface()
158
+	return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv)
159
+}
160
+func (m *Packet) Marshal() (dAtA []byte, err error) {
161
+	size := m.Size()
162
+	dAtA = make([]byte, size)
163
+	n, err := m.MarshalTo(dAtA)
164
+	if err != nil {
165
+		return nil, err
166
+	}
167
+	return dAtA[:n], nil
168
+}
169
+
170
+func (m *Packet) MarshalTo(dAtA []byte) (int, error) {
171
+	var i int
172
+	_ = i
173
+	var l int
174
+	_ = l
175
+	if m.Type != 0 {
176
+		dAtA[i] = 0x8
177
+		i++
178
+		i = encodeVarintWire(dAtA, i, uint64(m.Type))
179
+	}
180
+	if m.Stat != nil {
181
+		dAtA[i] = 0x12
182
+		i++
183
+		i = encodeVarintWire(dAtA, i, uint64(m.Stat.Size()))
184
+		n1, err := m.Stat.MarshalTo(dAtA[i:])
185
+		if err != nil {
186
+			return 0, err
187
+		}
188
+		i += n1
189
+	}
190
+	if m.ID != 0 {
191
+		dAtA[i] = 0x18
192
+		i++
193
+		i = encodeVarintWire(dAtA, i, uint64(m.ID))
194
+	}
195
+	if len(m.Data) > 0 {
196
+		dAtA[i] = 0x22
197
+		i++
198
+		i = encodeVarintWire(dAtA, i, uint64(len(m.Data)))
199
+		i += copy(dAtA[i:], m.Data)
200
+	}
201
+	return i, nil
202
+}
203
+
204
+func encodeFixed64Wire(dAtA []byte, offset int, v uint64) int {
205
+	dAtA[offset] = uint8(v)
206
+	dAtA[offset+1] = uint8(v >> 8)
207
+	dAtA[offset+2] = uint8(v >> 16)
208
+	dAtA[offset+3] = uint8(v >> 24)
209
+	dAtA[offset+4] = uint8(v >> 32)
210
+	dAtA[offset+5] = uint8(v >> 40)
211
+	dAtA[offset+6] = uint8(v >> 48)
212
+	dAtA[offset+7] = uint8(v >> 56)
213
+	return offset + 8
214
+}
215
+func encodeFixed32Wire(dAtA []byte, offset int, v uint32) int {
216
+	dAtA[offset] = uint8(v)
217
+	dAtA[offset+1] = uint8(v >> 8)
218
+	dAtA[offset+2] = uint8(v >> 16)
219
+	dAtA[offset+3] = uint8(v >> 24)
220
+	return offset + 4
221
+}
222
+func encodeVarintWire(dAtA []byte, offset int, v uint64) int {
223
+	for v >= 1<<7 {
224
+		dAtA[offset] = uint8(v&0x7f | 0x80)
225
+		v >>= 7
226
+		offset++
227
+	}
228
+	dAtA[offset] = uint8(v)
229
+	return offset + 1
230
+}
231
+func (m *Packet) Size() (n int) {
232
+	var l int
233
+	_ = l
234
+	if m.Type != 0 {
235
+		n += 1 + sovWire(uint64(m.Type))
236
+	}
237
+	if m.Stat != nil {
238
+		l = m.Stat.Size()
239
+		n += 1 + l + sovWire(uint64(l))
240
+	}
241
+	if m.ID != 0 {
242
+		n += 1 + sovWire(uint64(m.ID))
243
+	}
244
+	l = len(m.Data)
245
+	if l > 0 {
246
+		n += 1 + l + sovWire(uint64(l))
247
+	}
248
+	return n
249
+}
250
+
251
+func sovWire(x uint64) (n int) {
252
+	for {
253
+		n++
254
+		x >>= 7
255
+		if x == 0 {
256
+			break
257
+		}
258
+	}
259
+	return n
260
+}
261
+func sozWire(x uint64) (n int) {
262
+	return sovWire(uint64((x << 1) ^ uint64((int64(x) >> 63))))
263
+}
264
+func (this *Packet) String() string {
265
+	if this == nil {
266
+		return "nil"
267
+	}
268
+	s := strings.Join([]string{`&Packet{`,
269
+		`Type:` + fmt.Sprintf("%v", this.Type) + `,`,
270
+		`Stat:` + strings.Replace(fmt.Sprintf("%v", this.Stat), "Stat", "Stat", 1) + `,`,
271
+		`ID:` + fmt.Sprintf("%v", this.ID) + `,`,
272
+		`Data:` + fmt.Sprintf("%v", this.Data) + `,`,
273
+		`}`,
274
+	}, "")
275
+	return s
276
+}
277
+func valueToStringWire(v interface{}) string {
278
+	rv := reflect.ValueOf(v)
279
+	if rv.IsNil() {
280
+		return "nil"
281
+	}
282
+	pv := reflect.Indirect(rv).Interface()
283
+	return fmt.Sprintf("*%v", pv)
284
+}
285
+func (m *Packet) Unmarshal(dAtA []byte) error {
286
+	l := len(dAtA)
287
+	iNdEx := 0
288
+	for iNdEx < l {
289
+		preIndex := iNdEx
290
+		var wire uint64
291
+		for shift := uint(0); ; shift += 7 {
292
+			if shift >= 64 {
293
+				return ErrIntOverflowWire
294
+			}
295
+			if iNdEx >= l {
296
+				return io.ErrUnexpectedEOF
297
+			}
298
+			b := dAtA[iNdEx]
299
+			iNdEx++
300
+			wire |= (uint64(b) & 0x7F) << shift
301
+			if b < 0x80 {
302
+				break
303
+			}
304
+		}
305
+		fieldNum := int32(wire >> 3)
306
+		wireType := int(wire & 0x7)
307
+		if wireType == 4 {
308
+			return fmt.Errorf("proto: Packet: wiretype end group for non-group")
309
+		}
310
+		if fieldNum <= 0 {
311
+			return fmt.Errorf("proto: Packet: illegal tag %d (wire type %d)", fieldNum, wire)
312
+		}
313
+		switch fieldNum {
314
+		case 1:
315
+			if wireType != 0 {
316
+				return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
317
+			}
318
+			m.Type = 0
319
+			for shift := uint(0); ; shift += 7 {
320
+				if shift >= 64 {
321
+					return ErrIntOverflowWire
322
+				}
323
+				if iNdEx >= l {
324
+					return io.ErrUnexpectedEOF
325
+				}
326
+				b := dAtA[iNdEx]
327
+				iNdEx++
328
+				m.Type |= (Packet_PacketType(b) & 0x7F) << shift
329
+				if b < 0x80 {
330
+					break
331
+				}
332
+			}
333
+		case 2:
334
+			if wireType != 2 {
335
+				return fmt.Errorf("proto: wrong wireType = %d for field Stat", wireType)
336
+			}
337
+			var msglen int
338
+			for shift := uint(0); ; shift += 7 {
339
+				if shift >= 64 {
340
+					return ErrIntOverflowWire
341
+				}
342
+				if iNdEx >= l {
343
+					return io.ErrUnexpectedEOF
344
+				}
345
+				b := dAtA[iNdEx]
346
+				iNdEx++
347
+				msglen |= (int(b) & 0x7F) << shift
348
+				if b < 0x80 {
349
+					break
350
+				}
351
+			}
352
+			if msglen < 0 {
353
+				return ErrInvalidLengthWire
354
+			}
355
+			postIndex := iNdEx + msglen
356
+			if postIndex > l {
357
+				return io.ErrUnexpectedEOF
358
+			}
359
+			if m.Stat == nil {
360
+				m.Stat = &Stat{}
361
+			}
362
+			if err := m.Stat.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
363
+				return err
364
+			}
365
+			iNdEx = postIndex
366
+		case 3:
367
+			if wireType != 0 {
368
+				return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
369
+			}
370
+			m.ID = 0
371
+			for shift := uint(0); ; shift += 7 {
372
+				if shift >= 64 {
373
+					return ErrIntOverflowWire
374
+				}
375
+				if iNdEx >= l {
376
+					return io.ErrUnexpectedEOF
377
+				}
378
+				b := dAtA[iNdEx]
379
+				iNdEx++
380
+				m.ID |= (uint32(b) & 0x7F) << shift
381
+				if b < 0x80 {
382
+					break
383
+				}
384
+			}
385
+		case 4:
386
+			if wireType != 2 {
387
+				return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType)
388
+			}
389
+			var byteLen int
390
+			for shift := uint(0); ; shift += 7 {
391
+				if shift >= 64 {
392
+					return ErrIntOverflowWire
393
+				}
394
+				if iNdEx >= l {
395
+					return io.ErrUnexpectedEOF
396
+				}
397
+				b := dAtA[iNdEx]
398
+				iNdEx++
399
+				byteLen |= (int(b) & 0x7F) << shift
400
+				if b < 0x80 {
401
+					break
402
+				}
403
+			}
404
+			if byteLen < 0 {
405
+				return ErrInvalidLengthWire
406
+			}
407
+			postIndex := iNdEx + byteLen
408
+			if postIndex > l {
409
+				return io.ErrUnexpectedEOF
410
+			}
411
+			m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...)
412
+			if m.Data == nil {
413
+				m.Data = []byte{}
414
+			}
415
+			iNdEx = postIndex
416
+		default:
417
+			iNdEx = preIndex
418
+			skippy, err := skipWire(dAtA[iNdEx:])
419
+			if err != nil {
420
+				return err
421
+			}
422
+			if skippy < 0 {
423
+				return ErrInvalidLengthWire
424
+			}
425
+			if (iNdEx + skippy) > l {
426
+				return io.ErrUnexpectedEOF
427
+			}
428
+			iNdEx += skippy
429
+		}
430
+	}
431
+
432
+	if iNdEx > l {
433
+		return io.ErrUnexpectedEOF
434
+	}
435
+	return nil
436
+}
437
+func skipWire(dAtA []byte) (n int, err error) {
438
+	l := len(dAtA)
439
+	iNdEx := 0
440
+	for iNdEx < l {
441
+		var wire uint64
442
+		for shift := uint(0); ; shift += 7 {
443
+			if shift >= 64 {
444
+				return 0, ErrIntOverflowWire
445
+			}
446
+			if iNdEx >= l {
447
+				return 0, io.ErrUnexpectedEOF
448
+			}
449
+			b := dAtA[iNdEx]
450
+			iNdEx++
451
+			wire |= (uint64(b) & 0x7F) << shift
452
+			if b < 0x80 {
453
+				break
454
+			}
455
+		}
456
+		wireType := int(wire & 0x7)
457
+		switch wireType {
458
+		case 0:
459
+			for shift := uint(0); ; shift += 7 {
460
+				if shift >= 64 {
461
+					return 0, ErrIntOverflowWire
462
+				}
463
+				if iNdEx >= l {
464
+					return 0, io.ErrUnexpectedEOF
465
+				}
466
+				iNdEx++
467
+				if dAtA[iNdEx-1] < 0x80 {
468
+					break
469
+				}
470
+			}
471
+			return iNdEx, nil
472
+		case 1:
473
+			iNdEx += 8
474
+			return iNdEx, nil
475
+		case 2:
476
+			var length int
477
+			for shift := uint(0); ; shift += 7 {
478
+				if shift >= 64 {
479
+					return 0, ErrIntOverflowWire
480
+				}
481
+				if iNdEx >= l {
482
+					return 0, io.ErrUnexpectedEOF
483
+				}
484
+				b := dAtA[iNdEx]
485
+				iNdEx++
486
+				length |= (int(b) & 0x7F) << shift
487
+				if b < 0x80 {
488
+					break
489
+				}
490
+			}
491
+			iNdEx += length
492
+			if length < 0 {
493
+				return 0, ErrInvalidLengthWire
494
+			}
495
+			return iNdEx, nil
496
+		case 3:
497
+			for {
498
+				var innerWire uint64
499
+				var start int = iNdEx
500
+				for shift := uint(0); ; shift += 7 {
501
+					if shift >= 64 {
502
+						return 0, ErrIntOverflowWire
503
+					}
504
+					if iNdEx >= l {
505
+						return 0, io.ErrUnexpectedEOF
506
+					}
507
+					b := dAtA[iNdEx]
508
+					iNdEx++
509
+					innerWire |= (uint64(b) & 0x7F) << shift
510
+					if b < 0x80 {
511
+						break
512
+					}
513
+				}
514
+				innerWireType := int(innerWire & 0x7)
515
+				if innerWireType == 4 {
516
+					break
517
+				}
518
+				next, err := skipWire(dAtA[start:])
519
+				if err != nil {
520
+					return 0, err
521
+				}
522
+				iNdEx = start + next
523
+			}
524
+			return iNdEx, nil
525
+		case 4:
526
+			return iNdEx, nil
527
+		case 5:
528
+			iNdEx += 4
529
+			return iNdEx, nil
530
+		default:
531
+			return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
532
+		}
533
+	}
534
+	panic("unreachable")
535
+}
536
+
537
+var (
538
+	ErrInvalidLengthWire = fmt.Errorf("proto: negative length found during unmarshaling")
539
+	ErrIntOverflowWire   = fmt.Errorf("proto: integer overflow")
540
+)
541
+
542
+func init() { proto.RegisterFile("wire.proto", fileDescriptorWire) }
543
+
544
+var fileDescriptorWire = []byte{
545
+	// 253 bytes of a gzipped FileDescriptorProto
546
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x2a, 0xcf, 0x2c, 0x4a,
547
+	0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x4b, 0x2b, 0x2e, 0x2d, 0xc9, 0xcc, 0x91, 0xe2,
548
+	0x2a, 0x2e, 0x49, 0x2c, 0x81, 0x88, 0x29, 0x9d, 0x65, 0xe4, 0x62, 0x0b, 0x48, 0x4c, 0xce, 0x4e,
549
+	0x2d, 0x11, 0xd2, 0xe5, 0x62, 0x29, 0xa9, 0x2c, 0x48, 0x95, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x33,
550
+	0x92, 0xd4, 0x83, 0xa8, 0xd6, 0x83, 0xc8, 0x42, 0xa9, 0x90, 0xca, 0x82, 0xd4, 0x20, 0xb0, 0x32,
551
+	0x21, 0x05, 0x2e, 0x16, 0x90, 0x39, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xdc, 0x46, 0x3c, 0x30, 0xe5,
552
+	0xc1, 0x25, 0x89, 0x25, 0x41, 0x60, 0x19, 0x21, 0x3e, 0x2e, 0x26, 0x4f, 0x17, 0x09, 0x66, 0x05,
553
+	0x46, 0x0d, 0xde, 0x20, 0x26, 0x4f, 0x17, 0x21, 0x21, 0x2e, 0x96, 0x94, 0xc4, 0x92, 0x44, 0x09,
554
+	0x16, 0x05, 0x46, 0x0d, 0x9e, 0x20, 0x30, 0x5b, 0xc9, 0x8f, 0x8b, 0x0b, 0x61, 0xb2, 0x10, 0x3f,
555
+	0x17, 0x77, 0x80, 0xa3, 0xb3, 0xb7, 0x6b, 0x48, 0x7c, 0x70, 0x88, 0x63, 0x88, 0x00, 0x83, 0x10,
556
+	0x1f, 0x17, 0x17, 0x54, 0x20, 0xc8, 0x35, 0x50, 0x80, 0x11, 0x49, 0x81, 0x8b, 0x63, 0x88, 0xa3,
557
+	0x00, 0x13, 0x92, 0x02, 0x37, 0x4f, 0x3f, 0x01, 0x66, 0x27, 0x9d, 0x0b, 0x0f, 0xe5, 0x18, 0x6e,
558
+	0x3c, 0x94, 0x63, 0xf8, 0xf0, 0x50, 0x8e, 0xb1, 0xe1, 0x91, 0x1c, 0xe3, 0x8a, 0x47, 0x72, 0x8c,
559
+	0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x8b, 0x47, 0x72,
560
+	0x0c, 0x1f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x90, 0xc4, 0x06, 0x0e, 0x04, 0x63, 0x40,
561
+	0x00, 0x00, 0x00, 0xff, 0xff, 0xda, 0x30, 0x43, 0x22, 0x26, 0x01, 0x00, 0x00,
562
+}
0 563
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+syntax = "proto3";
1
+
2
+package fsutil;
3
+
4
+import "stat.proto";
5
+
6
+message Packet {
7
+  enum PacketType {
8
+      PACKET_STAT = 0;
9
+      PACKET_REQ = 1;
10
+      PACKET_DATA = 2;
11
+      PACKET_FIN = 3;
12
+    }
13
+  PacketType type = 1;
14
+  Stat stat = 2;
15
+  uint32 ID = 3;
16
+  bytes data = 4;
17
+}
0 18
new file mode 100644
... ...
@@ -0,0 +1,67 @@
0
+// Copyright 2016 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 errgroup provides synchronization, error propagation, and Context
5
+// cancelation for groups of goroutines working on subtasks of a common task.
6
+package errgroup
7
+
8
+import (
9
+	"sync"
10
+
11
+	"golang.org/x/net/context"
12
+)
13
+
14
+// A Group is a collection of goroutines working on subtasks that are part of
15
+// the same overall task.
16
+//
17
+// A zero Group is valid and does not cancel on error.
18
+type Group struct {
19
+	cancel func()
20
+
21
+	wg sync.WaitGroup
22
+
23
+	errOnce sync.Once
24
+	err     error
25
+}
26
+
27
+// WithContext returns a new Group and an associated Context derived from ctx.
28
+//
29
+// The derived Context is canceled the first time a function passed to Go
30
+// returns a non-nil error or the first time Wait returns, whichever occurs
31
+// first.
32
+func WithContext(ctx context.Context) (*Group, context.Context) {
33
+	ctx, cancel := context.WithCancel(ctx)
34
+	return &Group{cancel: cancel}, ctx
35
+}
36
+
37
+// Wait blocks until all function calls from the Go method have returned, then
38
+// returns the first non-nil error (if any) from them.
39
+func (g *Group) Wait() error {
40
+	g.wg.Wait()
41
+	if g.cancel != nil {
42
+		g.cancel()
43
+	}
44
+	return g.err
45
+}
46
+
47
+// Go calls the given function in a new goroutine.
48
+//
49
+// The first call to return a non-nil error cancels the group; its error will be
50
+// returned by Wait.
51
+func (g *Group) Go(f func() error) {
52
+	g.wg.Add(1)
53
+
54
+	go func() {
55
+		defer g.wg.Done()
56
+
57
+		if err := f(); err != nil {
58
+			g.errOnce.Do(func() {
59
+				g.err = err
60
+				if g.cancel != nil {
61
+					g.cancel()
62
+				}
63
+			})
64
+		}
65
+	}()
66
+}
0 67
new file mode 100644
... ...
@@ -0,0 +1,111 @@
0
+// Copyright 2013 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 singleflight provides a duplicate function call suppression
5
+// mechanism.
6
+package singleflight // import "golang.org/x/sync/singleflight"
7
+
8
+import "sync"
9
+
10
+// call is an in-flight or completed singleflight.Do call
11
+type call struct {
12
+	wg sync.WaitGroup
13
+
14
+	// These fields are written once before the WaitGroup is done
15
+	// and are only read after the WaitGroup is done.
16
+	val interface{}
17
+	err error
18
+
19
+	// These fields are read and written with the singleflight
20
+	// mutex held before the WaitGroup is done, and are read but
21
+	// not written after the WaitGroup is done.
22
+	dups  int
23
+	chans []chan<- Result
24
+}
25
+
26
+// Group represents a class of work and forms a namespace in
27
+// which units of work can be executed with duplicate suppression.
28
+type Group struct {
29
+	mu sync.Mutex       // protects m
30
+	m  map[string]*call // lazily initialized
31
+}
32
+
33
+// Result holds the results of Do, so they can be passed
34
+// on a channel.
35
+type Result struct {
36
+	Val    interface{}
37
+	Err    error
38
+	Shared bool
39
+}
40
+
41
+// Do executes and returns the results of the given function, making
42
+// sure that only one execution is in-flight for a given key at a
43
+// time. If a duplicate comes in, the duplicate caller waits for the
44
+// original to complete and receives the same results.
45
+// The return value shared indicates whether v was given to multiple callers.
46
+func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
47
+	g.mu.Lock()
48
+	if g.m == nil {
49
+		g.m = make(map[string]*call)
50
+	}
51
+	if c, ok := g.m[key]; ok {
52
+		c.dups++
53
+		g.mu.Unlock()
54
+		c.wg.Wait()
55
+		return c.val, c.err, true
56
+	}
57
+	c := new(call)
58
+	c.wg.Add(1)
59
+	g.m[key] = c
60
+	g.mu.Unlock()
61
+
62
+	g.doCall(c, key, fn)
63
+	return c.val, c.err, c.dups > 0
64
+}
65
+
66
+// DoChan is like Do but returns a channel that will receive the
67
+// results when they are ready.
68
+func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result {
69
+	ch := make(chan Result, 1)
70
+	g.mu.Lock()
71
+	if g.m == nil {
72
+		g.m = make(map[string]*call)
73
+	}
74
+	if c, ok := g.m[key]; ok {
75
+		c.dups++
76
+		c.chans = append(c.chans, ch)
77
+		g.mu.Unlock()
78
+		return ch
79
+	}
80
+	c := &call{chans: []chan<- Result{ch}}
81
+	c.wg.Add(1)
82
+	g.m[key] = c
83
+	g.mu.Unlock()
84
+
85
+	go g.doCall(c, key, fn)
86
+
87
+	return ch
88
+}
89
+
90
+// doCall handles the single call for a key.
91
+func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) {
92
+	c.val, c.err = fn()
93
+	c.wg.Done()
94
+
95
+	g.mu.Lock()
96
+	delete(g.m, key)
97
+	for _, ch := range c.chans {
98
+		ch <- Result{c.val, c.err, c.dups > 0}
99
+	}
100
+	g.mu.Unlock()
101
+}
102
+
103
+// Forget tells the singleflight to forget about a key.  Future calls
104
+// to Do for this key will call the function rather than waiting for
105
+// an earlier call to complete.
106
+func (g *Group) Forget(key string) {
107
+	g.mu.Lock()
108
+	delete(g.m, key)
109
+	g.mu.Unlock()
110
+}