81 lines
2.6 KiB
Go
81 lines
2.6 KiB
Go
// Copyright 2024 the Go-FUSE Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package fs
|
|
|
|
import (
|
|
"context"
|
|
"syscall"
|
|
|
|
"github.com/hanwen/go-fuse/v2/internal/xattr"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
const unix_UTIME_OMIT = unix.UTIME_OMIT
|
|
|
|
// FreeBSD has added copy_file_range(2) since FreeBSD 12. However,
|
|
// golang.org/x/sys/unix hasn't add corresponding syscall constant or
|
|
// wrap function. Here we define the syscall constant until sys/unix
|
|
// provides.
|
|
const sys_COPY_FILE_RANGE = 569
|
|
|
|
// TODO: replace the manual syscall when sys/unix provides CopyFileRange
|
|
// for FreeBSD
|
|
func doCopyFileRange(fdIn int, offIn int64, fdOut int, offOut int64,
|
|
len int, flags int) (uint32, syscall.Errno) {
|
|
count, _, errno := unix.Syscall6(sys_COPY_FILE_RANGE,
|
|
uintptr(fdIn), uintptr(offIn), uintptr(fdOut), uintptr(offOut),
|
|
uintptr(len), uintptr(flags),
|
|
)
|
|
return uint32(count), errno
|
|
}
|
|
|
|
func intDev(dev uint32) uint64 {
|
|
return uint64(dev)
|
|
}
|
|
|
|
// Since FUSE on FreeBSD expect Linux flavor data format of
|
|
// listxattr, we should reconstruct it with data returned by
|
|
// FreeBSD's syscall. And here we have added a "user." prefix
|
|
// to put them under "user" namespace, which is readable and
|
|
// writable for normal user, for a userspace implemented FS.
|
|
func rebuildAttrBuf(attrList [][]byte) []byte {
|
|
ret := make([]byte, 0)
|
|
for _, attrName := range attrList {
|
|
nsAttrName := append([]byte("user."), attrName...)
|
|
ret = append(ret, nsAttrName...)
|
|
ret = append(ret, 0x0)
|
|
}
|
|
return ret
|
|
}
|
|
|
|
var _ = (NodeListxattrer)((*LoopbackNode)(nil))
|
|
|
|
func (n *LoopbackNode) Listxattr(ctx context.Context, dest []byte) (uint32, syscall.Errno) {
|
|
// In order to simulate same data format as Linux does,
|
|
// and the size of returned buf is required to match, we must
|
|
// call unix.Llistxattr twice.
|
|
sz, err := unix.Llistxattr(n.path(), nil)
|
|
if err != nil {
|
|
return uint32(sz), ToErrno(err)
|
|
}
|
|
rawBuf := make([]byte, sz)
|
|
sz, err = unix.Llistxattr(n.path(), rawBuf)
|
|
if err != nil {
|
|
return uint32(sz), ToErrno(err)
|
|
}
|
|
attrList := xattr.ParseAttrNames(rawBuf)
|
|
rebuiltBuf := rebuildAttrBuf(attrList)
|
|
sz = len(rebuiltBuf)
|
|
if len(dest) != 0 {
|
|
// When len(dest) is 0, which means that caller wants to get
|
|
// the size. If len(dest) is less than len(rebuiltBuf), but greater
|
|
// than 0 dest will be also filled with data from rebuiltBuf,
|
|
// but truncated to len(dest). copy() function will do the same.
|
|
// And this behaviour is same as FreeBSD's syscall extattr_list_file(2).
|
|
sz = copy(dest, rebuiltBuf)
|
|
}
|
|
return uint32(sz), ToErrno(err)
|
|
}
|