[SCM] Samba Shared Repository - branch v4-25-stable updated

Björn Jacke bjacke at samba.org
Sun Sep 6 15:36:59 UTC 2026


The branch, v4-25-stable has been updated
       via  b5923e8d956 VERSION: Disable GIT_SNAPSHOT for the 4.25.0rc2 release.
       via  00317d9bd33 WHATSNEW: Add release notes for Samba 4.25.0rc2.
       via  0b00baf153f s4:rpc_server/dnsserver: allow dnsserver_db_do_reset_dword() to add new dNSProperty values
       via  e36aee8ca63 s4:rpc_server/dnsserver: fix talloc hierarchy in dnsserver_db_do_reset_dword()
       via  e0fafab4c52 python/tests: add tests for samba-tool dns zoneoptions on a zone without dNSProperty values
       via  825c1030d2f s4:dns_server: change DNS_MAX_UDP_PACKET_LENGTH to 512
       via  120f1c8de80 python:tests/dns: use tcp for the CVE-2018-14629 regression tests
       via  20914734fcc s4:dns_server: avoid layer violation for truncated udp responses.
       via  af3fa1f7996 s4:dns_server: make it more obvious that the DNS over TCP length hdr is u16
       via  d285e69988f s4:kcc: let dns_tombstone_records_zone() skip if fAging is not 1
       via  81059f726fc s4:dns_server: let dns_get_zone_properties() fallback to serverinfo->dwDefault[No]RefreshInterval
       via  a4b9c50ffa5 s4:dns_server: move rpc_server/dnsserver/dnsutils.c to dns_server/dnsserver_utils.c
       via  2ba4e2055cf s4:dns_server: let dns_get_zone_properties() initialize zoneinfo completely.
       via  9ca6c0e526c s4:rpc_server/dnsserver: let dnsserver_init_zoneinfo() fallback to serverinfo->dwDefault[No]RefreshInterval
       via  ec6a582202d s4:rpc_server/dnsserver: define DNS_SERVER_DEFAULT_[NO_]REFRESH_INTERVAL as 24 * 7
       via  ee95e7af9b0 s4:rpc_server/dnsserver: let dnsserver_init_serverinfo() use dns_server_scavenging_interval()
       via  f45e23c381b s4:kcc: let kccsrv_dns_zone_scavenging() use dns_server_scavenging_interval()
       via  f12dd28268c s4:dns_server: add dns_server_scavenging_interval()
       via  6f6d5efa4e0 s4:rpc_server/common: turn lpcfg_dcerpc_server_info() into an inline function
       via  f88a20bd7dc script/autobuild.py: also add .stderr output including backtraces
       via  980de7dd837 libcli/dns: Do not pass NULL pointer to memcpy()
       via  64bf27775a4 s3:wscript_build: let samba-cluster-support depend on ndr-samba
       via  73382bcce3e VERSION: Bump version up to Samba 4.25.0rc2...
       via  f73e0f70ff7 vfs_ceph_rgw: Return ENOATTR for non-existing xattr
       via  6b8676194f6 vfs_ceph_rgw: Add fs_capabilities method
       via  0601b5cab51 vfs_ceph_rgw: add flistxattrs method
      from  c9aab36f124 VERSION: Disable GIT_SNAPSHOT for the Samba 4.25.0rc1 release.

https://git.samba.org/?p=samba.git;a=shortlog;h=v4-25-stable


- Log -----------------------------------------------------------------
-----------------------------------------------------------------------

Summary of changes:
 VERSION                                            |   2 +-
 WHATSNEW.txt                                       |  22 ++-
 lib/param/param.h                                  |   1 -
 libcli/dns/dns.c                                   |   8 +-
 python/samba/tests/dns.py                          |   6 +-
 python/samba/tests/samba_tool/dnscmd.py            |  72 +++++--
 script/autobuild.py                                |  39 +++-
 source3/modules/vfs_ceph_rgw.c                     | 217 +++++++++++++++++++--
 source3/wscript_build                              |   1 +
 source4/dns_server/dns_server.c                    |  99 +++++++---
 source4/dns_server/dns_server.h                    |  14 +-
 source4/dns_server/dnsserver_common.c              |  73 ++++++-
 source4/dns_server/dnsserver_common.h              |   5 +
 .../dnsutils.c => dns_server/dnsserver_utils.c}    |  35 +++-
 source4/dns_server/wscript_build                   |   4 +-
 source4/dsdb/kcc/kcc_periodic.c                    |  12 +-
 source4/dsdb/kcc/scavenge_dns_records.c            |  16 ++
 source4/rpc_server/common/common.h                 |  26 +++
 source4/rpc_server/common/loadparm.c               |  45 -----
 source4/rpc_server/dnsserver/dnsdb.c               | 157 +++++++++++----
 source4/rpc_server/dnsserver/dnsserver.h           |  16 ++
 .../tests/rpc_dns_server_dnsutils_test.c           |   2 +-
 source4/rpc_server/wscript_build                   |   2 -
 23 files changed, 689 insertions(+), 185 deletions(-)
 rename source4/{rpc_server/dnsserver/dnsutils.c => dns_server/dnsserver_utils.c} (93%)
 delete mode 100644 source4/rpc_server/common/loadparm.c


Changeset truncated at 500 lines:

diff --git a/VERSION b/VERSION
index c8c17f7655a..eb0134e760a 100644
--- a/VERSION
+++ b/VERSION
@@ -89,7 +89,7 @@ SAMBA_VERSION_PRE_RELEASE=
 # e.g. SAMBA_VERSION_RC_RELEASE=1                      #
 #  ->  "3.0.0rc1"                                      #
 ########################################################
-SAMBA_VERSION_RC_RELEASE=1
+SAMBA_VERSION_RC_RELEASE=2
 
 ########################################################
 # To mark SVN snapshots this should be set to 'yes'    #
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 4a18ef84130..8ff4a163541 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,7 +1,7 @@
 Release Announcements
 =====================
 
-This is the first release candidate of Samba 4.25.  This is *not*
+This is the second release candidate of Samba 4.25.  This is *not*
 intended for production environments and is designed for testing
 purposes only.  Please report any defects via the Samba bug reporting
 system at https://bugzilla.samba.org/.
@@ -135,7 +135,7 @@ activated automatically, there is nothing to configure or maintain.
 
 On a cluster the currently active level is stored persistently in
 cluster_level.tdb. On a fresh cluster it is initialized with the
-highest level supported by the first node that starts up. From then
+highest level supported by the second node that starts up. From then
 on the level never changes on its own, it is only raised when an
 administrator explicitly asks for it. A node that does not support
 the currently active level refuses to start, which keeps a node
@@ -191,6 +191,24 @@ smb.conf changes
   kdc default domain supported enctypes   New default     AES encryption types (if supported by domain)
 
 
+CHANGES SINCE 4.25.0rc1
+=======================
+
+o  Stefan Metzmacher <metze at samba.org>
+   * BUG 15988: Samba internal DNS service doesn't handle switch from UDP to TCP
+     when packet is larger than 4k
+   * BUG 16194: autobuild failures need to be reported in a more verbose way
+   * BUG 16219: samba-cluster-support should depend on ndr-samba
+   * BUG 16223: DNS scavenging happens even if fAging is FALSE
+   * BUG 16226: samba-tool dns zoneoptions $DC_SERVER_IP
+     _msdcs.addom.samba.example.com -P --aging=1 gives
+     WERR_INTERNAL_DB_ERROR
+
+o  Jennifer Sutton <jennifersutton at catalyst.net.nz>
+   * BUG 16225: dns client problems related to EDNS usage
+
+
+
 KNOWN ISSUES
 ============
 
diff --git a/lib/param/param.h b/lib/param/param.h
index ed10fa9e90d..6cf27c24597 100644
--- a/lib/param/param.h
+++ b/lib/param/param.h
@@ -188,7 +188,6 @@ void lpcfg_smbcli_options(struct loadparm_context *lp_ctx,
 void lpcfg_smbcli_session_options(struct loadparm_context *lp_ctx,
 				 struct smbcli_session_options *options);
 const char *lpcfg_socket_options(struct loadparm_context *);
-struct dcerpc_server_info *lpcfg_dcerpc_server_info(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx);
 struct gensec_settings *lpcfg_gensec_settings(TALLOC_CTX *, struct loadparm_context *);
 
 /* The following definitions come from param/util.c  */
diff --git a/libcli/dns/dns.c b/libcli/dns/dns.c
index 5087715b5e7..2fd4a32f58c 100644
--- a/libcli/dns/dns.c
+++ b/libcli/dns/dns.c
@@ -119,9 +119,11 @@ static struct tevent_req *dns_udp_request_send(
 	if (tevent_req_nomem(udp_q->additional, req)) {
 		return tevent_req_post(req, ev);
 	}
-	memcpy(udp_q->additional,
-	       _q->additional,
-	       sizeof(struct dns_res_rec) * _q->arcount);
+	if (_q->additional != NULL) {
+		memcpy(udp_q->additional,
+		       _q->additional,
+		       sizeof(struct dns_res_rec) * _q->arcount);
+	}
 
 	udp_q->additional[_q->arcount] = (struct dns_res_rec){
 		.name = "",
diff --git a/python/samba/tests/dns.py b/python/samba/tests/dns.py
index 365dfdd6d13..74b2e3a3d1f 100644
--- a/python/samba/tests/dns.py
+++ b/python/samba/tests/dns.py
@@ -909,7 +909,7 @@ class TestComplexQueries(DNSTest):
         self.finish_name_packet(p, questions)
 
         (response, response_packet) =\
-            self.dns_transaction_udp(p, host=self.server_ip)
+            self.dns_transaction_tcp(p, host=self.server_ip)
 
         self.assertEqual(len(response.answers), num_recs_to_enter)
 
@@ -959,7 +959,7 @@ class TestComplexQueries(DNSTest):
         self.finish_name_packet(p, questions)
 
         (response, response_packet) =\
-            self.dns_transaction_udp(p, host=self.server_ip)
+            self.dns_transaction_tcp(p, host=self.server_ip)
 
         self.assertEqual(len(response.answers), num_recs_to_enter)
 
@@ -2248,7 +2248,7 @@ class TestRPCRoundtrip(DNSTest):
 class TestUDPTruncation(DNSTest):
     """
     Samba internal DNS (no EDNS0): if a UDP reply would exceed
-    DNS_MAX_UDP_PACKET_LENGTH (1232) bytes, server should return
+    DNS_MAX_UDP_PACKET_LENGTH (512) bytes, server should return
     a small (<512 bytes) truncated response containing only
     the question (no answers), with TC set.
     TCP must return the full response (no size limit).
diff --git a/python/samba/tests/samba_tool/dnscmd.py b/python/samba/tests/samba_tool/dnscmd.py
index aa475fb84ac..97a7f2f6f55 100644
--- a/python/samba/tests/samba_tool/dnscmd.py
+++ b/python/samba/tests/samba_tool/dnscmd.py
@@ -116,11 +116,12 @@ class DnsCmdTestCase(SambaToolCmdTest):
                 "SRV": bad_srv
         }
 
-    def resetZone(self):
+    def resetZone(self, clear_properties=False):
         self.deleteZone()
-        self.addZone()
+        self.addZone(clear_properties=clear_properties)
 
-    def addZone(self):
+    def addZone(self, clear_properties=False):
+        self.zone_dn = None
         self.zone = "zone"
         result, out, err = self.runsubcmd("dns",
                                           "zonecreate",
@@ -128,6 +129,24 @@ class DnsCmdTestCase(SambaToolCmdTest):
                                           self.zone,
                                           self.creds_string)
         self.assertCmdSuccess(result, out, err)
+        zones = self.samdb.search(base="DC=DomainDnsZones,%s"
+                                  % self.samdb.get_default_basedn(),
+                                  scope=ldb.SCOPE_SUBTREE,
+                                  expression="(objectClass=dnsZone)",
+                                  attrs=["cn"])
+
+        for zone in zones:
+            if self.zone in str(zone.dn):
+                self.zone_dn = zone.dn
+                break
+        self.assertIsNotNone(self.zone_dn)
+        if clear_properties:
+            msg_dict = {
+                "dn": self.zone_dn,
+                "dNSProperty": []
+            }
+            msg = ldb.Message.from_dict(self.samdb, msg_dict, ldb.FLAG_MOD_DELETE)
+            self.samdb.modify(msg)
 
     def deleteZone(self):
         result, out, err = self.runsubcmd("dns",
@@ -948,25 +967,48 @@ class DnsCmdTestCase(SambaToolCmdTest):
         self.assertTrue(out != '')
 
     def test_zoneoptions_aging(self):
-        for options, vals, error in (
-                (['--aging=1'], {'fAging': 'TRUE'}, False),
-                (['--aging=0'], {'fAging': 'FALSE'}, False),
-                (['--aging=-1'], {'fAging': 'FALSE'}, True),
-                (['--aging=2'], {}, True),
-                (['--aging=2', '--norefreshinterval=1'], {}, True),
+        for options, vals, error, clear_properties in (
+                (['--aging=1'], {'fAging': 'TRUE'}, False, False),
+                (['--aging=0'], {'fAging': 'FALSE'}, False, False),
+                (['--aging=-1'], {'fAging': 'FALSE'}, True, False),
+                (['--aging=2'], {}, True, False),
+                (['--aging=2', '--norefreshinterval=1'], {}, True, False),
                 (['--aging=1', '--norefreshinterval=1'],
-                 {'fAging': 'TRUE', 'dwNoRefreshInterval': '1'}, False),
+                 {'fAging': 'TRUE', 'dwNoRefreshInterval': '1'}, False, False),
+                # setting --norefreshinterval=0 results in the server default
                 (['--aging=1', '--norefreshinterval=0'],
-                 {'fAging': 'TRUE', 'dwNoRefreshInterval': '0'}, False),
+                 {'fAging': 'TRUE', 'dwNoRefreshInterval': '168'}, False, False),
                 (['--aging=0', '--norefreshinterval=99', '--refreshinterval=99'],
                  {'fAging': 'FALSE',
                   'dwNoRefreshInterval': '99',
-                  'dwRefreshInterval': '99'}, False),
+                  'dwRefreshInterval': '99'}, False, False),
                 (['--aging=0', '--norefreshinterval=-99', '--refreshinterval=99'],
-                 {}, True),
-                (['--refreshinterval=9999999'], {}, True),
-                (['--norefreshinterval=9999999'], {}, True),
+                 {}, True, False),
+                (['--refreshinterval=9999999'], {}, True, False),
+                (['--norefreshinterval=9999999'], {}, True, False),
+                (['--aging=1', '--norefreshinterval=100', '--refreshinterval=200'],
+                 {'fAging': 'TRUE',
+                  'dwNoRefreshInterval': '100',
+                  'dwRefreshInterval': '200'},
+                  False, True),
+                (['--aging=1'],
+                 {'fAging': 'TRUE',
+                  'dwNoRefreshInterval': '168',
+                  'dwRefreshInterval': '168'},
+                  False, True),
+                (['--norefreshinterval=100'],
+                 {'fAging': 'FALSE',
+                  'dwNoRefreshInterval': '100',
+                  'dwRefreshInterval': '168'},
+                  False, True),
+                (['--refreshinterval=200'],
+                 {'fAging': 'FALSE',
+                  'dwNoRefreshInterval': '168',
+                  'dwRefreshInterval': '200'},
+                  False, True),
                 ):
+            if clear_properties:
+                self.resetZone(clear_properties=True)
             result, out, err = self.runsubcmd("dns",
                                               "zoneoptions",
                                               os.environ["SERVER"],
diff --git a/script/autobuild.py b/script/autobuild.py
index 35cc70b3bf3..9c62c971a06 100755
--- a/script/autobuild.py
+++ b/script/autobuild.py
@@ -1799,19 +1799,44 @@ The top commit for the tree that was built was:
     if add_log_tail and os.access(log_stdout, os.R_OK):
         f = open(log_stdout, 'r')
         lines = f.readlines()
-        log_tail = "".join(lines[-50:])
         num_lines = len(lines)
+        num_tail = 50
+        if num_tail > num_lines:
+            num_tail = num_lines
+        log_tail = "".join(lines[-num_tail:])
+        text += '''
+The last %s lines of %s.stdout:
+
+%s
+    ''' % (num_tail, failed_tag, log_tail)
         log_stderr = "%s/%s.stderr" % (gitroot, failed_tag)
-        if num_lines < 50 and os.access(log_stderr, os.R_OK):
+        if os.access(log_stderr, os.R_OK):
             # Also include stderr (compile failures) if < 50 lines of stdout
             f = open(log_stderr, 'r')
-            log_tail += "".join(f.readlines()[-(50 - num_lines):])
-
-        text += '''
-The last 50 lines of log messages:
+            lines = f.readlines()
+            num_lines = len(lines)
+            num_tail = 0
+            for i in range(num_lines):
+                if lines[i].find('INTERNAL ERROR') != -1:
+                    num_tail = num_lines - i
+                    break
+                if lines[i].find('PANIC') != -1:
+                    num_tail = num_lines - i
+                    break
+                if lines[i].find('BACKTRACE') != -1:
+                    num_tail = num_lines - i
+                    break
+            if num_tail < 50:
+                num_tail = 50
+            if num_tail > num_lines:
+                num_tail = num_lines
+            log_tail = "".join(lines[-num_tail:])
+
+            text += '''
+The last %u lines of %s.stderr:
 
 %s
-    ''' % log_tail
+    ''' % (num_tail, failed_tag, log_tail)
         f.close()
 
     logs = os.path.join(gitroot, 'logs.tar.gz')
diff --git a/source3/modules/vfs_ceph_rgw.c b/source3/modules/vfs_ceph_rgw.c
index 8a7ca204100..fbbec98e3d4 100644
--- a/source3/modules/vfs_ceph_rgw.c
+++ b/source3/modules/vfs_ceph_rgw.c
@@ -90,6 +90,13 @@ struct vfs_ceph_rgw_getxattr_arg {
 	int rc;
 	char *val;
 	size_t size;
+	bool cb_called;
+};
+
+struct vfs_ceph_rgw_lsxattr_arg {
+	int rc;
+	char *list;
+	size_t rem_size;
 };
 
 /*
@@ -896,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)
@@ -904,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;
 	}
@@ -937,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");
@@ -945,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;
 
@@ -956,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);
@@ -1002,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");
@@ -1887,8 +1938,7 @@ static int vfs_ceph_rgw_fstatvfs(struct vfs_handle_struct *handle,
 	 */
 	statbuf->FsIdentifier = (unsigned long int)-1;
 
-	/* We do not have any capabilities defined, returning 0 */
-	statbuf->FsCapabilities = 0;
+	statbuf->FsCapabilities = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
 
 	DBG_DEBUG("[CEPH_RGW] fstatvfs: name=%s f_bsize=%" PRIu64
 		  " f_blocks=%" PRIu64 " f_bfree=%" PRIu64 " f_bavail=%" PRIu64
@@ -2035,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");
@@ -2098,6 +2156,125 @@ out:
 	return status_code(rc);
 }
 
+/*
+ * Callback for rgw_lsxattrs() to build list of attribute names.
+ *
+ * @param attrs: List of attributes from RGW
+ * @param arg: Pointer to vfs_ceph_rgw_lsxattr_arg structure
+ * @param flags: Callback flags (unused)
+ * @return: 0 to continue iteration, RGW_LSXATTR_FLAG_STOP to stop
+ *
+ * Output format: null-separated attribute names (e.g., "user.foo\0user.bar\0")
+ *
+ */
+static int ceph_rgw_lsxattr_cb(rgw_xattrlist *attrs, void *arg, uint32_t flags)
+{
+	uint32_t i;
+	struct vfs_ceph_rgw_lsxattr_arg *cb_arg = arg;
+
+	for (i = 0; i < attrs->xattr_cnt; i++) {
+		const rgw_xattr *attr = &attrs->xattrs[i];
+		uint32_t len = attr->key.len + 1;
+
+		if (len > cb_arg->rem_size) {
+			DBG_DEBUG("[CEPH_RGW] Not enough space for more "
+				  "names\n");
+			cb_arg->rc = -ERANGE;
+			return RGW_LSXATTR_FLAG_STOP;
+		}
+
+		memcpy(cb_arg->list, attr->key.val, attr->key.len);
+		cb_arg->list[attr->key.len] = '\0';
+		DBG_DEBUG("[CEPH_RGW] xattr-name:%s\n", cb_arg->list);
+
+		cb_arg->list += len;
+		cb_arg->rem_size -= len;
+	}
+	return 0;
+}
+
+static ssize_t vfs_ceph_rgw_flistxattr(vfs_handle_struct *handle,
+				       struct files_struct *fsp,
+				       char *list,
+				       size_t size)
+{
+	ssize_t ret = -ENOMEM;
+	struct vfs_ceph_rgw_config *config = NULL;
+	struct vfs_ceph_rgw_fh *fh = NULL;
+	struct vfs_ceph_rgw_lsxattr_arg cb_arg = {};
+
+	START_PROFILE_X(SNUM(handle->conn), syscall_flistxattr);


-- 
Samba Shared Repository



More information about the samba-cvs mailing list