mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-08 15:41:15 +02:00
* mount: drop the unused go-fuse fs package dependency WFS embedded fs.Inode but never used any of its methods, and the only other reference was RENAME_EXCHANGE, a constant sitting next to three literals. Removing both drops fs and five internal packages from the mount build graph. * mount: build the package on windows Windows has no fcntl lock types, no O_ACCMODE and no x/sys/unix, so a handful of constants kept weed/mount pinned to unix even though the code using them is portable in-memory logic. Route them through per-OS shims and give setBlksize a windows no-op. The POSIX lock table now compiles on windows but stays unreachable: WinFsp resolves byte-range locks in its own kernel driver, so nothing will feed it there. go.mod points at a go-fuse branch commit and needs repinning to a release tag once that lands. * ci: cross-compile for windows Nothing caught the unix-only constants creeping into weed/mount until a release build failed. * mount: let readdir feed a sink instead of the kernel buffer doReadDirectory wrote directly into fuse.DirEntryList, which is the kernel's wire format. A front end that is not the kernel would have to pack entries only to parse them straight back out. Route it through DirEntrySink instead. ReadDir and ReadDirPlus pass the reply buffer, so nothing changes for the FUSE server. * mount: pin go-fuse v2.9.4 for the windows build
225 lines
5.0 KiB
Go
225 lines
5.0 KiB
Go
//go:build !freebsd
|
|
|
|
package mount
|
|
|
|
import (
|
|
"runtime"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/seaweedfs/go-fuse/v2/fuse"
|
|
)
|
|
|
|
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.IsOverQuotaWithUncommitted() {
|
|
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)
|
|
}
|
|
_, exists := entry.Extended[XATTR_PREFIX+attr]
|
|
switch input.Flags {
|
|
case xattr_CREATE:
|
|
if exists {
|
|
return fuse.Status(syscall.EEXIST)
|
|
}
|
|
case xattr_REPLACE:
|
|
if !exists {
|
|
return fuse.ENODATA
|
|
}
|
|
}
|
|
|
|
// data aliases the FUSE request's pooled input buffer, which is
|
|
// recycled once this handler returns. Copy before storing so a
|
|
// later request reusing the buffer cannot corrupt the value.
|
|
entry.Extended[XATTR_PREFIX+attr] = append([]byte(nil), 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)
|
|
|
|
if fh != nil {
|
|
fh.dirtyMetadata = true
|
|
return fuse.OK
|
|
}
|
|
|
|
return wfs.saveEntry(path, entry)
|
|
}
|