[SCM] Samba Shared Repository - branch master updated
Volker Lendecke
vlendec at samba.org
Tue Sep 8 16:40:02 UTC 2026
The branch, master has been updated
via 1f6909cbb7a vfs_fruit: Allow renames for long filenames that don't have a ._ sidecar
via 1b2f40ee33c vfs_fruit: Fix namelength overflow errors in fruit_rename
via 0a620af4ac9 tests: Add vfs_fruit rename regression tests for long ._ files
via caefa8cf552 pylibsmb: Make "afpinfo_pack" available for python-level tests
via e4ccd8f8165 lib: Move afpinfo functions from adouble.c into its own subsystem
via ed8ff6ccd77 pylibsmb: Add AFPINFO_STREAM_NAME and AFPRESOURCE_STREAM_NAME constants
from 96fe1454cb7 npsd_echo_server: Simplify npsd_echo_accept_client
https://git.samba.org/?p=samba.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 1f6909cbb7a2fbd0784a72d4d2660b0f697d39d0
Author: Volker Lendecke <vl at samba.org>
Date: Tue Sep 8 11:15:16 2026 +0200
vfs_fruit: Allow renames for long filenames that don't have a ._ sidecar
The kernel checks name length before existence, so we get ENAMETOOLONG
on a ._ sidecar rename even if it does not exist. Allow this.
Adapt the test directly: With the test still throwing an exception before the
vfs_fruit fix we can't easily put the test into knownfail.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16238
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
Autobuild-User(master): Volker Lendecke <vl at samba.org>
Autobuild-Date(master): Tue Sep 8 16:39:21 UTC 2026 on atb-devel-224
commit 1b2f40ee33cdb931f849a2a8211f6b2c729b39b7
Author: Volker Lendecke <vl at samba.org>
Date: Mon Sep 7 17:39:28 2026 +0200
vfs_fruit: Fix namelength overflow errors in fruit_rename
Renaming the ._ sidecar files can fail due to name length
restrictions, ._ is longer than the base file. Rename the sidecar file
first, so that we don't leave stale sidecars around if the base rename
succeeded but the sidecar rename failed due to name restrictions.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16238
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
commit 0a620af4ac9d322a80e69e6b77b5bf783404e0a0
Author: Volker Lendecke <vl at samba.org>
Date: Mon Sep 7 17:12:05 2026 +0200
tests: Add vfs_fruit rename regression tests for long ._ files
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16238
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
commit caefa8cf552c75655e9ac7b10cdc335e3e417d29
Author: Volker Lendecke <vl at samba.org>
Date: Mon Sep 7 17:32:39 2026 +0200
pylibsmb: Make "afpinfo_pack" available for python-level tests
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16238
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
commit e4ccd8f8165422e66f9de28e6861ccd2d62be712
Author: Volker Lendecke <vl at samba.org>
Date: Mon Sep 7 17:04:28 2026 +0200
lib: Move afpinfo functions from adouble.c into its own subsystem
Makes it easier to expose via python
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16238
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
commit ed8ff6ccd77b67736ed566659ae780e4f77cc94f
Author: Volker Lendecke <vl at samba.org>
Date: Mon Sep 7 16:58:50 2026 +0200
pylibsmb: Add AFPINFO_STREAM_NAME and AFPRESOURCE_STREAM_NAME constants
To be used in tests soon
BUG: https://bugzilla.samba.org/show_bug.cgi?id=16238
Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
-----------------------------------------------------------------------
Summary of changes:
python/samba/tests/libsmb-basic.py | 80 +++++++++++++++++
source3/lib/adouble.c | 70 +--------------
source3/lib/adouble.h | 5 +-
source3/lib/afpinfo.c | 91 +++++++++++++++++++
source3/{utils/passwd_proto.h => lib/afpinfo.h} | 24 ++---
source3/libsmb/pylibsmb.c | 58 +++++++++++++
source3/modules/vfs_fruit.c | 111 +++++++++++++++++-------
source3/wscript_build | 9 +-
8 files changed, 330 insertions(+), 118 deletions(-)
create mode 100644 source3/lib/afpinfo.c
copy source3/{utils/passwd_proto.h => lib/afpinfo.h} (58%)
Changeset truncated at 500 lines:
diff --git a/python/samba/tests/libsmb-basic.py b/python/samba/tests/libsmb-basic.py
index 20d3dd48c3c..56d4f86dbe6 100644
--- a/python/samba/tests/libsmb-basic.py
+++ b/python/samba/tests/libsmb-basic.py
@@ -263,6 +263,86 @@ class LibsmbTestCase(samba.tests.libsmb.LibsmbTests):
c.deltree("teststreams")
+ def test_fruit_rename_long_to_short_name(self):
+ """
+ Test renaming a long src name to a short one where the
+ long name pushes the ._ sidecar file over the ENAMETOOLONG
+ error. This can only happen when there is no ._ sidecar, but
+ the rename syscall will still return ENAMETOOLONG. Handle that
+ properly for the src filename to allow the base rename.
+ """
+ c = libsmb.Conn(self.server_ip, "vfs_fruit", self.lp, self.creds)
+
+ srcname = "s" * 254
+ dstname = "d" * 10
+
+ self.clean_file(c, srcname)
+ self.clean_file(c, dstname)
+
+ try:
+ fnum = c.create(srcname,
+ DesiredAccess=security.SEC_FILE_ALL,
+ CreateDisposition=libsmb.FILE_CREATE)
+ c.close(fnum)
+
+ c.rename(srcname, dstname)
+
+ ls = [f['name'] for f in c.list("\\")]
+ self.assertNotIn(srcname, ls)
+ self.assertIn(dstname, ls)
+ finally:
+ self.clean_file(c, srcname)
+ self.clean_file(c, dstname)
+
+ def create_appledouble(self, c, filename):
+ """Make vfs_fruit create a real "._<filename>" AppleDouble
+ file for filename on disk.
+ """
+ finder_info = b'\x00' * 31 + b'\x01'
+ c.savefile(filename + libsmb.AFPINFO_STREAM_NAME,
+ libsmb.afpinfo_pack(finder_info))
+
+ rsrc_fnum = c.create(filename + libsmb.AFPRESOURCE_STREAM_NAME,
+ DesiredAccess=security.SEC_FILE_ALL,
+ CreateDisposition=libsmb.FILE_OPEN_IF)
+ c.write(rsrc_fnum, b'\x01' * 16, 0)
+ c.close(rsrc_fnum)
+
+ def test_fruit_rename_short_to_long_name(self):
+ """
+ Rename a short file with ._ sidecar file to a long file name
+ driving the ._ sidecar over ENAMETOOLONG. Make sure that the
+ base file rename did not happen at all.
+ """
+ c = libsmb.Conn(self.server_ip, "vfs_fruit", self.lp, self.creds)
+
+ srcname = "s" * 10
+ dstname = "d" * 254
+
+ self.clean_file(c, srcname)
+ self.clean_file(c, dstname)
+
+ try:
+ fnum = c.create(srcname,
+ DesiredAccess=security.SEC_FILE_ALL,
+ CreateDisposition=libsmb.FILE_CREATE)
+ c.close(fnum)
+
+ # Force creation of a real "._<srcname>" AppleDouble file
+ self.create_appledouble(c, srcname)
+
+ with self.assertRaises(NTSTATUSError) as cm:
+ c.rename(srcname, dstname)
+ self.assertEqual(cm.exception.args[0],
+ ntstatus.NT_STATUS_OBJECT_NAME_INVALID)
+
+ ls = [f['name'] for f in c.list("\\")]
+ self.assertIn(srcname, ls)
+ self.assertNotIn(dstname, ls)
+ finally:
+ self.clean_file(c, srcname)
+ self.clean_file(c, dstname)
+
if __name__ == "__main__":
import unittest
unittest.main()
diff --git a/source3/lib/adouble.c b/source3/lib/adouble.c
index 5e445f0cdb8..b4fc1013327 100644
--- a/source3/lib/adouble.c
+++ b/source3/lib/adouble.c
@@ -19,6 +19,7 @@
#include "includes.h"
#include "adouble.h"
+#include "lib/afpinfo.h"
#include "MacExtensions.h"
#include "string_replace.h"
#include "smbd/smbd.h"
@@ -2801,75 +2802,6 @@ struct smb_filename *adouble_name(TALLOC_CTX *mem_ctx,
return cp_smb_filename(mem_ctx, &ad_fname);
}
-/**
- * Allocate and initialize an AfpInfo struct
- **/
-AfpInfo *afpinfo_new(TALLOC_CTX *ctx)
-{
- AfpInfo *ai = talloc(ctx, AfpInfo);
- if (ai == NULL) {
- return NULL;
- }
- *ai = (AfpInfo){
- .afpi_Signature = AFP_Signature,
- .afpi_Version = AFP_Version,
- .afpi_BackupTime = AD_DATE_START,
- };
- return ai;
-}
-
-/**
- * Pack an AfpInfo struct into a buffer
- *
- * Buffer size must be at least AFP_INFO_SIZE
- * Returns size of packed buffer
- **/
-ssize_t afpinfo_pack(const AfpInfo *ai, char *buf)
-{
- memset(buf, 0, AFP_INFO_SIZE);
-
- RSIVAL(buf, 0, ai->afpi_Signature);
- RSIVAL(buf, 4, ai->afpi_Version);
- RSIVAL(buf, 12, ai->afpi_BackupTime);
- memcpy(buf + 16, ai->afpi_FinderInfo, sizeof(ai->afpi_FinderInfo));
-
- return AFP_INFO_SIZE;
-}
-
-/**
- * Unpack a buffer into a AfpInfo structure
- *
- * Buffer size must be at least AFP_INFO_SIZE
- * Returns allocated AfpInfo struct
- **/
-AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data, bool validate)
-{
- AfpInfo *ai = talloc_zero(ctx, AfpInfo);
- if (ai == NULL) {
- return NULL;
- }
-
- ai->afpi_Signature = RIVAL(data, 0);
- ai->afpi_Version = RIVAL(data, 4);
- ai->afpi_BackupTime = RIVAL(data, 12);
- memcpy(ai->afpi_FinderInfo, (const char *)data + 16,
- sizeof(ai->afpi_FinderInfo));
-
- if (validate) {
- if (ai->afpi_Signature != AFP_Signature
- || ai->afpi_Version != AFP_Version)
- {
- DEBUG(1, ("Bad AfpInfo signature or version\n"));
- TALLOC_FREE(ai);
- }
- } else {
- ai->afpi_Signature = AFP_Signature;
- ai->afpi_Version = AFP_Version;
- }
-
- return ai;
-}
-
bool adouble_buf_parse(const uint8_t *buf,
size_t buflen,
struct adouble_buf *ad)
diff --git a/source3/lib/adouble.h b/source3/lib/adouble.h
index 8fd4b7e69b6..2e3e6e15b5b 100644
--- a/source3/lib/adouble.h
+++ b/source3/lib/adouble.h
@@ -20,6 +20,7 @@
#ifndef _ADOUBLE_H_
#define _ADOUBLE_H_
+#include "includes.h"
#include "MacExtensions.h"
#define ADOUBLE_NAME_PREFIX "._"
@@ -187,10 +188,6 @@ int adouble_path(TALLOC_CTX *ctx,
struct smb_filename *adouble_name(TALLOC_CTX *mem_ctx,
const struct smb_filename *base);
-AfpInfo *afpinfo_new(TALLOC_CTX *ctx);
-ssize_t afpinfo_pack(const AfpInfo *ai, char *buf);
-AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data, bool validate);
-
struct adouble_buf {
uint32_t magic;
uint32_t version;
diff --git a/source3/lib/afpinfo.c b/source3/lib/afpinfo.c
new file mode 100644
index 00000000000..9f629157120
--- /dev/null
+++ b/source3/lib/afpinfo.c
@@ -0,0 +1,91 @@
+/*
+ * AFP_AfpInfo packing/unpacking helpers
+ *
+ * Copyright (C) Ralph Boehme, 2019
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "afpinfo.h"
+#include "adouble.h"
+
+/**
+ * Allocate and initialize an AfpInfo struct
+ **/
+AfpInfo *afpinfo_new(TALLOC_CTX *ctx)
+{
+ AfpInfo *ai = talloc(ctx, AfpInfo);
+ if (ai == NULL) {
+ return NULL;
+ }
+ *ai = (AfpInfo){
+ .afpi_Signature = AFP_Signature,
+ .afpi_Version = AFP_Version,
+ .afpi_BackupTime = AD_DATE_START,
+ };
+ return ai;
+}
+
+/**
+ * Pack an AfpInfo struct into a buffer
+ *
+ * Buffer size must be at least AFP_INFO_SIZE
+ * Returns size of packed buffer
+ **/
+ssize_t afpinfo_pack(const AfpInfo *ai, char *buf)
+{
+ memset(buf, 0, AFP_INFO_SIZE);
+
+ RSIVAL(buf, 0, ai->afpi_Signature);
+ RSIVAL(buf, 4, ai->afpi_Version);
+ RSIVAL(buf, 12, ai->afpi_BackupTime);
+ memcpy(buf + 16, ai->afpi_FinderInfo, sizeof(ai->afpi_FinderInfo));
+
+ return AFP_INFO_SIZE;
+}
+
+/**
+ * Unpack a buffer into a AfpInfo structure
+ *
+ * Buffer size must be at least AFP_INFO_SIZE
+ * Returns allocated AfpInfo struct
+ **/
+AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data, bool validate)
+{
+ AfpInfo *ai = talloc_zero(ctx, AfpInfo);
+ if (ai == NULL) {
+ return NULL;
+ }
+
+ ai->afpi_Signature = RIVAL(data, 0);
+ ai->afpi_Version = RIVAL(data, 4);
+ ai->afpi_BackupTime = RIVAL(data, 12);
+ memcpy(ai->afpi_FinderInfo, (const char *)data + 16,
+ sizeof(ai->afpi_FinderInfo));
+
+ if (validate) {
+ if (ai->afpi_Signature != AFP_Signature
+ || ai->afpi_Version != AFP_Version)
+ {
+ DEBUG(1, ("Bad AfpInfo signature or version\n"));
+ TALLOC_FREE(ai);
+ }
+ } else {
+ ai->afpi_Signature = AFP_Signature;
+ ai->afpi_Version = AFP_Version;
+ }
+
+ return ai;
+}
diff --git a/source3/utils/passwd_proto.h b/source3/lib/afpinfo.h
similarity index 58%
copy from source3/utils/passwd_proto.h
copy to source3/lib/afpinfo.h
index 40998998ae7..5c9557f1ed3 100644
--- a/source3/utils/passwd_proto.h
+++ b/source3/lib/afpinfo.h
@@ -1,10 +1,7 @@
/*
- * Unix SMB/CIFS implementation.
- * collected prototypes header
+ * AFP_AfpInfo packing/unpacking helpers
*
- * frozen from "make proto" in May 2008
- *
- * Copyright (C) Michael Adam 2008
+ * Copyright (C) Ralph Boehme, 2019
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -13,19 +10,22 @@
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _PASSWD_PROTO_H_
-#define _PASSWD_PROTO_H_
-
+#ifndef _AFPINFO_H_
+#define _AFPINFO_H_
-/* The following definitions come from utils/passwd_util.c */
+#include "replace.h"
+#include <talloc.h>
+#include "MacExtensions.h"
-char *get_pass( const char *prompt, bool stdin_get);
+AfpInfo *afpinfo_new(TALLOC_CTX *ctx);
+ssize_t afpinfo_pack(const AfpInfo *ai, char *buf);
+AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data, bool validate);
-#endif /* _PASSWD_PROTO_H_ */
+#endif
diff --git a/source3/libsmb/pylibsmb.c b/source3/libsmb/pylibsmb.c
index 6013ee21e3f..5e65a867aad 100644
--- a/source3/libsmb/pylibsmb.c
+++ b/source3/libsmb/pylibsmb.c
@@ -62,6 +62,7 @@ c = libsmb.Conn("127.0.0.1",
#include "auth/credentials/pycredentials.h"
#include "trans2.h"
#include "libsmb/clirap.h"
+#include "lib/afpinfo.h"
#include "librpc/rpc/pyrpc_util.h"
#include "librpc/gen_ndr/ndr_security.h"
@@ -1429,6 +1430,50 @@ static PyObject *py_unix_mode_to_wire(struct py_cli_state *self,
return v;
}
+static PyObject *py_afpinfo_pack(PyObject *module,
+ PyObject *args,
+ PyObject *kwds)
+{
+ static const char *kwlist[] = {"finder_info", NULL};
+ TALLOC_CTX *frame = talloc_stackframe();
+ AfpInfo *ai = NULL;
+ char *finder_info = NULL;
+ Py_ssize_t finder_info_len = 0;
+ char buf[AFP_INFO_SIZE];
+ PyObject *result = NULL;
+ bool ok;
+
+ ok = ParseTupleAndKeywords(args,
+ kwds,
+ PYARG_BYTES_LEN,
+ kwlist,
+ &finder_info,
+ &finder_info_len);
+ if (!ok) {
+ goto fail;
+ }
+
+ if (finder_info_len != AFP_FinderSize) {
+ PyErr_Format(PyExc_ValueError,
+ "finder_info must be %d bytes",
+ AFP_FinderSize);
+ goto fail;
+ }
+
+ ai = afpinfo_new(frame);
+ if (ai == NULL) {
+ result = PyErr_NoMemory();
+ goto fail;
+ }
+ memcpy(ai->afpi_FinderInfo, finder_info, AFP_FinderSize);
+ afpinfo_pack(ai, buf);
+
+ result = PyBytes_FromStringAndSize(buf, sizeof(buf));
+fail:
+ TALLOC_FREE(frame);
+ return result;
+}
+
static PyObject *py_cli_qfileinfo(struct py_cli_state *self, PyObject *args)
{
TALLOC_CTX *frame = talloc_stackframe();
@@ -3522,6 +3567,14 @@ static PyMethodDef py_libsmb_methods[] = {
METH_VARARGS,
"Convert posix wire format mode to mode_t",
},
+ {
+ "afpinfo_pack",
+ PY_DISCARD_FUNC_SIG(PyCFunction, py_afpinfo_pack),
+ METH_VARARGS | METH_KEYWORDS,
+ "afpinfo_pack(finder_info) -> bytes\n\n"
+ "\t\tPack an AfpInfo structure for the AFP_AfpInfo "
+ "stream with a caller supplied 32 byte Finder Info blob.",
+ },
{0},
};
@@ -3815,5 +3868,10 @@ MODULE_INIT_FUNC(libsmb_samba_cwrapper)
ADD_FLAGS(SMB2_CLOSE_FLAGS_FULL_INFORMATION);
+#define ADD_TEXT(val) PyModule_AddObject(m, #val, PyUnicode_FromString(val))
+
+ ADD_TEXT(AFPINFO_STREAM_NAME);
+ ADD_TEXT(AFPRESOURCE_STREAM_NAME);
+
return m;
}
diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c
index f41b355a0de..4a348e02cbd 100644
--- a/source3/modules/vfs_fruit.c
+++ b/source3/modules/vfs_fruit.c
@@ -35,6 +35,7 @@
#include "string_replace.h"
#include "hash_inode.h"
#include "lib/adouble.h"
+#include "lib/afpinfo.h"
#include "lib/util_macstreams.h"
#include "source3/smbd/dir.h"
#include "lib/util/smb_strtox.h"
@@ -1931,45 +1932,95 @@ static int fruit_renameat(struct vfs_handle_struct *handle,
return -1;
}
- rc = SMB_VFS_NEXT_RENAMEAT(handle,
- src_dirfsp,
- smb_fname_src,
- dst_dirfsp,
- smb_fname_dst,
- how);
- if (rc != 0) {
- return -1;
- }
-
- if ((config->rsrc != FRUIT_RSRC_ADFILE) ||
- (!S_ISREG(smb_fname_src->st.st_ex_mode)))
+ if ((config->rsrc == FRUIT_RSRC_ADFILE) &&
+ S_ISREG(smb_fname_src->st.st_ex_mode))
{
- return 0;
- }
+ /*
+ * Rename the AppleDouble sidecar file before the base
+ * file. If we renamed the base file first and this
+ * failed, eg because appending the "._" prefix to the
+ * destination name overflows NAME_MAX, the sidecar
+ * file would be left behind orphaned under its old
+ * name.
+ */
+ rc = adouble_path(talloc_tos(),
+ smb_fname_src,
+ &src_adp_smb_fname);
+ if (rc != 0) {
+ goto done;
+ }
- rc = adouble_path(talloc_tos(), smb_fname_src, &src_adp_smb_fname);
- if (rc != 0) {
- goto done;
- }
+ rc = adouble_path(talloc_tos(),
+ smb_fname_dst,
+ &dst_adp_smb_fname);
+ if (rc != 0) {
+ goto done;
+ }
- rc = adouble_path(talloc_tos(), smb_fname_dst, &dst_adp_smb_fname);
- if (rc != 0) {
- goto done;
--
Samba Shared Repository
More information about the samba-cvs
mailing list