From: Vinit Agnihotri Date: Tue, 14 Jul 2026 10:33:37 +0000 (+0530) Subject: vfs_ceph_rgw: Return ENOATTR for non-existing xattr X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e39f85d383ba15dffc0b8fd109b361cfb89afee7;p=thirdparty%2Fsamba.git vfs_ceph_rgw: Return ENOATTR for non-existing xattr In case of existing xattr, rgw_getxattrs() API executes callback and returns 0 on success. We then determine number of bytes to return from callback. In case of non-existing xattr, rgw_getxattrs() API does not execute callback but returns 0. Upper layer expect NT_STATUS_OBJECT_NAME_NOT_FOUND in case of non-existing xattr. Since we were returning 0, upper layer treats it as missing data and flags as error. This fix allows module to handle this situation by returning -ENOATTR for non-existing xattr, thereby providing correct information for upper layer. Additional changes: - rgw_getxattrs() do not set errno, thus relevant handling is removed. - Added error handling for special names to get/set/rm xattr calls. BUG: https://bugzilla.samba.org/show_bug.cgi?id=16218 Signed-off-by: Vinit Agnihotri Reviewed-by: Shachar Sharon Reviewed-by: Anoop C S Reviewed-by: Guenther Deschner Autobuild-User(master): Anoop C S Autobuild-Date(master): Tue Aug 11 06:06:14 UTC 2026 on atb-devel-224 --- diff --git a/source3/modules/vfs_ceph_rgw.c b/source3/modules/vfs_ceph_rgw.c index d6b1837d394..fbbec98e3d4 100644 --- a/source3/modules/vfs_ceph_rgw.c +++ b/source3/modules/vfs_ceph_rgw.c @@ -90,6 +90,7 @@ struct vfs_ceph_rgw_getxattr_arg { int rc; char *val; size_t size; + bool cb_called; }; struct vfs_ceph_rgw_lsxattr_arg { @@ -902,6 +903,17 @@ static void prepare_xattr_list(rgw_xattrlist *attr_list, } } +/* + * Callback for rgw_getxattrs() to get value for given attribute names. + * + * @param attrs: List of attributes received from RGW + * @param arg: Pointer to vfs_ceph_rgw_getxattr_arg structure + * @param flags: Callback flags (unused) + * @return: 0 to mark completion for callback. + * + * Output: value for attribute and size in bytes via callback argument. + * + */ static int ceph_rgw_getxattr_cb(rgw_xattrlist *attr_list, void *arg, uint32_t flags) @@ -910,7 +922,8 @@ static int ceph_rgw_getxattr_cb(rgw_xattrlist *attr_list, *cb_arg = (struct vfs_ceph_rgw_getxattr_arg *)arg; rgw_xattr *xattr = attr_list->xattrs; - if ((cb_arg->size != 0) && (cb_arg->size < xattr->val.len)) { + cb_arg->cb_called = true; + if (cb_arg->size < xattr->val.len) { cb_arg->rc = -ERANGE; return 0; } @@ -943,6 +956,24 @@ static ssize_t vfs_ceph_rgw_fgetxattr(struct vfs_handle_struct *handle, DBG_DEBUG("[CEPH_RGW] fgetxattr: [%s] %s\n", fsp_str_dbg(fsp), name); + /* + * We do not support posix like handling to get current size of + * extended attribute from backend in case of size is mentioned as 0. + */ + if (size == 0) { + DBG_DEBUG("[CEPH_RGW] No support to get size xattr\n"); + rc = -ENOTSUP; + goto out; + } + + if (is_special_name(fsp->fsp_name->base_name)) { + DBG_DEBUG( + "[CEPH_RGW] Cannot perform op on special name [%s]\n", + fsp_str_dbg(fsp)); + rc = -EINVAL; + goto out; + } + rc = vfs_ceph_rgw_fetch_fh(handle, fsp, &fh); if (rc != 0) { DBG_ERR("[CEPH_RGW] Unable to fetch handle\n"); @@ -951,7 +982,6 @@ static ssize_t vfs_ceph_rgw_fgetxattr(struct vfs_handle_struct *handle, prepare_xattr_list(&attr_list, discard_const(name), NULL, 0); - cb_arg.rc = 0; cb_arg.val = value; cb_arg.size = size; @@ -962,23 +992,30 @@ static ssize_t vfs_ceph_rgw_fgetxattr(struct vfs_handle_struct *handle, &cb_arg, RGW_GETXATTR_FLAG_NONE); - if (rc < 0) { - int err = errno; - if (err == 0) { - rc = -ENODATA; - } else { - DBG_ERR("[CEPH_RGW] Error getting xattr. " - "rc = %d errno = %d cbErr = %d\n", - rc, - err, - cb_arg.rc); - rc = -err; - } + if (rc < 0 || cb_arg.rc < 0) { + DBG_ERR("[CEPH_RGW] Error getting xattr. " + "rc = %d cbErr = %d\n", + rc, + cb_arg.rc); + rc = (rc < 0) ? rc : cb_arg.rc; goto out; } + + /* + * API returns 0 on success and callback serves to indicate + * number of bytes to return. + */ rc = cb_arg.rc; - if (rc < 0) { - DBG_ERR("[CEPH_RGW] Error getting xattr. Err=%d\n", cb_arg.rc); + + /* + * In case of requested xattr is not found, + * API returns 0, and callback is not called. + * Therefore we treat this case as -ENOATTR. + */ + if (rc == 0 && !cb_arg.cb_called) { + DBG_DEBUG("[CEPH_RGW] xattr %s not found.\n", name); + rc = -ENOATTR; + /* fall through */ } out: DBG_DEBUG("[CEPH_RGW] fgetxattr(...) = %d\n", rc); @@ -1008,6 +1045,14 @@ static int vfs_ceph_rgw_fsetxattr(struct vfs_handle_struct *handle, DBG_DEBUG("[CEPH_RGW] fsetxattr [%s] %s\n", fsp_str_dbg(fsp), name); + if (is_special_name(fsp->fsp_name->base_name)) { + DBG_DEBUG( + "[CEPH_RGW] Cannot perform op on special name [%s]\n", + fsp_str_dbg(fsp)); + rc = -EINVAL; + goto out; + } + rc = vfs_ceph_rgw_fetch_fh(handle, fsp, &fh); if (rc != 0) { DBG_ERR("[CEPH_RGW] Unable to fetch handle\n"); @@ -2040,6 +2085,14 @@ static int vfs_ceph_rgw_fremovexattr(struct vfs_handle_struct *handle, struct vfs_ceph_rgw_config, goto out); + if (is_special_name(fsp->fsp_name->base_name)) { + DBG_DEBUG( + "[CEPH_RGW] Cannot perform op on special name [%s]\n", + fsp_str_dbg(fsp)); + rc = -EINVAL; + goto out; + } + rc = vfs_ceph_rgw_fetch_fh(handle, fsp, &fh); if (rc != 0) { DBG_ERR("[CEPH_RGW] Unable to fetch handle\n");