66
|
1 // Copyright 2018 The Go Authors. All rights reserved.
|
|
2 // Use of this source code is governed by a BSD-style
|
|
3 // license that can be found in the LICENSE file.
|
|
4
|
|
5 //go:build freebsd || netbsd
|
|
6 // +build freebsd netbsd
|
|
7
|
|
8 package unix
|
|
9
|
|
10 import (
|
|
11 "strings"
|
|
12 "unsafe"
|
|
13 )
|
|
14
|
|
15 // Derive extattr namespace and attribute name
|
|
16
|
|
17 func xattrnamespace(fullattr string) (ns int, attr string, err error) {
|
|
18 s := strings.IndexByte(fullattr, '.')
|
|
19 if s == -1 {
|
|
20 return -1, "", ENOATTR
|
|
21 }
|
|
22
|
|
23 namespace := fullattr[0:s]
|
|
24 attr = fullattr[s+1:]
|
|
25
|
|
26 switch namespace {
|
|
27 case "user":
|
|
28 return EXTATTR_NAMESPACE_USER, attr, nil
|
|
29 case "system":
|
|
30 return EXTATTR_NAMESPACE_SYSTEM, attr, nil
|
|
31 default:
|
|
32 return -1, "", ENOATTR
|
|
33 }
|
|
34 }
|
|
35
|
|
36 func initxattrdest(dest []byte, idx int) (d unsafe.Pointer) {
|
|
37 if len(dest) > idx {
|
|
38 return unsafe.Pointer(&dest[idx])
|
|
39 } else {
|
|
40 return unsafe.Pointer(_zero)
|
|
41 }
|
|
42 }
|
|
43
|
|
44 // FreeBSD and NetBSD implement their own syscalls to handle extended attributes
|
|
45
|
|
46 func Getxattr(file string, attr string, dest []byte) (sz int, err error) {
|
|
47 d := initxattrdest(dest, 0)
|
|
48 destsize := len(dest)
|
|
49
|
|
50 nsid, a, err := xattrnamespace(attr)
|
|
51 if err != nil {
|
|
52 return -1, err
|
|
53 }
|
|
54
|
|
55 return ExtattrGetFile(file, nsid, a, uintptr(d), destsize)
|
|
56 }
|
|
57
|
|
58 func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) {
|
|
59 d := initxattrdest(dest, 0)
|
|
60 destsize := len(dest)
|
|
61
|
|
62 nsid, a, err := xattrnamespace(attr)
|
|
63 if err != nil {
|
|
64 return -1, err
|
|
65 }
|
|
66
|
|
67 return ExtattrGetFd(fd, nsid, a, uintptr(d), destsize)
|
|
68 }
|
|
69
|
|
70 func Lgetxattr(link string, attr string, dest []byte) (sz int, err error) {
|
|
71 d := initxattrdest(dest, 0)
|
|
72 destsize := len(dest)
|
|
73
|
|
74 nsid, a, err := xattrnamespace(attr)
|
|
75 if err != nil {
|
|
76 return -1, err
|
|
77 }
|
|
78
|
|
79 return ExtattrGetLink(link, nsid, a, uintptr(d), destsize)
|
|
80 }
|
|
81
|
|
82 // flags are unused on FreeBSD
|
|
83
|
|
84 func Fsetxattr(fd int, attr string, data []byte, flags int) (err error) {
|
|
85 var d unsafe.Pointer
|
|
86 if len(data) > 0 {
|
|
87 d = unsafe.Pointer(&data[0])
|
|
88 }
|
|
89 datasiz := len(data)
|
|
90
|
|
91 nsid, a, err := xattrnamespace(attr)
|
|
92 if err != nil {
|
|
93 return
|
|
94 }
|
|
95
|
|
96 _, err = ExtattrSetFd(fd, nsid, a, uintptr(d), datasiz)
|
|
97 return
|
|
98 }
|
|
99
|
|
100 func Setxattr(file string, attr string, data []byte, flags int) (err error) {
|
|
101 var d unsafe.Pointer
|
|
102 if len(data) > 0 {
|
|
103 d = unsafe.Pointer(&data[0])
|
|
104 }
|
|
105 datasiz := len(data)
|
|
106
|
|
107 nsid, a, err := xattrnamespace(attr)
|
|
108 if err != nil {
|
|
109 return
|
|
110 }
|
|
111
|
|
112 _, err = ExtattrSetFile(file, nsid, a, uintptr(d), datasiz)
|
|
113 return
|
|
114 }
|
|
115
|
|
116 func Lsetxattr(link string, attr string, data []byte, flags int) (err error) {
|
|
117 var d unsafe.Pointer
|
|
118 if len(data) > 0 {
|
|
119 d = unsafe.Pointer(&data[0])
|
|
120 }
|
|
121 datasiz := len(data)
|
|
122
|
|
123 nsid, a, err := xattrnamespace(attr)
|
|
124 if err != nil {
|
|
125 return
|
|
126 }
|
|
127
|
|
128 _, err = ExtattrSetLink(link, nsid, a, uintptr(d), datasiz)
|
|
129 return
|
|
130 }
|
|
131
|
|
132 func Removexattr(file string, attr string) (err error) {
|
|
133 nsid, a, err := xattrnamespace(attr)
|
|
134 if err != nil {
|
|
135 return
|
|
136 }
|
|
137
|
|
138 err = ExtattrDeleteFile(file, nsid, a)
|
|
139 return
|
|
140 }
|
|
141
|
|
142 func Fremovexattr(fd int, attr string) (err error) {
|
|
143 nsid, a, err := xattrnamespace(attr)
|
|
144 if err != nil {
|
|
145 return
|
|
146 }
|
|
147
|
|
148 err = ExtattrDeleteFd(fd, nsid, a)
|
|
149 return
|
|
150 }
|
|
151
|
|
152 func Lremovexattr(link string, attr string) (err error) {
|
|
153 nsid, a, err := xattrnamespace(attr)
|
|
154 if err != nil {
|
|
155 return
|
|
156 }
|
|
157
|
|
158 err = ExtattrDeleteLink(link, nsid, a)
|
|
159 return
|
|
160 }
|
|
161
|
|
162 func Listxattr(file string, dest []byte) (sz int, err error) {
|
|
163 destsiz := len(dest)
|
|
164
|
|
165 // FreeBSD won't allow you to list xattrs from multiple namespaces
|
68
|
166 s, pos := 0, 0
|
66
|
167 for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
|
68
|
168 stmp, e := ListxattrNS(file, nsid, dest[pos:])
|
66
|
169
|
|
170 /* Errors accessing system attrs are ignored so that
|
|
171 * we can implement the Linux-like behavior of omitting errors that
|
|
172 * we don't have read permissions on
|
|
173 *
|
|
174 * Linux will still error if we ask for user attributes on a file that
|
|
175 * we don't have read permissions on, so don't ignore those errors
|
|
176 */
|
68
|
177 if e != nil {
|
|
178 if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
|
|
179 continue
|
|
180 }
|
66
|
181 return s, e
|
|
182 }
|
|
183
|
|
184 s += stmp
|
68
|
185 pos = s
|
|
186 if pos > destsiz {
|
|
187 pos = destsiz
|
66
|
188 }
|
68
|
189 }
|
|
190
|
|
191 return s, nil
|
|
192 }
|
|
193
|
|
194 func ListxattrNS(file string, nsid int, dest []byte) (sz int, err error) {
|
|
195 d := initxattrdest(dest, 0)
|
|
196 destsiz := len(dest)
|
|
197
|
|
198 s, e := ExtattrListFile(file, nsid, uintptr(d), destsiz)
|
|
199 if e != nil {
|
|
200 return 0, err
|
66
|
201 }
|
|
202
|
|
203 return s, nil
|
|
204 }
|
|
205
|
|
206 func Flistxattr(fd int, dest []byte) (sz int, err error) {
|
|
207 destsiz := len(dest)
|
|
208
|
68
|
209 s, pos := 0, 0
|
66
|
210 for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
|
68
|
211 stmp, e := FlistxattrNS(fd, nsid, dest[pos:])
|
|
212
|
|
213 if e != nil {
|
|
214 if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
|
|
215 continue
|
|
216 }
|
66
|
217 return s, e
|
|
218 }
|
|
219
|
|
220 s += stmp
|
68
|
221 pos = s
|
|
222 if pos > destsiz {
|
|
223 pos = destsiz
|
66
|
224 }
|
68
|
225 }
|
|
226
|
|
227 return s, nil
|
|
228 }
|
|
229
|
|
230 func FlistxattrNS(fd int, nsid int, dest []byte) (sz int, err error) {
|
|
231 d := initxattrdest(dest, 0)
|
|
232 destsiz := len(dest)
|
|
233
|
|
234 s, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz)
|
|
235 if e != nil {
|
|
236 return 0, err
|
66
|
237 }
|
|
238
|
|
239 return s, nil
|
|
240 }
|
|
241
|
|
242 func Llistxattr(link string, dest []byte) (sz int, err error) {
|
|
243 destsiz := len(dest)
|
|
244
|
68
|
245 s, pos := 0, 0
|
66
|
246 for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
|
68
|
247 stmp, e := LlistxattrNS(link, nsid, dest[pos:])
|
|
248
|
|
249 if e != nil {
|
|
250 if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
|
|
251 continue
|
|
252 }
|
66
|
253 return s, e
|
|
254 }
|
|
255
|
|
256 s += stmp
|
68
|
257 pos = s
|
|
258 if pos > destsiz {
|
|
259 pos = destsiz
|
66
|
260 }
|
|
261 }
|
|
262
|
|
263 return s, nil
|
|
264 }
|
68
|
265
|
|
266 func LlistxattrNS(link string, nsid int, dest []byte) (sz int, err error) {
|
|
267 d := initxattrdest(dest, 0)
|
|
268 destsiz := len(dest)
|
|
269
|
|
270 s, e := ExtattrListLink(link, nsid, uintptr(d), destsiz)
|
|
271 if e != nil {
|
|
272 return 0, err
|
|
273 }
|
|
274
|
|
275 return s, nil
|
|
276 }
|