You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

xattr_bsd.go 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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. }
  32. if dest != nil {
  33. // extattr_get_file and extattr_list_file treat NULL differently from
  34. // a non-NULL pointer of length zero. Preserve the property of nilness,
  35. // even if we can't use dest directly.
  36. return unsafe.Pointer(&_zero)
  37. }
  38. return nil
  39. }
  40. // FreeBSD and NetBSD implement their own syscalls to handle extended attributes
  41. func Getxattr(file string, attr string, dest []byte) (sz int, err error) {
  42. d := initxattrdest(dest, 0)
  43. destsize := len(dest)
  44. nsid, a, err := xattrnamespace(attr)
  45. if err != nil {
  46. return -1, err
  47. }
  48. return ExtattrGetFile(file, nsid, a, uintptr(d), destsize)
  49. }
  50. func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) {
  51. d := initxattrdest(dest, 0)
  52. destsize := len(dest)
  53. nsid, a, err := xattrnamespace(attr)
  54. if err != nil {
  55. return -1, err
  56. }
  57. return ExtattrGetFd(fd, nsid, a, uintptr(d), destsize)
  58. }
  59. func Lgetxattr(link string, attr string, dest []byte) (sz int, err error) {
  60. d := initxattrdest(dest, 0)
  61. destsize := len(dest)
  62. nsid, a, err := xattrnamespace(attr)
  63. if err != nil {
  64. return -1, err
  65. }
  66. return ExtattrGetLink(link, nsid, a, uintptr(d), destsize)
  67. }
  68. // flags are unused on FreeBSD
  69. func Fsetxattr(fd int, attr string, data []byte, flags int) (err error) {
  70. var d unsafe.Pointer
  71. if len(data) > 0 {
  72. d = unsafe.Pointer(&data[0])
  73. }
  74. datasiz := len(data)
  75. nsid, a, err := xattrnamespace(attr)
  76. if err != nil {
  77. return
  78. }
  79. _, err = ExtattrSetFd(fd, nsid, a, uintptr(d), datasiz)
  80. return
  81. }
  82. func Setxattr(file string, attr string, data []byte, flags int) (err error) {
  83. var d unsafe.Pointer
  84. if len(data) > 0 {
  85. d = unsafe.Pointer(&data[0])
  86. }
  87. datasiz := len(data)
  88. nsid, a, err := xattrnamespace(attr)
  89. if err != nil {
  90. return
  91. }
  92. _, err = ExtattrSetFile(file, nsid, a, uintptr(d), datasiz)
  93. return
  94. }
  95. func Lsetxattr(link string, attr string, data []byte, flags int) (err error) {
  96. var d unsafe.Pointer
  97. if len(data) > 0 {
  98. d = unsafe.Pointer(&data[0])
  99. }
  100. datasiz := len(data)
  101. nsid, a, err := xattrnamespace(attr)
  102. if err != nil {
  103. return
  104. }
  105. _, err = ExtattrSetLink(link, nsid, a, uintptr(d), datasiz)
  106. return
  107. }
  108. func Removexattr(file string, attr string) (err error) {
  109. nsid, a, err := xattrnamespace(attr)
  110. if err != nil {
  111. return
  112. }
  113. err = ExtattrDeleteFile(file, nsid, a)
  114. return
  115. }
  116. func Fremovexattr(fd int, attr string) (err error) {
  117. nsid, a, err := xattrnamespace(attr)
  118. if err != nil {
  119. return
  120. }
  121. err = ExtattrDeleteFd(fd, nsid, a)
  122. return
  123. }
  124. func Lremovexattr(link string, attr string) (err error) {
  125. nsid, a, err := xattrnamespace(attr)
  126. if err != nil {
  127. return
  128. }
  129. err = ExtattrDeleteLink(link, nsid, a)
  130. return
  131. }
  132. func Listxattr(file string, dest []byte) (sz int, err error) {
  133. destsiz := len(dest)
  134. // FreeBSD won't allow you to list xattrs from multiple namespaces
  135. s, pos := 0, 0
  136. for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
  137. stmp, e := ListxattrNS(file, nsid, dest[pos:])
  138. /* Errors accessing system attrs are ignored so that
  139. * we can implement the Linux-like behavior of omitting errors that
  140. * we don't have read permissions on
  141. *
  142. * Linux will still error if we ask for user attributes on a file that
  143. * we don't have read permissions on, so don't ignore those errors
  144. */
  145. if e != nil {
  146. if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
  147. continue
  148. }
  149. return s, e
  150. }
  151. s += stmp
  152. pos = s
  153. if pos > destsiz {
  154. pos = destsiz
  155. }
  156. }
  157. return s, nil
  158. }
  159. func ListxattrNS(file string, nsid int, dest []byte) (sz int, err error) {
  160. d := initxattrdest(dest, 0)
  161. destsiz := len(dest)
  162. s, e := ExtattrListFile(file, nsid, uintptr(d), destsiz)
  163. if e != nil {
  164. return 0, err
  165. }
  166. return s, nil
  167. }
  168. func Flistxattr(fd int, dest []byte) (sz int, err error) {
  169. destsiz := len(dest)
  170. s, pos := 0, 0
  171. for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
  172. stmp, e := FlistxattrNS(fd, nsid, dest[pos:])
  173. if e != nil {
  174. if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
  175. continue
  176. }
  177. return s, e
  178. }
  179. s += stmp
  180. pos = s
  181. if pos > destsiz {
  182. pos = destsiz
  183. }
  184. }
  185. return s, nil
  186. }
  187. func FlistxattrNS(fd int, nsid int, dest []byte) (sz int, err error) {
  188. d := initxattrdest(dest, 0)
  189. destsiz := len(dest)
  190. s, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz)
  191. if e != nil {
  192. return 0, err
  193. }
  194. return s, nil
  195. }
  196. func Llistxattr(link string, dest []byte) (sz int, err error) {
  197. destsiz := len(dest)
  198. s, pos := 0, 0
  199. for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
  200. stmp, e := LlistxattrNS(link, nsid, dest[pos:])
  201. if e != nil {
  202. if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
  203. continue
  204. }
  205. return s, e
  206. }
  207. s += stmp
  208. pos = s
  209. if pos > destsiz {
  210. pos = destsiz
  211. }
  212. }
  213. return s, nil
  214. }
  215. func LlistxattrNS(link string, nsid int, dest []byte) (sz int, err error) {
  216. d := initxattrdest(dest, 0)
  217. destsiz := len(dest)
  218. s, e := ExtattrListLink(link, nsid, uintptr(d), destsiz)
  219. if e != nil {
  220. return 0, err
  221. }
  222. return s, nil
  223. }