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.

214 lines
4.7 KiB

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