src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

xattr_bsd.go (5793B)


      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 }