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