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  }