weedfs_xattr.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. //go:build !freebsd
  2. // +build !freebsd
  3. package mount
  4. import (
  5. "runtime"
  6. "strings"
  7. "syscall"
  8. "github.com/hanwen/go-fuse/v2/fuse"
  9. sys "golang.org/x/sys/unix"
  10. )
  11. const (
  12. // https://man7.org/linux/man-pages/man7/xattr.7.html#:~:text=The%20VFS%20imposes%20limitations%20that,in%20listxattr(2)).
  13. MAX_XATTR_NAME_SIZE = 255
  14. MAX_XATTR_VALUE_SIZE = 65536
  15. XATTR_PREFIX = "xattr-" // same as filer
  16. )
  17. // GetXAttr reads an extended attribute, and should return the
  18. // number of bytes. If the buffer is too small, return ERANGE,
  19. // with the required buffer size.
  20. func (wfs *WFS) GetXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string, dest []byte) (size uint32, code fuse.Status) {
  21. if wfs.option.DisableXAttr {
  22. return 0, fuse.Status(syscall.ENOTSUP)
  23. }
  24. //validate attr name
  25. if len(attr) > MAX_XATTR_NAME_SIZE {
  26. if runtime.GOOS == "darwin" {
  27. return 0, fuse.EPERM
  28. } else {
  29. return 0, fuse.ERANGE
  30. }
  31. }
  32. if len(attr) == 0 {
  33. return 0, fuse.EINVAL
  34. }
  35. _, _, entry, status := wfs.maybeReadEntry(header.NodeId)
  36. if status != fuse.OK {
  37. return 0, status
  38. }
  39. if entry == nil {
  40. return 0, fuse.ENOENT
  41. }
  42. if entry.Extended == nil {
  43. return 0, fuse.ENOATTR
  44. }
  45. data, found := entry.Extended[XATTR_PREFIX+attr]
  46. if !found {
  47. return 0, fuse.ENOATTR
  48. }
  49. if len(dest) < len(data) {
  50. return uint32(len(data)), fuse.ERANGE
  51. }
  52. copy(dest, data)
  53. return uint32(len(data)), fuse.OK
  54. }
  55. // SetXAttr writes an extended attribute.
  56. // https://man7.org/linux/man-pages/man2/setxattr.2.html
  57. //
  58. // By default (i.e., flags is zero), the extended attribute will be
  59. // created if it does not exist, or the value will be replaced if
  60. // the attribute already exists. To modify these semantics, one of
  61. // the following values can be specified in flags:
  62. //
  63. // XATTR_CREATE
  64. // Perform a pure create, which fails if the named attribute
  65. // exists already.
  66. //
  67. // XATTR_REPLACE
  68. // Perform a pure replace operation, which fails if the named
  69. // attribute does not already exist.
  70. func (wfs *WFS) SetXAttr(cancel <-chan struct{}, input *fuse.SetXAttrIn, attr string, data []byte) fuse.Status {
  71. if wfs.option.DisableXAttr {
  72. return fuse.Status(syscall.ENOTSUP)
  73. }
  74. if wfs.IsOverQuota {
  75. return fuse.Status(syscall.ENOSPC)
  76. }
  77. //validate attr name
  78. if len(attr) > MAX_XATTR_NAME_SIZE {
  79. if runtime.GOOS == "darwin" {
  80. return fuse.EPERM
  81. } else {
  82. return fuse.ERANGE
  83. }
  84. }
  85. if len(attr) == 0 {
  86. return fuse.EINVAL
  87. }
  88. //validate attr value
  89. if len(data) > MAX_XATTR_VALUE_SIZE {
  90. if runtime.GOOS == "darwin" {
  91. return fuse.Status(syscall.E2BIG)
  92. } else {
  93. return fuse.ERANGE
  94. }
  95. }
  96. path, fh, entry, status := wfs.maybeReadEntry(input.NodeId)
  97. if status != fuse.OK {
  98. return status
  99. }
  100. if entry == nil {
  101. return fuse.ENOENT
  102. }
  103. if fh != nil {
  104. fh.entryLock.Lock()
  105. defer fh.entryLock.Unlock()
  106. }
  107. if entry.Extended == nil {
  108. entry.Extended = make(map[string][]byte)
  109. }
  110. oldData, _ := entry.Extended[XATTR_PREFIX+attr]
  111. switch input.Flags {
  112. case sys.XATTR_CREATE:
  113. if len(oldData) > 0 {
  114. break
  115. }
  116. fallthrough
  117. case sys.XATTR_REPLACE:
  118. fallthrough
  119. default:
  120. entry.Extended[XATTR_PREFIX+attr] = data
  121. }
  122. if fh != nil {
  123. fh.dirtyMetadata = true
  124. return fuse.OK
  125. }
  126. return wfs.saveEntry(path, entry)
  127. }
  128. // ListXAttr lists extended attributes as '\0' delimited byte
  129. // slice, and return the number of bytes. If the buffer is too
  130. // small, return ERANGE, with the required buffer size.
  131. func (wfs *WFS) ListXAttr(cancel <-chan struct{}, header *fuse.InHeader, dest []byte) (n uint32, code fuse.Status) {
  132. if wfs.option.DisableXAttr {
  133. return 0, fuse.Status(syscall.ENOTSUP)
  134. }
  135. _, _, entry, status := wfs.maybeReadEntry(header.NodeId)
  136. if status != fuse.OK {
  137. return 0, status
  138. }
  139. if entry == nil {
  140. return 0, fuse.ENOENT
  141. }
  142. if entry.Extended == nil {
  143. return 0, fuse.OK
  144. }
  145. var data []byte
  146. for k := range entry.Extended {
  147. if strings.HasPrefix(k, XATTR_PREFIX) {
  148. data = append(data, k[len(XATTR_PREFIX):]...)
  149. data = append(data, 0)
  150. }
  151. }
  152. if len(dest) < len(data) {
  153. return uint32(len(data)), fuse.ERANGE
  154. }
  155. copy(dest, data)
  156. return uint32(len(data)), fuse.OK
  157. }
  158. // RemoveXAttr removes an extended attribute.
  159. func (wfs *WFS) RemoveXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string) fuse.Status {
  160. if wfs.option.DisableXAttr {
  161. return fuse.Status(syscall.ENOTSUP)
  162. }
  163. if len(attr) == 0 {
  164. return fuse.EINVAL
  165. }
  166. path, fh, entry, status := wfs.maybeReadEntry(header.NodeId)
  167. if status != fuse.OK {
  168. return status
  169. }
  170. if entry == nil {
  171. return fuse.OK
  172. }
  173. if fh != nil {
  174. fh.entryLock.Lock()
  175. defer fh.entryLock.Unlock()
  176. }
  177. if entry.Extended == nil {
  178. return fuse.ENOATTR
  179. }
  180. _, found := entry.Extended[XATTR_PREFIX+attr]
  181. if !found {
  182. return fuse.ENOATTR
  183. }
  184. delete(entry.Extended, XATTR_PREFIX+attr)
  185. return wfs.saveEntry(path, entry)
  186. }