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 d := initxattrdest(dest, 0)
|
|
164 destsiz := len(dest)
|
|
165
|
|
166 // FreeBSD won't allow you to list xattrs from multiple namespaces
|
|
167 s := 0
|
|
168 for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
|
|
169 stmp, e := ExtattrListFile(file, nsid, uintptr(d), destsiz)
|
|
170
|
|
171 /* Errors accessing system attrs are ignored so that
|
|
172 * we can implement the Linux-like behavior of omitting errors that
|
|
173 * we don't have read permissions on
|
|
174 *
|
|
175 * Linux will still error if we ask for user attributes on a file that
|
|
176 * we don't have read permissions on, so don't ignore those errors
|
|
177 */
|
|
178 if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
|
|
179 continue
|
|
180 } else if e != nil {
|
|
181 return s, e
|
|
182 }
|
|
183
|
|
184 s += stmp
|
|
185 destsiz -= s
|
|
186 if destsiz < 0 {
|
|
187 destsiz = 0
|
|
188 }
|
|
189 d = initxattrdest(dest, s)
|
|
190 }
|
|
191
|
|
192 return s, nil
|
|
193 }
|
|
194
|
|
195 func Flistxattr(fd int, dest []byte) (sz int, err error) {
|
|
196 d := initxattrdest(dest, 0)
|
|
197 destsiz := len(dest)
|
|
198
|
|
199 s := 0
|
|
200 for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
|
|
201 stmp, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz)
|
|
202 if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
|
|
203 continue
|
|
204 } else if e != nil {
|
|
205 return s, e
|
|
206 }
|
|
207
|
|
208 s += stmp
|
|
209 destsiz -= s
|
|
210 if destsiz < 0 {
|
|
211 destsiz = 0
|
|
212 }
|
|
213 d = initxattrdest(dest, s)
|
|
214 }
|
|
215
|
|
216 return s, nil
|
|
217 }
|
|
218
|
|
219 func Llistxattr(link string, dest []byte) (sz int, err error) {
|
|
220 d := initxattrdest(dest, 0)
|
|
221 destsiz := len(dest)
|
|
222
|
|
223 s := 0
|
|
224 for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
|
|
225 stmp, e := ExtattrListLink(link, nsid, uintptr(d), destsiz)
|
|
226 if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
|
|
227 continue
|
|
228 } else if e != nil {
|
|
229 return s, e
|
|
230 }
|
|
231
|
|
232 s += stmp
|
|
233 destsiz -= s
|
|
234 if destsiz < 0 {
|
|
235 destsiz = 0
|
|
236 }
|
|
237 d = initxattrdest(dest, s)
|
|
238 }
|
|
239
|
|
240 return s, nil
|
|
241 }
|