fix: enforce XATTR_REPLACE semantics in setxattr (#10059)

* 修复weedfs_xattr.go 中 XATTR_REPLACE 语义缺失

* mount: fix XATTR_CREATE/XATTR_REPLACE flag semantics in setxattr

XATTR_CREATE fell through into the XATTR_REPLACE branch: creating a new
attribute hit the empty-oldData guard and returned ENODATA instead of
creating it, while creating over an existing attribute silently succeeded
without the EEXIST that setxattr(2) requires. Drop the fallthrough chain
so CREATE returns EEXIST when the attribute already exists, REPLACE
returns ENODATA when it is missing, and otherwise the value is written.
Test existence via the map lookup so an attribute with an empty value is
still treated as present.

---------

Co-authored-by: 王郁文 <wangyuwen@cmict.chinamobile.com>
Co-authored-by: Chris Lu <chris.lu@gmail.com>
This commit is contained in:
shiftraodd
2026-06-23 01:31:14 -07:00
committed by GitHub
co-authored by 王郁文 Chris Lu
parent 4bcd27fb6f
commit 1e2412e502
+11 -10
View File
@@ -121,22 +121,23 @@ func (wfs *WFS) SetXAttr(cancel <-chan struct{}, input *fuse.SetXAttrIn, attr st
if entry.Extended == nil {
entry.Extended = make(map[string][]byte)
}
oldData, _ := entry.Extended[XATTR_PREFIX+attr]
_, exists := entry.Extended[XATTR_PREFIX+attr]
switch input.Flags {
case sys.XATTR_CREATE:
if len(oldData) > 0 {
break
if exists {
return fuse.Status(syscall.EEXIST)
}
fallthrough
case sys.XATTR_REPLACE:
fallthrough
default:
// 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 !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