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.
		
		
		
		
		
			
		
			
				
					
					
						
							217 lines
						
					
					
						
							4.7 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							217 lines
						
					
					
						
							4.7 KiB
						
					
					
				
								//go:build !freebsd
							 | 
						|
								// +build !freebsd
							 | 
						|
								
							 | 
						|
								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)
							 | 
						|
								}
							 |