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