mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-18 13:17:08 +00:00
weed/mount implements all four xattr operations and the filer stores the values, but the Windows adapter overrode none of them, so cgofuse's defaults answered every call with 'not implemented'. WinFsp advertises extended attribute support either way, because cgofuse registers the callbacks unconditionally, so applications were told the volume has them and then refused on every use. Attributes written from Linux were invisible from Windows. Untested in CI: exercising Windows extended attributes needs the native NtSetEaFile path rather than anything in os or PowerShell.
88 lines
2.9 KiB
Go
88 lines
2.9 KiB
Go
package winfsp
|
|
|
|
import (
|
|
"syscall"
|
|
"testing"
|
|
|
|
cgofuse "github.com/winfsp/cgofuse/fuse"
|
|
)
|
|
|
|
// The errno values are spelled out so the table stays portable and testable on
|
|
// any runner. This pins them to what cgofuse actually decodes, so a divergence
|
|
// is a failing test rather than an operation reporting an unrelated error.
|
|
func TestErrnoValuesMatchCgofuse(t *testing.T) {
|
|
for _, c := range []struct {
|
|
name string
|
|
ours int
|
|
want int
|
|
}{
|
|
{"EPERM", ePERM, cgofuse.EPERM},
|
|
{"ENOENT", eNOENT, cgofuse.ENOENT},
|
|
{"EINTR", eINTR, cgofuse.EINTR},
|
|
{"EIO", eIO, cgofuse.EIO},
|
|
{"ENXIO", eNXIO, cgofuse.ENXIO},
|
|
{"EBADF", eBADF, cgofuse.EBADF},
|
|
{"EAGAIN", eAGAIN, cgofuse.EAGAIN},
|
|
{"ENOMEM", eNOMEM, cgofuse.ENOMEM},
|
|
{"EACCES", eACCES, cgofuse.EACCES},
|
|
{"EBUSY", eBUSY, cgofuse.EBUSY},
|
|
{"EEXIST", eEXIST, cgofuse.EEXIST},
|
|
{"EXDEV", eXDEV, cgofuse.EXDEV},
|
|
{"ENODEV", eNODEV, cgofuse.ENODEV},
|
|
{"ENOTDIR", eNOTDIR, cgofuse.ENOTDIR},
|
|
{"EISDIR", eISDIR, cgofuse.EISDIR},
|
|
{"EINVAL", eINVAL, cgofuse.EINVAL},
|
|
{"ENFILE", eNFILE, cgofuse.ENFILE},
|
|
{"EMFILE", eMFILE, cgofuse.EMFILE},
|
|
{"EFBIG", eFBIG, cgofuse.EFBIG},
|
|
{"ENOSPC", eNOSPC, cgofuse.ENOSPC},
|
|
{"ESPIPE", eSPIPE, cgofuse.ESPIPE},
|
|
{"EROFS", eROFS, cgofuse.EROFS},
|
|
{"EMLINK", eMLINK, cgofuse.EMLINK},
|
|
{"EPIPE", ePIPE, cgofuse.EPIPE},
|
|
{"ERANGE", eRANGE, cgofuse.ERANGE},
|
|
{"ENAMETOOLONG", eNAMETOOLONG, cgofuse.ENAMETOOLONG},
|
|
{"ENOSYS", eNOSYS, cgofuse.ENOSYS},
|
|
{"ENOTEMPTY", eNOTEMPTY, cgofuse.ENOTEMPTY},
|
|
{"ELOOP", eLOOP, cgofuse.ELOOP},
|
|
{"ENODATA", eNODATA, cgofuse.ENODATA},
|
|
{"ENOTSUP", eNOTSUP, cgofuse.ENOTSUP},
|
|
} {
|
|
if c.ours != c.want {
|
|
t.Errorf("%s = %d, cgofuse uses %d", c.name, c.ours, c.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// translateOpenFlags relies on cgofuse using MSVC's numbering while the raw
|
|
// filesystem reads Go's. Pin that, because a swap between O_EXCL and O_TRUNC
|
|
// would turn "fail if it exists" into "truncate it".
|
|
func TestOpenFlagTranslation(t *testing.T) {
|
|
for _, c := range []struct {
|
|
name string
|
|
in int
|
|
want uint32
|
|
}{
|
|
{"O_EXCL", cgofuse.O_EXCL, uint32(syscall.O_EXCL)},
|
|
{"O_TRUNC", cgofuse.O_TRUNC, uint32(syscall.O_TRUNC)},
|
|
{"O_CREAT", cgofuse.O_CREAT, uint32(syscall.O_CREAT)},
|
|
{"O_APPEND", cgofuse.O_APPEND, uint32(syscall.O_APPEND)},
|
|
} {
|
|
if got := translateOpenFlags(c.in); got != c.want {
|
|
t.Errorf("translateOpenFlags(%s=%#x) = %#x, want %#x", c.name, c.in, got, c.want)
|
|
}
|
|
}
|
|
if got := translateOpenFlags(cgofuse.O_RDWR); got != uint32(syscall.O_RDWR) {
|
|
t.Errorf("access mode not preserved: %#x", got)
|
|
}
|
|
}
|
|
|
|
// Setxattr passes cgofuse's flags straight to the raw filesystem, which is
|
|
// only correct while the two number them identically. The other side is
|
|
// pinned by TestXattrFlagValues in weed/mount, so editing either alone fails.
|
|
func TestXattrFlagValues(t *testing.T) {
|
|
if cgofuse.XATTR_CREATE != 1 || cgofuse.XATTR_REPLACE != 2 {
|
|
t.Fatalf("cgofuse xattr flags moved: create=%d replace=%d", cgofuse.XATTR_CREATE, cgofuse.XATTR_REPLACE)
|
|
}
|
|
}
|