232 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			232 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// Copyright 2018 The Go Authors. All rights reserved.
							 | 
						||
| 
								 | 
							
								// Use of this source code is governed by a BSD-style
							 | 
						||
| 
								 | 
							
								// license that can be found in the LICENSE file.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// +build freebsd netbsd
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								package unix
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"strings"
							 | 
						||
| 
								 | 
							
									"unsafe"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Derive extattr namespace and attribute name
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func xattrnamespace(fullattr string) (ns int, attr string, err error) {
							 | 
						||
| 
								 | 
							
									s := strings.IndexByte(fullattr, '.')
							 | 
						||
| 
								 | 
							
									if s == -1 {
							 | 
						||
| 
								 | 
							
										return -1, "", ENOATTR
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									namespace := fullattr[0:s]
							 | 
						||
| 
								 | 
							
									attr = fullattr[s+1:]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									switch namespace {
							 | 
						||
| 
								 | 
							
									case "user":
							 | 
						||
| 
								 | 
							
										return EXTATTR_NAMESPACE_USER, attr, nil
							 | 
						||
| 
								 | 
							
									case "system":
							 | 
						||
| 
								 | 
							
										return EXTATTR_NAMESPACE_SYSTEM, attr, nil
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										return -1, "", ENOATTR
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func initxattrdest(dest []byte, idx int) (d unsafe.Pointer) {
							 | 
						||
| 
								 | 
							
									if len(dest) > idx {
							 | 
						||
| 
								 | 
							
										return unsafe.Pointer(&dest[idx])
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										return unsafe.Pointer(_zero)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// FreeBSD and NetBSD implement their own syscalls to handle extended attributes
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Getxattr(file string, attr string, dest []byte) (sz int, err error) {
							 | 
						||
| 
								 | 
							
									d := initxattrdest(dest, 0)
							 | 
						||
| 
								 | 
							
									destsize := len(dest)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									nsid, a, err := xattrnamespace(attr)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return -1, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return ExtattrGetFile(file, nsid, a, uintptr(d), destsize)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) {
							 | 
						||
| 
								 | 
							
									d := initxattrdest(dest, 0)
							 | 
						||
| 
								 | 
							
									destsize := len(dest)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									nsid, a, err := xattrnamespace(attr)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return -1, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return ExtattrGetFd(fd, nsid, a, uintptr(d), destsize)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Lgetxattr(link string, attr string, dest []byte) (sz int, err error) {
							 | 
						||
| 
								 | 
							
									d := initxattrdest(dest, 0)
							 | 
						||
| 
								 | 
							
									destsize := len(dest)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									nsid, a, err := xattrnamespace(attr)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return -1, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return ExtattrGetLink(link, nsid, a, uintptr(d), destsize)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// flags are unused on FreeBSD
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Fsetxattr(fd int, attr string, data []byte, flags int) (err error) {
							 | 
						||
| 
								 | 
							
									d := unsafe.Pointer(&data[0])
							 | 
						||
| 
								 | 
							
									datasiz := len(data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									nsid, a, err := xattrnamespace(attr)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									_, err = ExtattrSetFd(fd, nsid, a, uintptr(d), datasiz)
							 | 
						||
| 
								 | 
							
									return
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Setxattr(file string, attr string, data []byte, flags int) (err error) {
							 | 
						||
| 
								 | 
							
									d := unsafe.Pointer(&data[0])
							 | 
						||
| 
								 | 
							
									datasiz := len(data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									nsid, a, err := xattrnamespace(attr)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									_, err = ExtattrSetFile(file, nsid, a, uintptr(d), datasiz)
							 | 
						||
| 
								 | 
							
									return
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Lsetxattr(link string, attr string, data []byte, flags int) (err error) {
							 | 
						||
| 
								 | 
							
									d := unsafe.Pointer(&data[0])
							 | 
						||
| 
								 | 
							
									datasiz := len(data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									nsid, a, err := xattrnamespace(attr)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									_, err = ExtattrSetLink(link, nsid, a, uintptr(d), datasiz)
							 | 
						||
| 
								 | 
							
									return
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Removexattr(file string, attr string) (err error) {
							 | 
						||
| 
								 | 
							
									nsid, a, err := xattrnamespace(attr)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									err = ExtattrDeleteFile(file, nsid, a)
							 | 
						||
| 
								 | 
							
									return
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Fremovexattr(fd int, attr string) (err error) {
							 | 
						||
| 
								 | 
							
									nsid, a, err := xattrnamespace(attr)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									err = ExtattrDeleteFd(fd, nsid, a)
							 | 
						||
| 
								 | 
							
									return
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Lremovexattr(link string, attr string) (err error) {
							 | 
						||
| 
								 | 
							
									nsid, a, err := xattrnamespace(attr)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									err = ExtattrDeleteLink(link, nsid, a)
							 | 
						||
| 
								 | 
							
									return
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Listxattr(file string, dest []byte) (sz int, err error) {
							 | 
						||
| 
								 | 
							
									d := initxattrdest(dest, 0)
							 | 
						||
| 
								 | 
							
									destsiz := len(dest)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// FreeBSD won't allow you to list xattrs from multiple namespaces
							 | 
						||
| 
								 | 
							
									s := 0
							 | 
						||
| 
								 | 
							
									for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
							 | 
						||
| 
								 | 
							
										stmp, e := ExtattrListFile(file, nsid, uintptr(d), destsiz)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Errors accessing system attrs are ignored so that
							 | 
						||
| 
								 | 
							
										 * we can implement the Linux-like behavior of omitting errors that
							 | 
						||
| 
								 | 
							
										 * we don't have read permissions on
							 | 
						||
| 
								 | 
							
										 *
							 | 
						||
| 
								 | 
							
										 * Linux will still error if we ask for user attributes on a file that
							 | 
						||
| 
								 | 
							
										 * we don't have read permissions on, so don't ignore those errors
							 | 
						||
| 
								 | 
							
										 */
							 | 
						||
| 
								 | 
							
										if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										} else if e != nil {
							 | 
						||
| 
								 | 
							
											return s, e
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										s += stmp
							 | 
						||
| 
								 | 
							
										destsiz -= s
							 | 
						||
| 
								 | 
							
										if destsiz < 0 {
							 | 
						||
| 
								 | 
							
											destsiz = 0
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										d = initxattrdest(dest, s)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return s, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Flistxattr(fd int, dest []byte) (sz int, err error) {
							 | 
						||
| 
								 | 
							
									d := initxattrdest(dest, 0)
							 | 
						||
| 
								 | 
							
									destsiz := len(dest)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									s := 0
							 | 
						||
| 
								 | 
							
									for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
							 | 
						||
| 
								 | 
							
										stmp, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz)
							 | 
						||
| 
								 | 
							
										if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										} else if e != nil {
							 | 
						||
| 
								 | 
							
											return s, e
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										s += stmp
							 | 
						||
| 
								 | 
							
										destsiz -= s
							 | 
						||
| 
								 | 
							
										if destsiz < 0 {
							 | 
						||
| 
								 | 
							
											destsiz = 0
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										d = initxattrdest(dest, s)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return s, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func Llistxattr(link string, dest []byte) (sz int, err error) {
							 | 
						||
| 
								 | 
							
									d := initxattrdest(dest, 0)
							 | 
						||
| 
								 | 
							
									destsiz := len(dest)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									s := 0
							 | 
						||
| 
								 | 
							
									for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
							 | 
						||
| 
								 | 
							
										stmp, e := ExtattrListLink(link, nsid, uintptr(d), destsiz)
							 | 
						||
| 
								 | 
							
										if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										} else if e != nil {
							 | 
						||
| 
								 | 
							
											return s, e
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										s += stmp
							 | 
						||
| 
								 | 
							
										destsiz -= s
							 | 
						||
| 
								 | 
							
										if destsiz < 0 {
							 | 
						||
| 
								 | 
							
											destsiz = 0
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										d = initxattrdest(dest, s)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return s, nil
							 | 
						||
| 
								 | 
							
								}
							 |