github.com/etecs-ru/go-sys-wineventlog@v0.0.0-20210227233244-4c3abb794018/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 // +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 }