Update upstream source from tag 'upstream/0.4.2'
Update to upstream version '0.4.2'
with Debian dir 555980d83926107bb9615b4af10aa10b5dc9b1d7
Felix Lechner
3 years ago
17 | 17 | _cgo_gotypes.go |
18 | 18 | _cgo_export.* |
19 | 19 | |
20 | # Dependencies | |
21 | go.sum | |
22 | ||
23 | 20 | _testmain.go |
24 | 21 | |
25 | 22 | *.exe |
8 | 8 | echo "Building for FreeBSD..." |
9 | 9 | GOOS=freebsd go build |
10 | 10 | |
11 | echo "Building for Windows...(dummy)" | |
12 | GOOS=windows go build | |
13 | ||
11 | 14 | echo "Running tests..." |
12 | 15 | go vet |
13 | 16 | go test -v -race -coverprofile=coverage.txt -covermode=atomic |
1 | 1 | sudo: false |
2 | 2 | |
3 | 3 | go: |
4 | - "1.11" | |
4 | - "1.15.x" | |
5 | - "1.14.x" | |
5 | 6 | |
6 | 7 | os: |
7 | 8 | - linux |
8 | 9 | - osx |
10 | - windows | |
9 | 11 | |
10 | 12 | before_install: |
13 | - export GO111MODULE=on | |
11 | 14 | - go version |
12 | - export GO111MODULE=on | |
13 | 15 | - go get golang.org/x/tools/cmd/goimports |
14 | 16 | |
15 | 17 | install: |
17 | 19 | |
18 | 20 | script: |
19 | 21 | - ./.travis.sh |
20 | - diff <(goimports -d .) <(printf "") | |
22 | # goimports on windows gives false positives | |
23 | - if [[ "${TRAVIS_OS_NAME}" != "windows" ]]; then diff <(goimports -d .) <(printf ""); fi | |
21 | 24 | |
22 | 25 | after_success: |
23 | 26 | - bash <(curl -s https://codecov.io/bash) |
5 | 5 | |
6 | 6 | xattr |
7 | 7 | ===== |
8 | Extended attribute support for Go (linux + darwin + freebsd). | |
8 | Extended attribute support for Go (linux + darwin + freebsd + netbsd). | |
9 | 9 | |
10 | 10 | "Extended attributes are name:value pairs associated permanently with files and directories, similar to the environment strings associated with a process. An attribute may be defined or undefined. If it is defined, its value may be empty or non-empty." [See more...](https://en.wikipedia.org/wiki/Extended_file_attributes) |
11 | 11 | |
12 | `SetWithFlags` allows to additionally pass system flags to be forwarded to the underlying calls, FreeBSD does not support this and the parameter will be ignored. | |
12 | `SetWithFlags` allows to additionally pass system flags to be forwarded to the underlying calls. FreeBSD and NetBSD do not support this and the parameter will be ignored. | |
13 | 13 | |
14 | 14 | The `L` variants of all functions (`LGet/LSet/...`) are identical to `Get/Set/...` except that they |
15 | 15 | do not reference a symlink that appears at the end of a path. See |
0 | 0 | module github.com/pkg/xattr |
1 | 1 | |
2 | require golang.org/x/sys v0.0.0-20181021155630-eda9bb28ed51 | |
2 | go 1.14 | |
3 | ||
4 | require golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 |
0 | golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7OwF73JPWsQLvH1z2Kxck= | |
1 | golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
0 | // +build freebsd netbsd | |
1 | ||
2 | package xattr | |
3 | ||
4 | import ( | |
5 | "os" | |
6 | "syscall" | |
7 | "unsafe" | |
8 | ) | |
9 | ||
10 | const ( | |
11 | // XATTR_SUPPORTED will be true if the current platform is supported | |
12 | XATTR_SUPPORTED = true | |
13 | ||
14 | EXTATTR_NAMESPACE_USER = 1 | |
15 | ||
16 | // ENOATTR is not exported by the syscall package on Linux, because it is | |
17 | // an alias for ENODATA. We export it here so it is available on all | |
18 | // our supported platforms. | |
19 | ENOATTR = syscall.ENOATTR | |
20 | ) | |
21 | ||
22 | func getxattr(path string, name string, data []byte) (int, error) { | |
23 | return sysGet(syscall.SYS_EXTATTR_GET_FILE, path, name, data) | |
24 | } | |
25 | ||
26 | func lgetxattr(path string, name string, data []byte) (int, error) { | |
27 | return sysGet(syscall.SYS_EXTATTR_GET_LINK, path, name, data) | |
28 | } | |
29 | ||
30 | func fgetxattr(f *os.File, name string, data []byte) (int, error) { | |
31 | return getxattr(f.Name(), name, data) | |
32 | } | |
33 | ||
34 | // sysGet is called by getxattr and lgetxattr with the appropriate syscall | |
35 | // number. This works because syscalls have the same signature and return | |
36 | // values. | |
37 | func sysGet(syscallNum uintptr, path string, name string, data []byte) (int, error) { | |
38 | ptr, nbytes := bytePtrFromSlice(data) | |
39 | /* | |
40 | ssize_t extattr_get_file( | |
41 | const char *path, | |
42 | int attrnamespace, | |
43 | const char *attrname, | |
44 | void *data, | |
45 | size_t nbytes); | |
46 | ||
47 | ssize_t extattr_get_link( | |
48 | const char *path, | |
49 | int attrnamespace, | |
50 | const char *attrname, | |
51 | void *data, | |
52 | size_t nbytes); | |
53 | */ | |
54 | r0, _, err := syscall.Syscall6(syscallNum, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), | |
55 | EXTATTR_NAMESPACE_USER, uintptr(unsafe.Pointer(syscall.StringBytePtr(name))), | |
56 | uintptr(unsafe.Pointer(ptr)), uintptr(nbytes), 0) | |
57 | if err != syscall.Errno(0) { | |
58 | return int(r0), err | |
59 | } | |
60 | return int(r0), nil | |
61 | } | |
62 | ||
63 | func setxattr(path string, name string, data []byte, flags int) error { | |
64 | return sysSet(syscall.SYS_EXTATTR_SET_FILE, path, name, data) | |
65 | } | |
66 | ||
67 | func lsetxattr(path string, name string, data []byte, flags int) error { | |
68 | return sysSet(syscall.SYS_EXTATTR_SET_LINK, path, name, data) | |
69 | } | |
70 | ||
71 | func fsetxattr(f *os.File, name string, data []byte, flags int) error { | |
72 | return setxattr(f.Name(), name, data, flags) | |
73 | } | |
74 | ||
75 | // sysSet is called by setxattr and lsetxattr with the appropriate syscall | |
76 | // number. This works because syscalls have the same signature and return | |
77 | // values. | |
78 | func sysSet(syscallNum uintptr, path string, name string, data []byte) error { | |
79 | ptr, nbytes := bytePtrFromSlice(data) | |
80 | /* | |
81 | ssize_t extattr_set_file( | |
82 | const char *path, | |
83 | int attrnamespace, | |
84 | const char *attrname, | |
85 | const void *data, | |
86 | size_t nbytes | |
87 | ); | |
88 | ||
89 | ssize_t extattr_set_link( | |
90 | const char *path, | |
91 | int attrnamespace, | |
92 | const char *attrname, | |
93 | const void *data, | |
94 | size_t nbytes | |
95 | ); | |
96 | */ | |
97 | r0, _, err := syscall.Syscall6(syscallNum, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), | |
98 | EXTATTR_NAMESPACE_USER, uintptr(unsafe.Pointer(syscall.StringBytePtr(name))), | |
99 | uintptr(unsafe.Pointer(ptr)), uintptr(nbytes), 0) | |
100 | if err != syscall.Errno(0) { | |
101 | return err | |
102 | } | |
103 | if int(r0) != nbytes { | |
104 | return syscall.E2BIG | |
105 | } | |
106 | return nil | |
107 | } | |
108 | ||
109 | func removexattr(path string, name string) error { | |
110 | return sysRemove(syscall.SYS_EXTATTR_DELETE_FILE, path, name) | |
111 | } | |
112 | ||
113 | func lremovexattr(path string, name string) error { | |
114 | return sysRemove(syscall.SYS_EXTATTR_DELETE_LINK, path, name) | |
115 | } | |
116 | ||
117 | func fremovexattr(f *os.File, name string) error { | |
118 | return removexattr(f.Name(), name) | |
119 | } | |
120 | ||
121 | // sysSet is called by removexattr and lremovexattr with the appropriate syscall | |
122 | // number. This works because syscalls have the same signature and return | |
123 | // values. | |
124 | func sysRemove(syscallNum uintptr, path string, name string) error { | |
125 | /* | |
126 | int extattr_delete_file( | |
127 | const char *path, | |
128 | int attrnamespace, | |
129 | const char *attrname | |
130 | ); | |
131 | ||
132 | int extattr_delete_link( | |
133 | const char *path, | |
134 | int attrnamespace, | |
135 | const char *attrname | |
136 | ); | |
137 | */ | |
138 | _, _, err := syscall.Syscall(syscallNum, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), | |
139 | EXTATTR_NAMESPACE_USER, uintptr(unsafe.Pointer(syscall.StringBytePtr(name))), | |
140 | ) | |
141 | if err != syscall.Errno(0) { | |
142 | return err | |
143 | } | |
144 | return nil | |
145 | } | |
146 | ||
147 | func listxattr(path string, data []byte) (int, error) { | |
148 | return sysList(syscall.SYS_EXTATTR_LIST_FILE, path, data) | |
149 | } | |
150 | ||
151 | func llistxattr(path string, data []byte) (int, error) { | |
152 | return sysList(syscall.SYS_EXTATTR_LIST_LINK, path, data) | |
153 | } | |
154 | ||
155 | func flistxattr(f *os.File, data []byte) (int, error) { | |
156 | return listxattr(f.Name(), data) | |
157 | } | |
158 | ||
159 | // sysSet is called by listxattr and llistxattr with the appropriate syscall | |
160 | // number. This works because syscalls have the same signature and return | |
161 | // values. | |
162 | func sysList(syscallNum uintptr, path string, data []byte) (int, error) { | |
163 | ptr, nbytes := bytePtrFromSlice(data) | |
164 | /* | |
165 | ssize_t extattr_list_file( | |
166 | const char *path, | |
167 | int attrnamespace, | |
168 | void *data, | |
169 | size_t nbytes | |
170 | ); | |
171 | ||
172 | ssize_t extattr_list_link( | |
173 | const char *path, | |
174 | int attrnamespace, | |
175 | void *data, | |
176 | size_t nbytes | |
177 | ); | |
178 | */ | |
179 | r0, _, err := syscall.Syscall6(syscallNum, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), | |
180 | EXTATTR_NAMESPACE_USER, uintptr(unsafe.Pointer(ptr)), uintptr(nbytes), 0, 0) | |
181 | if err != syscall.Errno(0) { | |
182 | return int(r0), err | |
183 | } | |
184 | return int(r0), nil | |
185 | } | |
186 | ||
187 | // stringsFromByteSlice converts a sequence of attributes to a []string. | |
188 | // On FreeBSD, each entry consists of a single byte containing the length | |
189 | // of the attribute name, followed by the attribute name. | |
190 | // The name is _not_ terminated by NULL. | |
191 | func stringsFromByteSlice(buf []byte) (result []string) { | |
192 | index := 0 | |
193 | for index < len(buf) { | |
194 | next := index + 1 + int(buf[index]) | |
195 | result = append(result, string(buf[index+1:next])) | |
196 | index = next | |
197 | } | |
198 | return | |
199 | } |
4 | 4 | import ( |
5 | 5 | "os" |
6 | 6 | "syscall" |
7 | "unsafe" | |
8 | 7 | |
9 | 8 | "golang.org/x/sys/unix" |
10 | 9 | ) |
11 | 10 | |
12 | 11 | // See https://opensource.apple.com/source/xnu/xnu-1504.15.3/bsd/sys/xattr.h.auto.html |
13 | 12 | const ( |
13 | // XATTR_SUPPORTED will be true if the current platform is supported | |
14 | XATTR_SUPPORTED = true | |
15 | ||
14 | 16 | XATTR_NOFOLLOW = 0x0001 |
15 | 17 | XATTR_CREATE = 0x0002 |
16 | 18 | XATTR_REPLACE = 0x0004 |
29 | 31 | } |
30 | 32 | |
31 | 33 | func lgetxattr(path string, name string, data []byte) (int, error) { |
32 | value, size := bytePtrFromSlice(data) | |
33 | /* | |
34 | ssize_t getxattr( | |
35 | const char *path, | |
36 | const char *name, | |
37 | void *value, | |
38 | size_t size, | |
39 | u_int32_t position, | |
40 | int options | |
41 | ) | |
42 | */ | |
43 | r0, _, err := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), | |
44 | uintptr(unsafe.Pointer(syscall.StringBytePtr(name))), uintptr(unsafe.Pointer(value)), uintptr(size), 0, XATTR_NOFOLLOW) | |
45 | if err != syscall.Errno(0) { | |
46 | return int(r0), err | |
47 | } | |
48 | return int(r0), nil | |
34 | return unix.Lgetxattr(path, name, data) | |
49 | 35 | } |
50 | 36 | |
51 | 37 | func fgetxattr(f *os.File, name string, data []byte) (int, error) { |
57 | 43 | } |
58 | 44 | |
59 | 45 | func lsetxattr(path string, name string, data []byte, flags int) error { |
60 | return unix.Setxattr(path, name, data, flags|XATTR_NOFOLLOW) | |
46 | return unix.Lsetxattr(path, name, data, flags) | |
61 | 47 | } |
62 | 48 | |
63 | 49 | func fsetxattr(f *os.File, name string, data []byte, flags int) error { |
69 | 55 | } |
70 | 56 | |
71 | 57 | func lremovexattr(path string, name string) error { |
72 | /* | |
73 | int removexattr( | |
74 | const char *path, | |
75 | const char *name, | |
76 | int options | |
77 | ); | |
78 | */ | |
79 | _, _, err := syscall.Syscall(syscall.SYS_REMOVEXATTR, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), | |
80 | uintptr(unsafe.Pointer(syscall.StringBytePtr(name))), XATTR_NOFOLLOW) | |
81 | if err != syscall.Errno(0) { | |
82 | return err | |
83 | } | |
84 | return nil | |
58 | return unix.Lremovexattr(path, name) | |
85 | 59 | } |
86 | 60 | |
87 | 61 | func fremovexattr(f *os.File, name string) error { |
93 | 67 | } |
94 | 68 | |
95 | 69 | func llistxattr(path string, data []byte) (int, error) { |
96 | name, size := bytePtrFromSlice(data) | |
97 | /* | |
98 | ssize_t listxattr( | |
99 | const char *path, | |
100 | char *name, | |
101 | size_t size, | |
102 | int options | |
103 | ); | |
104 | */ | |
105 | r0, _, err := syscall.Syscall6(syscall.SYS_LISTXATTR, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), | |
106 | uintptr(unsafe.Pointer(name)), uintptr(size), XATTR_NOFOLLOW, 0, 0) | |
107 | if err != syscall.Errno(0) { | |
108 | return int(r0), err | |
109 | } | |
110 | return int(r0), nil | |
70 | return unix.Llistxattr(path, data) | |
111 | 71 | } |
112 | 72 | |
113 | 73 | func flistxattr(f *os.File, data []byte) (int, error) { |
0 | // +build freebsd | |
1 | ||
2 | package xattr | |
3 | ||
4 | import ( | |
5 | "os" | |
6 | "syscall" | |
7 | "unsafe" | |
8 | ) | |
9 | ||
10 | const ( | |
11 | EXTATTR_NAMESPACE_USER = 1 | |
12 | ||
13 | // ENOATTR is not exported by the syscall package on Linux, because it is | |
14 | // an alias for ENODATA. We export it here so it is available on all | |
15 | // our supported platforms. | |
16 | ENOATTR = syscall.ENOATTR | |
17 | ) | |
18 | ||
19 | func getxattr(path string, name string, data []byte) (int, error) { | |
20 | return sysGet(syscall.SYS_EXTATTR_GET_FILE, path, name, data) | |
21 | } | |
22 | ||
23 | func lgetxattr(path string, name string, data []byte) (int, error) { | |
24 | return sysGet(syscall.SYS_EXTATTR_GET_LINK, path, name, data) | |
25 | } | |
26 | ||
27 | func fgetxattr(f *os.File, name string, data []byte) (int, error) { | |
28 | return getxattr(f.Name(), name, data) | |
29 | } | |
30 | ||
31 | // sysGet is called by getxattr and lgetxattr with the appropriate syscall | |
32 | // number. This works because syscalls have the same signature and return | |
33 | // values. | |
34 | func sysGet(syscallNum uintptr, path string, name string, data []byte) (int, error) { | |
35 | ptr, nbytes := bytePtrFromSlice(data) | |
36 | /* | |
37 | ssize_t extattr_get_file( | |
38 | const char *path, | |
39 | int attrnamespace, | |
40 | const char *attrname, | |
41 | void *data, | |
42 | size_t nbytes); | |
43 | ||
44 | ssize_t extattr_get_link( | |
45 | const char *path, | |
46 | int attrnamespace, | |
47 | const char *attrname, | |
48 | void *data, | |
49 | size_t nbytes); | |
50 | */ | |
51 | r0, _, err := syscall.Syscall6(syscallNum, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), | |
52 | EXTATTR_NAMESPACE_USER, uintptr(unsafe.Pointer(syscall.StringBytePtr(name))), | |
53 | uintptr(unsafe.Pointer(ptr)), uintptr(nbytes), 0) | |
54 | if err != syscall.Errno(0) { | |
55 | return int(r0), err | |
56 | } | |
57 | return int(r0), nil | |
58 | } | |
59 | ||
60 | func setxattr(path string, name string, data []byte, flags int) error { | |
61 | return sysSet(syscall.SYS_EXTATTR_SET_FILE, path, name, data) | |
62 | } | |
63 | ||
64 | func lsetxattr(path string, name string, data []byte, flags int) error { | |
65 | return sysSet(syscall.SYS_EXTATTR_SET_LINK, path, name, data) | |
66 | } | |
67 | ||
68 | func fsetxattr(f *os.File, name string, data []byte, flags int) error { | |
69 | return setxattr(f.Name(), name, data, flags) | |
70 | } | |
71 | ||
72 | // sysSet is called by setxattr and lsetxattr with the appropriate syscall | |
73 | // number. This works because syscalls have the same signature and return | |
74 | // values. | |
75 | func sysSet(syscallNum uintptr, path string, name string, data []byte) error { | |
76 | ptr, nbytes := bytePtrFromSlice(data) | |
77 | /* | |
78 | ssize_t extattr_set_file( | |
79 | const char *path, | |
80 | int attrnamespace, | |
81 | const char *attrname, | |
82 | const void *data, | |
83 | size_t nbytes | |
84 | ); | |
85 | ||
86 | ssize_t extattr_set_link( | |
87 | const char *path, | |
88 | int attrnamespace, | |
89 | const char *attrname, | |
90 | const void *data, | |
91 | size_t nbytes | |
92 | ); | |
93 | */ | |
94 | r0, _, err := syscall.Syscall6(syscallNum, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), | |
95 | EXTATTR_NAMESPACE_USER, uintptr(unsafe.Pointer(syscall.StringBytePtr(name))), | |
96 | uintptr(unsafe.Pointer(ptr)), uintptr(nbytes), 0) | |
97 | if err != syscall.Errno(0) { | |
98 | return err | |
99 | } | |
100 | if int(r0) != nbytes { | |
101 | return syscall.E2BIG | |
102 | } | |
103 | return nil | |
104 | } | |
105 | ||
106 | func removexattr(path string, name string) error { | |
107 | return sysRemove(syscall.SYS_EXTATTR_DELETE_FILE, path, name) | |
108 | } | |
109 | ||
110 | func lremovexattr(path string, name string) error { | |
111 | return sysRemove(syscall.SYS_EXTATTR_DELETE_LINK, path, name) | |
112 | } | |
113 | ||
114 | func fremovexattr(f *os.File, name string) error { | |
115 | return removexattr(f.Name(), name) | |
116 | } | |
117 | ||
118 | // sysSet is called by removexattr and lremovexattr with the appropriate syscall | |
119 | // number. This works because syscalls have the same signature and return | |
120 | // values. | |
121 | func sysRemove(syscallNum uintptr, path string, name string) error { | |
122 | /* | |
123 | int extattr_delete_file( | |
124 | const char *path, | |
125 | int attrnamespace, | |
126 | const char *attrname | |
127 | ); | |
128 | ||
129 | int extattr_delete_link( | |
130 | const char *path, | |
131 | int attrnamespace, | |
132 | const char *attrname | |
133 | ); | |
134 | */ | |
135 | _, _, err := syscall.Syscall(syscallNum, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), | |
136 | EXTATTR_NAMESPACE_USER, uintptr(unsafe.Pointer(syscall.StringBytePtr(name))), | |
137 | ) | |
138 | if err != syscall.Errno(0) { | |
139 | return err | |
140 | } | |
141 | return nil | |
142 | } | |
143 | ||
144 | func listxattr(path string, data []byte) (int, error) { | |
145 | return sysList(syscall.SYS_EXTATTR_LIST_FILE, path, data) | |
146 | } | |
147 | ||
148 | func llistxattr(path string, data []byte) (int, error) { | |
149 | return sysList(syscall.SYS_EXTATTR_LIST_LINK, path, data) | |
150 | } | |
151 | ||
152 | func flistxattr(f *os.File, data []byte) (int, error) { | |
153 | return listxattr(f.Name(), data) | |
154 | } | |
155 | ||
156 | // sysSet is called by listxattr and llistxattr with the appropriate syscall | |
157 | // number. This works because syscalls have the same signature and return | |
158 | // values. | |
159 | func sysList(syscallNum uintptr, path string, data []byte) (int, error) { | |
160 | ptr, nbytes := bytePtrFromSlice(data) | |
161 | /* | |
162 | ssize_t extattr_list_file( | |
163 | const char *path, | |
164 | int attrnamespace, | |
165 | void *data, | |
166 | size_t nbytes | |
167 | ); | |
168 | ||
169 | ssize_t extattr_list_link( | |
170 | const char *path, | |
171 | int attrnamespace, | |
172 | void *data, | |
173 | size_t nbytes | |
174 | ); | |
175 | */ | |
176 | r0, _, err := syscall.Syscall6(syscallNum, uintptr(unsafe.Pointer(syscall.StringBytePtr(path))), | |
177 | EXTATTR_NAMESPACE_USER, uintptr(unsafe.Pointer(ptr)), uintptr(nbytes), 0, 0) | |
178 | if err != syscall.Errno(0) { | |
179 | return int(r0), err | |
180 | } | |
181 | return int(r0), nil | |
182 | } | |
183 | ||
184 | // stringsFromByteSlice converts a sequence of attributes to a []string. | |
185 | // On FreeBSD, each entry consists of a single byte containing the length | |
186 | // of the attribute name, followed by the attribute name. | |
187 | // The name is _not_ terminated by NULL. | |
188 | func stringsFromByteSlice(buf []byte) (result []string) { | |
189 | index := 0 | |
190 | for index < len(buf) { | |
191 | next := index + 1 + int(buf[index]) | |
192 | result = append(result, string(buf[index+1:next])) | |
193 | index = next | |
194 | } | |
195 | return | |
196 | } |
2 | 2 | package xattr |
3 | 3 | |
4 | 4 | import ( |
5 | "errors" | |
5 | 6 | "os" |
6 | 7 | "syscall" |
7 | 8 | |
9 | 10 | ) |
10 | 11 | |
11 | 12 | const ( |
13 | // XATTR_SUPPORTED will be true if the current platform is supported | |
14 | XATTR_SUPPORTED = true | |
15 | ||
12 | 16 | XATTR_CREATE = unix.XATTR_CREATE |
13 | 17 | XATTR_REPLACE = unix.XATTR_REPLACE |
14 | 18 | |
18 | 22 | ENOATTR = syscall.ENODATA |
19 | 23 | ) |
20 | 24 | |
25 | // On Linux, FUSE and CIFS filesystems can return EINTR for interrupted system | |
26 | // calls. This function works around this by retrying system calls until they | |
27 | // stop returning EINTR. | |
28 | // | |
29 | // See https://github.com/golang/go/commit/6b420169d798c7ebe733487b56ea5c3fa4aab5ce. | |
30 | func ignoringEINTR(fn func() error) (err error) { | |
31 | for { | |
32 | err = fn() | |
33 | if !errors.Is(err, unix.EINTR) { | |
34 | break | |
35 | } | |
36 | } | |
37 | return err | |
38 | } | |
39 | ||
21 | 40 | func getxattr(path string, name string, data []byte) (int, error) { |
22 | return unix.Getxattr(path, name, data) | |
41 | var r int | |
42 | err := ignoringEINTR(func() (err error) { | |
43 | r, err = unix.Getxattr(path, name, data) | |
44 | return err | |
45 | }) | |
46 | return r, err | |
23 | 47 | } |
24 | 48 | |
25 | 49 | func lgetxattr(path string, name string, data []byte) (int, error) { |
26 | return unix.Lgetxattr(path, name, data) | |
50 | var r int | |
51 | err := ignoringEINTR(func() (err error) { | |
52 | r, err = unix.Lgetxattr(path, name, data) | |
53 | return err | |
54 | }) | |
55 | return r, err | |
27 | 56 | } |
28 | 57 | |
29 | 58 | func fgetxattr(f *os.File, name string, data []byte) (int, error) { |
30 | return unix.Fgetxattr(int(f.Fd()), name, data) | |
59 | var r int | |
60 | err := ignoringEINTR(func() (err error) { | |
61 | r, err = unix.Fgetxattr(int(f.Fd()), name, data) | |
62 | return err | |
63 | }) | |
64 | return r, err | |
31 | 65 | } |
32 | 66 | |
33 | 67 | func setxattr(path string, name string, data []byte, flags int) error { |
34 | return unix.Setxattr(path, name, data, flags) | |
68 | return ignoringEINTR(func() (err error) { | |
69 | return unix.Setxattr(path, name, data, flags) | |
70 | }) | |
35 | 71 | } |
36 | 72 | |
37 | 73 | func lsetxattr(path string, name string, data []byte, flags int) error { |
38 | return unix.Lsetxattr(path, name, data, flags) | |
74 | return ignoringEINTR(func() (err error) { | |
75 | return unix.Lsetxattr(path, name, data, flags) | |
76 | }) | |
39 | 77 | } |
40 | 78 | |
41 | 79 | func fsetxattr(f *os.File, name string, data []byte, flags int) error { |
42 | return unix.Fsetxattr(int(f.Fd()), name, data, flags) | |
80 | return ignoringEINTR(func() (err error) { | |
81 | return unix.Fsetxattr(int(f.Fd()), name, data, flags) | |
82 | }) | |
43 | 83 | } |
44 | 84 | |
45 | 85 | func removexattr(path string, name string) error { |
46 | return unix.Removexattr(path, name) | |
86 | return ignoringEINTR(func() (err error) { | |
87 | return unix.Removexattr(path, name) | |
88 | }) | |
47 | 89 | } |
48 | 90 | |
49 | 91 | func lremovexattr(path string, name string) error { |
50 | return unix.Lremovexattr(path, name) | |
92 | return ignoringEINTR(func() (err error) { | |
93 | return unix.Lremovexattr(path, name) | |
94 | }) | |
51 | 95 | } |
52 | 96 | |
53 | 97 | func fremovexattr(f *os.File, name string) error { |
54 | return unix.Fremovexattr(int(f.Fd()), name) | |
98 | return ignoringEINTR(func() (err error) { | |
99 | return unix.Fremovexattr(int(f.Fd()), name) | |
100 | }) | |
55 | 101 | } |
56 | 102 | |
57 | 103 | func listxattr(path string, data []byte) (int, error) { |
58 | return unix.Listxattr(path, data) | |
104 | var r int | |
105 | err := ignoringEINTR(func() (err error) { | |
106 | r, err = unix.Listxattr(path, data) | |
107 | return err | |
108 | }) | |
109 | return r, err | |
59 | 110 | } |
60 | 111 | |
61 | 112 | func llistxattr(path string, data []byte) (int, error) { |
62 | return unix.Llistxattr(path, data) | |
113 | var r int | |
114 | err := ignoringEINTR(func() (err error) { | |
115 | r, err = unix.Llistxattr(path, data) | |
116 | return err | |
117 | }) | |
118 | return r, err | |
63 | 119 | } |
64 | 120 | |
65 | 121 | func flistxattr(f *os.File, data []byte) (int, error) { |
66 | return unix.Flistxattr(int(f.Fd()), data) | |
122 | var r int | |
123 | err := ignoringEINTR(func() (err error) { | |
124 | r, err = unix.Flistxattr(int(f.Fd()), data) | |
125 | return err | |
126 | }) | |
127 | return r, err | |
67 | 128 | } |
68 | 129 | |
69 | 130 | // stringsFromByteSlice converts a sequence of attributes to a []string. |
0 | package xattr | |
1 | ||
2 | import ( | |
3 | "syscall" | |
4 | "testing" | |
5 | ) | |
6 | ||
7 | func TestIgnoringEINTR(t *testing.T) { | |
8 | eintrs := 100 | |
9 | err := ignoringEINTR(func() error { | |
10 | if eintrs == 0 { | |
11 | return nil | |
12 | } | |
13 | eintrs-- | |
14 | return syscall.EINTR | |
15 | }) | |
16 | ||
17 | if err != nil { | |
18 | t.Fatal(err) | |
19 | } | |
20 | } |
0 | // +build !linux,!freebsd,!netbsd,!darwin | |
1 | ||
2 | package xattr | |
3 | ||
4 | import ( | |
5 | "os" | |
6 | ) | |
7 | ||
8 | // XATTR_SUPPORTED will be true if the current platform is supported | |
9 | const XATTR_SUPPORTED = false | |
10 | ||
11 | func getxattr(path string, name string, data []byte) (int, error) { | |
12 | return 0, nil | |
13 | } | |
14 | ||
15 | func lgetxattr(path string, name string, data []byte) (int, error) { | |
16 | return 0, nil | |
17 | } | |
18 | ||
19 | func fgetxattr(f *os.File, name string, data []byte) (int, error) { | |
20 | return 0, nil | |
21 | } | |
22 | ||
23 | func setxattr(path string, name string, data []byte, flags int) error { | |
24 | return nil | |
25 | } | |
26 | ||
27 | func lsetxattr(path string, name string, data []byte, flags int) error { | |
28 | return nil | |
29 | } | |
30 | ||
31 | func fsetxattr(f *os.File, name string, data []byte, flags int) error { | |
32 | return nil | |
33 | } | |
34 | ||
35 | func removexattr(path string, name string) error { | |
36 | return nil | |
37 | } | |
38 | ||
39 | func lremovexattr(path string, name string) error { | |
40 | return nil | |
41 | } | |
42 | ||
43 | func fremovexattr(f *os.File, name string) error { | |
44 | return nil | |
45 | } | |
46 | ||
47 | func listxattr(path string, data []byte) (int, error) { | |
48 | return 0, nil | |
49 | } | |
50 | ||
51 | func llistxattr(path string, data []byte) (int, error) { | |
52 | return 0, nil | |
53 | } | |
54 | ||
55 | func flistxattr(f *os.File, data []byte) (int, error) { | |
56 | return 0, nil | |
57 | } | |
58 | ||
59 | // dummy | |
60 | func stringsFromByteSlice(buf []byte) (result []string) { | |
61 | return []string{} | |
62 | } |