vfs_streams_xattr: stream name prefix and type suffix
Ralph Böhme
rb at sernet.de
Wed May 21 05:47:53 MDT 2014
Hi all!
I'm trying to figure out a proper solution such that xattrs sent by an
OS X SMB client as named streams are stored on disk on the server by
vfs_streams_xattr in a way that's compatible with the way other
protocols use xattr names.
Using vfs_streams_xattr for named streams support in Samba results in
all (this is simplified) streams stored on disk with a name
"user.DosStream.NAME:$DATA" where NAME is the name of the stream.
As the OS X SMB client sends xattrs as named streams across the wire,
an xattr that is created by the client with a name "foo" is stored on
the server as "user.DosStream.foo:$DATA".
Accessing the same filesystem with other protocols, eg AFP, would
expect "user.foo" as xattr name.
It would be nice to make the module behaviour configurable:
1) a string option for the prefix (with the previous value as default:
"user.DosStream.")
2) a boolean that controls whether the stream type ("$DATA") name is
appended to the xattr name (with a default of true which resembles
previous behaviour)
Attached patches implement this. The initial patch makes a private
function public. I'm then calling that function from the VFS module
for checking againt the private Samba xattr namespace.
With the patches applied, adding the following to smb.conf
streams_xattr:prefix = user.
streams_xattr:store_stream_type = no
gives the desired behaviour.
Thoughts?
Thanks!
-Ralph
--
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de,mailto:kontakt@sernet.de
-------------- next part --------------
>From 066fcf3c5bb414b84a349a1a5fda07e3e0308593 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <rb at sernet.de>
Date: Wed, 21 May 2014 11:52:27 +0200
Subject: [PATCH 1/2] Convert samba_private_attr_name() to a public function
Signed-off-by: Ralph Boehme <rb at sernet.de>
---
source3/modules/vfs_streams_xattr.c | 3 +++
source3/smbd/proto.h | 1 +
source3/smbd/trans2.c | 2 +-
3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c
index 5e9bd3e..5ff4f82 100644
--- a/source3/modules/vfs_streams_xattr.c
+++ b/source3/modules/vfs_streams_xattr.c
@@ -674,6 +674,9 @@ static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
prefix_len) != 0) {
continue;
}
+ if (samba_private_attr_name(names[i])) {
+ continue;
+ }
status = get_ea_value(names, conn, fsp, fname, names[i], &ea);
if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index f598816..3c6accf 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -1056,6 +1056,7 @@ NTSTATUS check_access(connection_struct *conn,
uint32_t access_mask);
uint64_t smb_roundup(connection_struct *conn, uint64_t val);
uint64_t get_FileIndex(connection_struct *conn, const SMB_STRUCT_STAT *psbuf);
+bool samba_private_attr_name(const char *unix_ea_name);
NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn,
files_struct *fsp, const char *fname,
const char *ea_name, struct ea_struct *pea);
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 4afb27e..aeada68 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -120,7 +120,7 @@ uint64_t get_FileIndex(connection_struct *conn, const SMB_STRUCT_STAT *psbuf)
Refuse to allow clients to overwrite our private xattrs.
****************************************************************************/
-static bool samba_private_attr_name(const char *unix_ea_name)
+bool samba_private_attr_name(const char *unix_ea_name)
{
static const char * const prohibited_ea_names[] = {
SAMBA_POSIX_INHERITANCE_EA_NAME,
--
1.8.5.3
-------------- next part --------------
>From 65c09e51770d77f88f37233383038b56d0ffb031 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <rb at sernet.de>
Date: Tue, 20 May 2014 15:17:01 +0200
Subject: [PATCH 2/2] vfs_streams_xattr: add options "prefix" and
"store_stream_type"
Add module options that can be used to configure the stream prefix the
module uses (option "prefix", a string) and whether the stream type
"$DATA" is appended to the xattr name on disk (option
"store_stream_type", a boolean).
The default "prefix" is "user.DosStream" and the default for
"store_stream_type" is true, this gives unchanged default behaviour
when not specifying this option.
OS X SMB clients will send xattrs as named streams over the wire, by
setting the options to the following values
streams_xattr:prefix = user.
streams_xattr:store_stream_type = no
OS X xattrs will be stored on disk on the server with their unmodified
names and as such provide interoperability with other protocols like
AFP.
Signed-off-by: Ralph Boehme <rb at sernet.de>
---
source3/modules/vfs_streams_xattr.c | 93 +++++++++++++++++++++++++++++--------
1 file changed, 73 insertions(+), 20 deletions(-)
diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c
index 5ff4f82..50f227d 100644
--- a/source3/modules/vfs_streams_xattr.c
+++ b/source3/modules/vfs_streams_xattr.c
@@ -29,6 +29,12 @@
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_VFS
+struct streams_xattr_config {
+ const char *prefix;
+ size_t prefix_len;
+ bool store_stream_type;
+};
+
struct stream_io {
char *base;
char *xattr_name;
@@ -95,16 +101,21 @@ static ssize_t get_xattr_size(connection_struct *conn,
* Given a stream name, populate xattr_name with the xattr name to use for
* accessing the stream.
*/
-static NTSTATUS streams_xattr_get_name(TALLOC_CTX *ctx,
+static NTSTATUS streams_xattr_get_name(vfs_handle_struct *handle,
+ TALLOC_CTX *ctx,
const char *stream_name,
char **xattr_name)
{
char *stype;
+ struct streams_xattr_config *config;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config,
+ return NT_STATUS_UNSUCCESSFUL);
stype = strchr_m(stream_name + 1, ':');
*xattr_name = talloc_asprintf(ctx, "%s%s",
- SAMBA_XATTR_DOSSTREAM_PREFIX,
+ config->prefix,
stream_name + 1);
if (*xattr_name == NULL) {
return NT_STATUS_NO_MEMORY;
@@ -112,8 +123,9 @@ static NTSTATUS streams_xattr_get_name(TALLOC_CTX *ctx,
if (stype == NULL) {
/* Append an explicit stream type if one wasn't specified. */
- *xattr_name = talloc_asprintf(ctx, "%s:$DATA",
- *xattr_name);
+ *xattr_name = talloc_asprintf(ctx, "%s%s",
+ *xattr_name,
+ config->store_stream_type ? ":$DATA" : "");
if (*xattr_name == NULL) {
return NT_STATUS_NO_MEMORY;
}
@@ -145,7 +157,7 @@ static bool streams_xattr_recheck(struct stream_io *sio)
return false;
}
- status = streams_xattr_get_name(talloc_tos(),
+ status = streams_xattr_get_name(sio->handle, talloc_tos(),
sio->fsp->fsp_name->stream_name,
&xattr_name);
if (!NT_STATUS_IS_OK(status)) {
@@ -271,7 +283,7 @@ static int streams_xattr_stat(vfs_handle_struct *handle,
}
/* Derive the xattr name to lookup. */
- status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
+ status = streams_xattr_get_name(handle, talloc_tos(), smb_fname->stream_name,
&xattr_name);
if (!NT_STATUS_IS_OK(status)) {
errno = map_errno_from_nt_status(status);
@@ -322,7 +334,7 @@ static int streams_xattr_lstat(vfs_handle_struct *handle,
}
/* Derive the xattr name to lookup. */
- status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
+ status = streams_xattr_get_name(handle, talloc_tos(), smb_fname->stream_name,
&xattr_name);
if (!NT_STATUS_IS_OK(status)) {
errno = map_errno_from_nt_status(status);
@@ -386,7 +398,7 @@ static int streams_xattr_open(vfs_handle_struct *handle,
return ret;
}
- status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
+ status = streams_xattr_get_name(handle, talloc_tos(), smb_fname->stream_name,
&xattr_name);
if (!NT_STATUS_IS_OK(status)) {
errno = map_errno_from_nt_status(status);
@@ -541,7 +553,7 @@ static int streams_xattr_unlink(vfs_handle_struct *handle,
return ret;
}
- status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
+ status = streams_xattr_get_name(handle, talloc_tos(), smb_fname->stream_name,
&xattr_name);
if (!NT_STATUS_IS_OK(status)) {
errno = map_errno_from_nt_status(status);
@@ -597,14 +609,14 @@ static int streams_xattr_rename(vfs_handle_struct *handle,
}
/* Get the xattr names. */
- status = streams_xattr_get_name(talloc_tos(),
+ status = streams_xattr_get_name(handle, talloc_tos(),
smb_fname_src->stream_name,
&src_xattr_name);
if (!NT_STATUS_IS_OK(status)) {
errno = map_errno_from_nt_status(status);
goto fail;
}
- status = streams_xattr_get_name(talloc_tos(),
+ status = streams_xattr_get_name(handle, talloc_tos(),
smb_fname_dst->stream_name,
&dst_xattr_name);
if (!NT_STATUS_IS_OK(status)) {
@@ -650,7 +662,7 @@ static int streams_xattr_rename(vfs_handle_struct *handle,
return ret;
}
-static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
+static NTSTATUS walk_xattr_streams(vfs_handle_struct *handle, files_struct *fsp,
const char *fname,
bool (*fn)(struct ea_struct *ea,
void *private_data),
@@ -659,9 +671,12 @@ static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
NTSTATUS status;
char **names;
size_t i, num_names;
- size_t prefix_len = strlen(SAMBA_XATTR_DOSSTREAM_PREFIX);
+ struct streams_xattr_config *config;
- status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
+ SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config,
+ return NT_STATUS_UNSUCCESSFUL);
+
+ status = get_ea_names_from_file(talloc_tos(), handle->conn, fsp, fname,
&names, &num_names);
if (!NT_STATUS_IS_OK(status)) {
return status;
@@ -670,23 +685,24 @@ static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
for (i=0; i<num_names; i++) {
struct ea_struct ea;
- if (strncmp(names[i], SAMBA_XATTR_DOSSTREAM_PREFIX,
- prefix_len) != 0) {
+ if (strncmp(names[i], config->prefix,
+ config->prefix_len) != 0) {
continue;
}
if (samba_private_attr_name(names[i])) {
continue;
}
- status = get_ea_value(names, conn, fsp, fname, names[i], &ea);
+ status = get_ea_value(names, handle->conn, fsp, fname, names[i], &ea);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("Could not get ea %s for file %s: %s\n",
names[i], fname, nt_errstr(status)));
continue;
}
- ea.name = talloc_asprintf(ea.value.data, ":%s",
- names[i] + prefix_len);
+ ea.name = talloc_asprintf(ea.value.data, ":%s%s",
+ names[i] + config->prefix_len,
+ config->store_stream_type ? "" : ":$DATA");
if (ea.name == NULL) {
DEBUG(0, ("talloc failed\n"));
continue;
@@ -806,7 +822,7 @@ static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle,
*/
status = NT_STATUS_OK;
} else {
- status = walk_xattr_streams(handle->conn, fsp, fname,
+ status = walk_xattr_streams(handle, fsp, fname,
collect_one_stream, &state);
}
@@ -832,6 +848,42 @@ static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle,
return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS;
}
+static int streams_xattr_connect(vfs_handle_struct *handle, const char *service, const char *user)
+{
+ struct streams_xattr_config *config;
+ const char *default_prefix = SAMBA_XATTR_DOSSTREAM_PREFIX;
+ const char **prefix;
+
+ config = talloc_zero(handle->conn, struct streams_xattr_config);
+ if (!config) {
+ DEBUG(1, ("talloc_zero() failed\n"));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ prefix = lp_parm_string_list(SNUM(handle->conn),
+ "streams_xattr", "prefix",
+ &default_prefix);
+ if (prefix) {
+ config->prefix = *prefix;
+ } else {
+ config->prefix = talloc_strdup(config, "");
+ }
+ config->prefix_len = strlen(config->prefix);
+ DEBUG(10, ("streams_xattr using stream prefix: %s\n", config->prefix));
+
+ config->store_stream_type = lp_parm_bool(SNUM(handle->conn),
+ "streams_xattr",
+ "store_stream_type",
+ true);
+
+ SMB_VFS_HANDLE_SET_DATA(handle, config,
+ NULL, struct stream_xattr_config,
+ return -1);
+
+ return 0;
+}
+
static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
files_struct *fsp, const void *data,
size_t n, off_t offset)
@@ -1034,6 +1086,7 @@ static int streams_xattr_fallocate(struct vfs_handle_struct *handle,
static struct vfs_fn_pointers vfs_streams_xattr_fns = {
.fs_capabilities_fn = streams_xattr_fs_capabilities,
+ .connect_fn = streams_xattr_connect,
.open_fn = streams_xattr_open,
.stat_fn = streams_xattr_stat,
.fstat_fn = streams_xattr_fstat,
--
1.8.5.3
More information about the samba-technical
mailing list