123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- package mount
- import (
- "runtime"
- "strings"
- "syscall"
- "github.com/hanwen/go-fuse/v2/fuse"
- sys "golang.org/x/sys/unix"
- )
- const (
- // https://man7.org/linux/man-pages/man7/xattr.7.html#:~:text=The%20VFS%20imposes%20limitations%20that,in%20listxattr(2)).
- MAX_XATTR_NAME_SIZE = 255
- MAX_XATTR_VALUE_SIZE = 65536
- XATTR_PREFIX = "xattr-" // same as filer
- )
- // GetXAttr reads an extended attribute, and should return the
- // number of bytes. If the buffer is too small, return ERANGE,
- // with the required buffer size.
- func (wfs *WFS) GetXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string, dest []byte) (size uint32, code fuse.Status) {
- if wfs.option.DisableXAttr {
- return 0, fuse.Status(syscall.ENOTSUP)
- }
- //validate attr name
- if len(attr) > MAX_XATTR_NAME_SIZE {
- if runtime.GOOS == "darwin" {
- return 0, fuse.EPERM
- } else {
- return 0, fuse.ERANGE
- }
- }
- if len(attr) == 0 {
- return 0, fuse.EINVAL
- }
- _, _, entry, status := wfs.maybeReadEntry(header.NodeId)
- if status != fuse.OK {
- return 0, status
- }
- if entry == nil {
- return 0, fuse.ENOENT
- }
- if entry.Extended == nil {
- return 0, fuse.ENOATTR
- }
- data, found := entry.Extended[XATTR_PREFIX+attr]
- if !found {
- return 0, fuse.ENOATTR
- }
- if len(dest) < len(data) {
- return uint32(len(data)), fuse.ERANGE
- }
- copy(dest, data)
- return uint32(len(data)), fuse.OK
- }
- // SetXAttr writes an extended attribute.
- // https://man7.org/linux/man-pages/man2/setxattr.2.html
- //
- // By default (i.e., flags is zero), the extended attribute will be
- // created if it does not exist, or the value will be replaced if
- // the attribute already exists. To modify these semantics, one of
- // the following values can be specified in flags:
- //
- // XATTR_CREATE
- // Perform a pure create, which fails if the named attribute
- // exists already.
- //
- // XATTR_REPLACE
- // Perform a pure replace operation, which fails if the named
- // attribute does not already exist.
- func (wfs *WFS) SetXAttr(cancel <-chan struct{}, input *fuse.SetXAttrIn, attr string, data []byte) fuse.Status {
- if wfs.option.DisableXAttr {
- return fuse.Status(syscall.ENOTSUP)
- }
- if wfs.IsOverQuota {
- return fuse.Status(syscall.ENOSPC)
- }
- //validate attr name
- if len(attr) > MAX_XATTR_NAME_SIZE {
- if runtime.GOOS == "darwin" {
- return fuse.EPERM
- } else {
- return fuse.ERANGE
- }
- }
- if len(attr) == 0 {
- return fuse.EINVAL
- }
- //validate attr value
- if len(data) > MAX_XATTR_VALUE_SIZE {
- if runtime.GOOS == "darwin" {
- return fuse.Status(syscall.E2BIG)
- } else {
- return fuse.ERANGE
- }
- }
- path, fh, entry, status := wfs.maybeReadEntry(input.NodeId)
- if status != fuse.OK {
- return status
- }
- if entry == nil {
- return fuse.ENOENT
- }
- if fh != nil {
- fh.entryLock.Lock()
- defer fh.entryLock.Unlock()
- }
- if entry.Extended == nil {
- entry.Extended = make(map[string][]byte)
- }
- oldData, _ := entry.Extended[XATTR_PREFIX+attr]
- switch input.Flags {
- case sys.XATTR_CREATE:
- if len(oldData) > 0 {
- break
- }
- fallthrough
- case sys.XATTR_REPLACE:
- fallthrough
- default:
- entry.Extended[XATTR_PREFIX+attr] = data
- }
- if fh != nil {
- fh.dirtyMetadata = true
- return fuse.OK
- }
- return wfs.saveEntry(path, entry)
- }
- // ListXAttr lists extended attributes as '\0' delimited byte
- // slice, and return the number of bytes. If the buffer is too
- // small, return ERANGE, with the required buffer size.
- func (wfs *WFS) ListXAttr(cancel <-chan struct{}, header *fuse.InHeader, dest []byte) (n uint32, code fuse.Status) {
- if wfs.option.DisableXAttr {
- return 0, fuse.Status(syscall.ENOTSUP)
- }
- _, _, entry, status := wfs.maybeReadEntry(header.NodeId)
- if status != fuse.OK {
- return 0, status
- }
- if entry == nil {
- return 0, fuse.ENOENT
- }
- if entry.Extended == nil {
- return 0, fuse.OK
- }
- var data []byte
- for k := range entry.Extended {
- if strings.HasPrefix(k, XATTR_PREFIX) {
- data = append(data, k[len(XATTR_PREFIX):]...)
- data = append(data, 0)
- }
- }
- if len(dest) < len(data) {
- return uint32(len(data)), fuse.ERANGE
- }
- copy(dest, data)
- return uint32(len(data)), fuse.OK
- }
- // RemoveXAttr removes an extended attribute.
- func (wfs *WFS) RemoveXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string) fuse.Status {
- if wfs.option.DisableXAttr {
- return fuse.Status(syscall.ENOTSUP)
- }
- if len(attr) == 0 {
- return fuse.EINVAL
- }
- path, fh, entry, status := wfs.maybeReadEntry(header.NodeId)
- if status != fuse.OK {
- return status
- }
- if entry == nil {
- return fuse.OK
- }
- if fh != nil {
- fh.entryLock.Lock()
- defer fh.entryLock.Unlock()
- }
- if entry.Extended == nil {
- return fuse.ENOATTR
- }
- _, found := entry.Extended[XATTR_PREFIX+attr]
- if !found {
- return fuse.ENOATTR
- }
- delete(entry.Extended, XATTR_PREFIX+attr)
- return wfs.saveEntry(path, entry)
- }
|