xattr_bsd.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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. //go:build freebsd || netbsd
  5. // +build freebsd netbsd
  6. package unix
  7. import (
  8. "strings"
  9. "unsafe"
  10. )
  11. // Derive extattr namespace and attribute name
  12. func xattrnamespace(fullattr string) (ns int, attr string, err error) {
  13. s := strings.IndexByte(fullattr, '.')
  14. if s == -1 {
  15. return -1, "", ENOATTR
  16. }
  17. namespace := fullattr[0:s]
  18. attr = fullattr[s+1:]
  19. switch namespace {
  20. case "user":
  21. return EXTATTR_NAMESPACE_USER, attr, nil
  22. case "system":
  23. return EXTATTR_NAMESPACE_SYSTEM, attr, nil
  24. default:
  25. return -1, "", ENOATTR
  26. }
  27. }
  28. func initxattrdest(dest []byte, idx int) (d unsafe.Pointer) {
  29. if len(dest) > idx {
  30. return unsafe.Pointer(&dest[idx])
  31. } else {
  32. return unsafe.Pointer(_zero)
  33. }
  34. }
  35. // FreeBSD and NetBSD implement their own syscalls to handle extended attributes
  36. func Getxattr(file string, attr string, dest []byte) (sz int, err error) {
  37. d := initxattrdest(dest, 0)
  38. destsize := len(dest)
  39. nsid, a, err := xattrnamespace(attr)
  40. if err != nil {
  41. return -1, err
  42. }
  43. return ExtattrGetFile(file, nsid, a, uintptr(d), destsize)
  44. }
  45. func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) {
  46. d := initxattrdest(dest, 0)
  47. destsize := len(dest)
  48. nsid, a, err := xattrnamespace(attr)
  49. if err != nil {
  50. return -1, err
  51. }
  52. return ExtattrGetFd(fd, nsid, a, uintptr(d), destsize)
  53. }
  54. func Lgetxattr(link string, attr string, dest []byte) (sz int, err error) {
  55. d := initxattrdest(dest, 0)
  56. destsize := len(dest)
  57. nsid, a, err := xattrnamespace(attr)
  58. if err != nil {
  59. return -1, err
  60. }
  61. return ExtattrGetLink(link, nsid, a, uintptr(d), destsize)
  62. }
  63. // flags are unused on FreeBSD
  64. func Fsetxattr(fd int, attr string, data []byte, flags int) (err error) {
  65. var d unsafe.Pointer
  66. if len(data) > 0 {
  67. d = unsafe.Pointer(&data[0])
  68. }
  69. datasiz := len(data)
  70. nsid, a, err := xattrnamespace(attr)
  71. if err != nil {
  72. return
  73. }
  74. _, err = ExtattrSetFd(fd, nsid, a, uintptr(d), datasiz)
  75. return
  76. }
  77. func Setxattr(file string, attr string, data []byte, flags int) (err error) {
  78. var d unsafe.Pointer
  79. if len(data) > 0 {
  80. d = unsafe.Pointer(&data[0])
  81. }
  82. datasiz := len(data)
  83. nsid, a, err := xattrnamespace(attr)
  84. if err != nil {
  85. return
  86. }
  87. _, err = ExtattrSetFile(file, nsid, a, uintptr(d), datasiz)
  88. return
  89. }
  90. func Lsetxattr(link string, attr string, data []byte, flags int) (err error) {
  91. var d unsafe.Pointer
  92. if len(data) > 0 {
  93. d = unsafe.Pointer(&data[0])
  94. }
  95. datasiz := len(data)
  96. nsid, a, err := xattrnamespace(attr)
  97. if err != nil {
  98. return
  99. }
  100. _, err = ExtattrSetLink(link, nsid, a, uintptr(d), datasiz)
  101. return
  102. }
  103. func Removexattr(file string, attr string) (err error) {
  104. nsid, a, err := xattrnamespace(attr)
  105. if err != nil {
  106. return
  107. }
  108. err = ExtattrDeleteFile(file, nsid, a)
  109. return
  110. }
  111. func Fremovexattr(fd int, attr string) (err error) {
  112. nsid, a, err := xattrnamespace(attr)
  113. if err != nil {
  114. return
  115. }
  116. err = ExtattrDeleteFd(fd, nsid, a)
  117. return
  118. }
  119. func Lremovexattr(link string, attr string) (err error) {
  120. nsid, a, err := xattrnamespace(attr)
  121. if err != nil {
  122. return
  123. }
  124. err = ExtattrDeleteLink(link, nsid, a)
  125. return
  126. }
  127. func Listxattr(file string, dest []byte) (sz int, err error) {
  128. d := initxattrdest(dest, 0)
  129. destsiz := len(dest)
  130. // FreeBSD won't allow you to list xattrs from multiple namespaces
  131. s := 0
  132. for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
  133. stmp, e := ExtattrListFile(file, nsid, uintptr(d), destsiz)
  134. /* Errors accessing system attrs are ignored so that
  135. * we can implement the Linux-like behavior of omitting errors that
  136. * we don't have read permissions on
  137. *
  138. * Linux will still error if we ask for user attributes on a file that
  139. * we don't have read permissions on, so don't ignore those errors
  140. */
  141. if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
  142. continue
  143. } else if e != nil {
  144. return s, e
  145. }
  146. s += stmp
  147. destsiz -= s
  148. if destsiz < 0 {
  149. destsiz = 0
  150. }
  151. d = initxattrdest(dest, s)
  152. }
  153. return s, nil
  154. }
  155. func Flistxattr(fd int, dest []byte) (sz int, err error) {
  156. d := initxattrdest(dest, 0)
  157. destsiz := len(dest)
  158. s := 0
  159. for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
  160. stmp, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz)
  161. if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
  162. continue
  163. } else if e != nil {
  164. return s, e
  165. }
  166. s += stmp
  167. destsiz -= s
  168. if destsiz < 0 {
  169. destsiz = 0
  170. }
  171. d = initxattrdest(dest, s)
  172. }
  173. return s, nil
  174. }
  175. func Llistxattr(link string, dest []byte) (sz int, err error) {
  176. d := initxattrdest(dest, 0)
  177. destsiz := len(dest)
  178. s := 0
  179. for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
  180. stmp, e := ExtattrListLink(link, nsid, uintptr(d), destsiz)
  181. if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
  182. continue
  183. } else if e != nil {
  184. return s, e
  185. }
  186. s += stmp
  187. destsiz -= s
  188. if destsiz < 0 {
  189. destsiz = 0
  190. }
  191. d = initxattrdest(dest, s)
  192. }
  193. return s, nil
  194. }