Source file src/cmd/vendor/golang.org/x/sys/unix/xattr_bsd.go

     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  }
   281  

View as plain text