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.
 
 

277 regels
5.5 KiB

  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. destsiz := len(dest)
  129. // FreeBSD won't allow you to list xattrs from multiple namespaces
  130. s, pos := 0, 0
  131. for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
  132. stmp, e := ListxattrNS(file, nsid, dest[pos:])
  133. /* Errors accessing system attrs are ignored so that
  134. * we can implement the Linux-like behavior of omitting errors that
  135. * we don't have read permissions on
  136. *
  137. * Linux will still error if we ask for user attributes on a file that
  138. * we don't have read permissions on, so don't ignore those errors
  139. */
  140. if e != nil {
  141. if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
  142. continue
  143. }
  144. return s, e
  145. }
  146. s += stmp
  147. pos = s
  148. if pos > destsiz {
  149. pos = destsiz
  150. }
  151. }
  152. return s, nil
  153. }
  154. func ListxattrNS(file string, nsid int, dest []byte) (sz int, err error) {
  155. d := initxattrdest(dest, 0)
  156. destsiz := len(dest)
  157. s, e := ExtattrListFile(file, nsid, uintptr(d), destsiz)
  158. if e != nil {
  159. return 0, err
  160. }
  161. return s, nil
  162. }
  163. func Flistxattr(fd int, dest []byte) (sz int, err error) {
  164. destsiz := len(dest)
  165. s, pos := 0, 0
  166. for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
  167. stmp, e := FlistxattrNS(fd, nsid, dest[pos:])
  168. if e != nil {
  169. if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
  170. continue
  171. }
  172. return s, e
  173. }
  174. s += stmp
  175. pos = s
  176. if pos > destsiz {
  177. pos = destsiz
  178. }
  179. }
  180. return s, nil
  181. }
  182. func FlistxattrNS(fd int, nsid int, dest []byte) (sz int, err error) {
  183. d := initxattrdest(dest, 0)
  184. destsiz := len(dest)
  185. s, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz)
  186. if e != nil {
  187. return 0, err
  188. }
  189. return s, nil
  190. }
  191. func Llistxattr(link string, dest []byte) (sz int, err error) {
  192. destsiz := len(dest)
  193. s, pos := 0, 0
  194. for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
  195. stmp, e := LlistxattrNS(link, nsid, dest[pos:])
  196. if e != nil {
  197. if e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
  198. continue
  199. }
  200. return s, e
  201. }
  202. s += stmp
  203. pos = s
  204. if pos > destsiz {
  205. pos = destsiz
  206. }
  207. }
  208. return s, nil
  209. }
  210. func LlistxattrNS(link string, nsid int, dest []byte) (sz int, err error) {
  211. d := initxattrdest(dest, 0)
  212. destsiz := len(dest)
  213. s, e := ExtattrListLink(link, nsid, uintptr(d), destsiz)
  214. if e != nil {
  215. return 0, err
  216. }
  217. return s, nil
  218. }