github.com/Andyfoo/golang/x/sys@v0.0.0-20190901054642-57c1bf301704/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 // +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 } else { 39 return unsafe.Pointer(_zero) 40 } 41 } 42 43 // FreeBSD and NetBSD implement their own syscalls to handle extended attributes 44 45 func 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 57 func 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 69 func 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 83 func Fsetxattr(fd int, attr string, data []byte, flags int) (err error) { 84 var d unsafe.Pointer 85 if len(data) > 0 { 86 d = unsafe.Pointer(&data[0]) 87 } 88 datasiz := len(data) 89 90 nsid, a, err := xattrnamespace(attr) 91 if err != nil { 92 return 93 } 94 95 _, err = ExtattrSetFd(fd, nsid, a, uintptr(d), datasiz) 96 return 97 } 98 99 func Setxattr(file string, attr string, data []byte, flags int) (err error) { 100 var d unsafe.Pointer 101 if len(data) > 0 { 102 d = unsafe.Pointer(&data[0]) 103 } 104 datasiz := len(data) 105 106 nsid, a, err := xattrnamespace(attr) 107 if err != nil { 108 return 109 } 110 111 _, err = ExtattrSetFile(file, nsid, a, uintptr(d), datasiz) 112 return 113 } 114 115 func Lsetxattr(link string, attr string, data []byte, flags int) (err error) { 116 var d unsafe.Pointer 117 if len(data) > 0 { 118 d = unsafe.Pointer(&data[0]) 119 } 120 datasiz := len(data) 121 122 nsid, a, err := xattrnamespace(attr) 123 if err != nil { 124 return 125 } 126 127 _, err = ExtattrSetLink(link, nsid, a, uintptr(d), datasiz) 128 return 129 } 130 131 func Removexattr(file string, attr string) (err error) { 132 nsid, a, err := xattrnamespace(attr) 133 if err != nil { 134 return 135 } 136 137 err = ExtattrDeleteFile(file, nsid, a) 138 return 139 } 140 141 func Fremovexattr(fd int, attr string) (err error) { 142 nsid, a, err := xattrnamespace(attr) 143 if err != nil { 144 return 145 } 146 147 err = ExtattrDeleteFd(fd, nsid, a) 148 return 149 } 150 151 func Lremovexattr(link string, attr string) (err error) { 152 nsid, a, err := xattrnamespace(attr) 153 if err != nil { 154 return 155 } 156 157 err = ExtattrDeleteLink(link, nsid, a) 158 return 159 } 160 161 func Listxattr(file string, dest []byte) (sz int, err error) { 162 d := initxattrdest(dest, 0) 163 destsiz := len(dest) 164 165 // FreeBSD won't allow you to list xattrs from multiple namespaces 166 s := 0 167 for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} { 168 stmp, e := ExtattrListFile(file, nsid, uintptr(d), destsiz) 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 */ 177 if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER { 178 continue 179 } else if e != nil { 180 return s, e 181 } 182 183 s += stmp 184 destsiz -= s 185 if destsiz < 0 { 186 destsiz = 0 187 } 188 d = initxattrdest(dest, s) 189 } 190 191 return s, nil 192 } 193 194 func Flistxattr(fd int, dest []byte) (sz int, err error) { 195 d := initxattrdest(dest, 0) 196 destsiz := len(dest) 197 198 s := 0 199 for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} { 200 stmp, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz) 201 if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER { 202 continue 203 } else if e != nil { 204 return s, e 205 } 206 207 s += stmp 208 destsiz -= s 209 if destsiz < 0 { 210 destsiz = 0 211 } 212 d = initxattrdest(dest, s) 213 } 214 215 return s, nil 216 } 217 218 func Llistxattr(link string, dest []byte) (sz int, err error) { 219 d := initxattrdest(dest, 0) 220 destsiz := len(dest) 221 222 s := 0 223 for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} { 224 stmp, e := ExtattrListLink(link, nsid, uintptr(d), destsiz) 225 if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER { 226 continue 227 } else if e != nil { 228 return s, e 229 } 230 231 s += stmp 232 destsiz -= s 233 if destsiz < 0 { 234 destsiz = 0 235 } 236 d = initxattrdest(dest, s) 237 } 238 239 return s, nil 240 }