|
|
@@ -136,6 +136,238 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
|
|
|
return
|
|
|
}
|
|
|
|
|
|
+// Derive extattr namespace and attribute name
|
|
|
+
|
|
|
+func xattrnamespace(fullattr string) (ns int, attr string, err error) {
|
|
|
+ s := -1
|
|
|
+ for idx, val := range fullattr {
|
|
|
+ if val == '.' {
|
|
|
+ s = idx
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 implements its 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
|
|
|
+ var e error
|
|
|
+ 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 {
|
|
|
+ e = nil
|
|
|
+ continue
|
|
|
+ } else if e != nil {
|
|
|
+ return s, e
|
|
|
+ }
|
|
|
+
|
|
|
+ s += stmp
|
|
|
+ destsiz -= s
|
|
|
+ if destsiz < 0 {
|
|
|
+ destsiz = 0
|
|
|
+ }
|
|
|
+ d = initxattrdest(dest, s)
|
|
|
+ }
|
|
|
+
|
|
|
+ return s, e
|
|
|
+}
|
|
|
+
|
|
|
+func Flistxattr(fd int, dest []byte) (sz int, err error) {
|
|
|
+ d := initxattrdest(dest, 0)
|
|
|
+ destsiz := len(dest)
|
|
|
+
|
|
|
+ s := 0
|
|
|
+ var e error
|
|
|
+ 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 {
|
|
|
+ e = nil
|
|
|
+ continue
|
|
|
+ } else if e != nil {
|
|
|
+ return s, e
|
|
|
+ }
|
|
|
+
|
|
|
+ s += stmp
|
|
|
+ destsiz -= s
|
|
|
+ if destsiz < 0 {
|
|
|
+ destsiz = 0
|
|
|
+ }
|
|
|
+ d = initxattrdest(dest, s)
|
|
|
+ }
|
|
|
+
|
|
|
+ return s, e
|
|
|
+}
|
|
|
+
|
|
|
+func Llistxattr(link string, dest []byte) (sz int, err error) {
|
|
|
+ d := initxattrdest(dest, 0)
|
|
|
+ destsiz := len(dest)
|
|
|
+
|
|
|
+ s := 0
|
|
|
+ var e error
|
|
|
+ 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 {
|
|
|
+ e = nil
|
|
|
+ continue
|
|
|
+ } else if e != nil {
|
|
|
+ return s, e
|
|
|
+ }
|
|
|
+
|
|
|
+ s += stmp
|
|
|
+ destsiz -= s
|
|
|
+ if destsiz < 0 {
|
|
|
+ destsiz = 0
|
|
|
+ }
|
|
|
+ d = initxattrdest(dest, s)
|
|
|
+ }
|
|
|
+
|
|
|
+ return s, e
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Exposed directly
|
|
|
*/
|
|
|
@@ -150,6 +382,18 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
|
|
|
//sysnb Dup(fd int) (nfd int, err error)
|
|
|
//sysnb Dup2(from int, to int) (err error)
|
|
|
//sys Exit(code int)
|
|
|
+//sys ExtattrGetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error)
|
|
|
+//sys ExtattrSetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error)
|
|
|
+//sys ExtattrDeleteFd(fd int, attrnamespace int, attrname string) (err error)
|
|
|
+//sys ExtattrListFd(fd int, attrnamespace int, data uintptr, nbytes int) (ret int, err error)
|
|
|
+//sys ExtattrGetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error)
|
|
|
+//sys ExtattrSetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error)
|
|
|
+//sys ExtattrDeleteFile(file string, attrnamespace int, attrname string) (err error)
|
|
|
+//sys ExtattrListFile(file string, attrnamespace int, data uintptr, nbytes int) (ret int, err error)
|
|
|
+//sys ExtattrGetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error)
|
|
|
+//sys ExtattrSetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error)
|
|
|
+//sys ExtattrDeleteLink(link string, attrnamespace int, attrname string) (err error)
|
|
|
+//sys ExtattrListLink(link string, attrnamespace int, data uintptr, nbytes int) (ret int, err error)
|
|
|
//sys Fchdir(fd int) (err error)
|
|
|
//sys Fchflags(fd int, flags int) (err error)
|
|
|
//sys Fchmod(fd int, mode uint32) (err error)
|