weedfs_xattr.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package mount
  2. import (
  3. "github.com/hanwen/go-fuse/v2/fuse"
  4. sys "golang.org/x/sys/unix"
  5. "runtime"
  6. "strings"
  7. "syscall"
  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. //validate attr name
  20. if len(attr) > MAX_XATTR_NAME_SIZE {
  21. if runtime.GOOS == "darwin" {
  22. return 0, fuse.EPERM
  23. } else {
  24. return 0, fuse.ERANGE
  25. }
  26. }
  27. if len(attr) == 0 {
  28. return 0, fuse.EINVAL
  29. }
  30. _, _, entry, status := wfs.maybeReadEntry(header.NodeId)
  31. if status != fuse.OK {
  32. return 0, status
  33. }
  34. if entry == nil {
  35. return 0, fuse.ENOENT
  36. }
  37. if entry.Extended == nil {
  38. return 0, fuse.ENOATTR
  39. }
  40. data, found := entry.Extended[XATTR_PREFIX+attr]
  41. if !found {
  42. return 0, fuse.ENOATTR
  43. }
  44. if len(dest) < len(data) {
  45. return uint32(len(data)), fuse.ERANGE
  46. }
  47. copy(dest, data)
  48. return uint32(len(data)), fuse.OK
  49. }
  50. // SetXAttr writes an extended attribute.
  51. // https://man7.org/linux/man-pages/man2/setxattr.2.html
  52. // By default (i.e., flags is zero), the extended attribute will be
  53. // created if it does not exist, or the value will be replaced if
  54. // the attribute already exists. To modify these semantics, one of
  55. // the following values can be specified in flags:
  56. //
  57. // XATTR_CREATE
  58. // Perform a pure create, which fails if the named attribute
  59. // exists already.
  60. //
  61. // XATTR_REPLACE
  62. // Perform a pure replace operation, which fails if the named
  63. // attribute does not already exist.
  64. func (wfs *WFS) SetXAttr(cancel <-chan struct{}, input *fuse.SetXAttrIn, attr string, data []byte) fuse.Status {
  65. //validate attr name
  66. if len(attr) > MAX_XATTR_NAME_SIZE {
  67. if runtime.GOOS == "darwin" {
  68. return fuse.EPERM
  69. } else {
  70. return fuse.ERANGE
  71. }
  72. }
  73. if len(attr) == 0 {
  74. return fuse.EINVAL
  75. }
  76. //validate attr value
  77. if len(data) > MAX_XATTR_VALUE_SIZE {
  78. if runtime.GOOS == "darwin" {
  79. return fuse.Status(syscall.E2BIG)
  80. } else {
  81. return fuse.ERANGE
  82. }
  83. }
  84. path, _, entry, status := wfs.maybeReadEntry(input.NodeId)
  85. if status != fuse.OK {
  86. return status
  87. }
  88. if entry.Extended == nil {
  89. entry.Extended = make(map[string][]byte)
  90. }
  91. oldData, _ := entry.Extended[XATTR_PREFIX+attr]
  92. switch input.Flags {
  93. case sys.XATTR_CREATE:
  94. if len(oldData) > 0 {
  95. break
  96. }
  97. fallthrough
  98. case sys.XATTR_REPLACE:
  99. fallthrough
  100. default:
  101. entry.Extended[XATTR_PREFIX+attr] = data
  102. }
  103. return wfs.saveEntry(path, entry)
  104. }
  105. // ListXAttr lists extended attributes as '\0' delimited byte
  106. // slice, and return the number of bytes. If the buffer is too
  107. // small, return ERANGE, with the required buffer size.
  108. func (wfs *WFS) ListXAttr(cancel <-chan struct{}, header *fuse.InHeader, dest []byte) (n uint32, code fuse.Status) {
  109. _, _, entry, status := wfs.maybeReadEntry(header.NodeId)
  110. if status != fuse.OK {
  111. return 0, status
  112. }
  113. if entry == nil {
  114. return 0, fuse.ENOENT
  115. }
  116. if entry.Extended == nil {
  117. return 0, fuse.ENOATTR
  118. }
  119. var data []byte
  120. for k := range entry.Extended {
  121. if strings.HasPrefix(k, XATTR_PREFIX) {
  122. data = append(data, k[len(XATTR_PREFIX):]...)
  123. data = append(data, 0)
  124. }
  125. }
  126. if len(dest) < len(data) {
  127. return uint32(len(data)), fuse.ERANGE
  128. }
  129. copy(dest, data)
  130. return uint32(len(data)), fuse.OK
  131. }
  132. // RemoveXAttr removes an extended attribute.
  133. func (wfs *WFS) RemoveXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string) fuse.Status {
  134. if len(attr) == 0 {
  135. return fuse.EINVAL
  136. }
  137. path, _, entry, status := wfs.maybeReadEntry(header.NodeId)
  138. if status != fuse.OK {
  139. return status
  140. }
  141. if entry.Extended == nil {
  142. return fuse.ENOATTR
  143. }
  144. _, found := entry.Extended[XATTR_PREFIX+attr]
  145. if !found {
  146. return fuse.ENOATTR
  147. }
  148. delete(entry.Extended, XATTR_PREFIX+attr)
  149. return wfs.saveEntry(path, entry)
  150. }