[SCM] Samba Shared Repository - branch v3-2-test updated - initial-v3-2-test-1535-gd813bd9

Volker Lendecke vl at samba.org
Sat Jan 19 22:50:08 GMT 2008


The branch, v3-2-test has been updated
       via  d813bd9e02d9baf916eb96c478be89f0c435e07c (commit)
       via  9f0d778490415b05224f36287df999672ee16928 (commit)
       via  c34d729c7c0600a8f11bf7e489a634a4e37fe88e (commit)
      from  999647329028147d7c29a3348202641b3e03430e (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-2-test


- Log -----------------------------------------------------------------
commit d813bd9e02d9baf916eb96c478be89f0c435e07c
Author: Volker Lendecke <vl at samba.org>
Date:   Sat Jan 19 23:10:09 2008 +0100

    Add "split_ntfs_stream_name()" together with a torture test

commit 9f0d778490415b05224f36287df999672ee16928
Author: Volker Lendecke <vl at samba.org>
Date:   Sat Jan 19 22:44:55 2008 +0100

    Add an error mapping for ENOATTR

commit c34d729c7c0600a8f11bf7e489a634a4e37fe88e
Author: Volker Lendecke <vl at samba.org>
Date:   Sat Jan 19 20:41:15 2008 +0100

    Add the STREAMINFO vfs call
    
    Based on jpeach's work, modified the streaminfo prototype
    
    Make use of it in trans2.c together with marshall_stream_info()

-----------------------------------------------------------------------

Summary of changes:
 source/include/vfs.h         |   10 ++++
 source/include/vfs_macros.h  |    3 +
 source/lib/errmap_unix.c     |    3 +
 source/lib/util.c            |   90 +++++++++++++++++++++++++++++++++
 source/modules/vfs_default.c |   59 ++++++++++++++++++++++
 source/smbd/nttrans.c        |    3 +
 source/smbd/trans2.c         |  112 +++++++++++++++++++++++++++++++++++++-----
 source/torture/torture.c     |   69 ++++++++++++++++++++++++++
 8 files changed, 336 insertions(+), 13 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source/include/vfs.h b/source/include/vfs.h
index 3109a5c..cda28a1 100644
--- a/source/include/vfs.h
+++ b/source/include/vfs.h
@@ -104,6 +104,7 @@
 /* Leave at 22 - not yet released. Remove parameter fromfd from sendfile. - obnox */
 /* Leave at 22 - not yet released. Remove parameter fromfd from recvfile. - obnox */
 /* Leave at 22 - not yet released. Additional change: add operations for offline files -- ab */
+/* Leave at 22 - not yet released. Add the streaminfo call. -- jpeach, vl */
 
 #define SMB_VFS_INTERFACE_VERSION 22
 
@@ -198,6 +199,7 @@ typedef enum _vfs_op_type {
 	SMB_VFS_OP_NOTIFY_WATCH,
 	SMB_VFS_OP_CHFLAGS,
 	SMB_VFS_OP_FILE_ID_CREATE,
+	SMB_VFS_OP_STREAMINFO,
 
 	/* NT ACL operations. */
 
@@ -339,6 +341,13 @@ struct vfs_ops {
 		int (*chflags)(struct vfs_handle_struct *handle, const char *path, unsigned int flags);
 		struct file_id (*file_id_create)(struct vfs_handle_struct *handle, SMB_DEV_T dev, SMB_INO_T inode);
 
+		NTSTATUS (*streaminfo)(struct vfs_handle_struct *handle,
+				       struct files_struct *fsp,
+				       const char *fname,
+				       TALLOC_CTX *mem_ctx,
+				       unsigned int *num_streams,
+				       struct stream_struct **streams);
+
 		/* NT ACL operations. */
 
 		NTSTATUS (*fget_nt_acl)(struct vfs_handle_struct *handle,
@@ -476,6 +485,7 @@ struct vfs_ops {
 		struct vfs_handle_struct *notify_watch;
 		struct vfs_handle_struct *chflags;
 		struct vfs_handle_struct *file_id_create;
+		struct vfs_handle_struct *streaminfo;
 
 		/* NT ACL operations. */
 
diff --git a/source/include/vfs_macros.h b/source/include/vfs_macros.h
index dd30f97..1674f26 100644
--- a/source/include/vfs_macros.h
+++ b/source/include/vfs_macros.h
@@ -82,6 +82,7 @@
 #define SMB_VFS_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs.ops.notify_watch((conn)->vfs.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
 #define SMB_VFS_CHFLAGS(conn, path, flags) ((conn)->vfs.ops.chflags((conn)->vfs.handles.chflags, (path), (flags)))
 #define SMB_VFS_FILE_ID_CREATE(conn, dev, inode) ((conn)->vfs.ops.file_id_create((conn)->vfs.handles.file_id_create, (dev), (inode)))
+#define SMB_VFS_STREAMINFO(conn, fsp, fname, mem_ctx, num_streams, streams) ((conn)->vfs.ops.streaminfo((conn)->vfs.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
 
 /* NT ACL operations. */
 #define SMB_VFS_FGET_NT_ACL(fsp, security_info, ppdesc) ((fsp)->conn->vfs.ops.fget_nt_acl((fsp)->conn->vfs.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
@@ -206,6 +207,7 @@
 #define SMB_VFS_OPAQUE_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_opaque.ops.notify_watch((conn)->vfs_opaque.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
 #define SMB_VFS_OPAQUE_CHFLAGS(conn, path, flags) ((conn)->vfs_opaque.ops.chflags((conn)->vfs_opaque.handles.chflags, (path), (flags)))
 #define SMB_VFS_OPAQUE_FILE_ID_CREATE(conn, dev, inode) ((conn)->vfs.ops_opaque.file_id_create((conn)->vfs_opaque.handles.file_id_create, (dev), (inode)))
+#define SMB_VFS_OPAQUE_STREAMINFO(conn, fsp, fname, mem_ctx, num_streams, streams) ((conn)->vfs_opaque.ops.streaminfo((conn)->vfs_opaque.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
 
 /* NT ACL operations. */
 #define SMB_VFS_OPAQUE_FGET_NT_ACL(fsp, security_info, ppdesc) ((fsp)->conn->vfs_opaque.ops.fget_nt_acl((fsp)->conn->vfs_opaque.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
@@ -331,6 +333,7 @@
 #define SMB_VFS_NEXT_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_next.ops.notify_watch((conn)->vfs_next.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
 #define SMB_VFS_NEXT_CHFLAGS(handle, path, flags) ((handle)->vfs_next.ops.chflags((handle)->vfs_next.handles.chflags, (path), (flags)))
 #define SMB_VFS_NEXT_FILE_ID_CREATE(handle, dev, inode) ((handle)->vfs_next.ops.file_id_create((handle)->vfs_next.handles.file_id_create, (dev), (inode)))
+#define SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname, mem_ctx, num_streams, streams) ((handle)->vfs.ops.streaminfo((handle)->vfs.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
 
 /* NT ACL operations. */
 #define SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, ppdesc) ((handle)->vfs_next.ops.fget_nt_acl((handle)->vfs_next.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
diff --git a/source/lib/errmap_unix.c b/source/lib/errmap_unix.c
index 885a1c5..8194cf8 100644
--- a/source/lib/errmap_unix.c
+++ b/source/lib/errmap_unix.c
@@ -92,6 +92,9 @@ const struct unix_error_map unix_dos_nt_errmap[] = {
 #ifdef EWOULDBLOCK
 	{ EWOULDBLOCK, ERRDOS, 111, NT_STATUS_NETWORK_BUSY },
 #endif
+#ifdef ENOATTR
+	{ ENOATTR, ERRDOS, ERRbadfile, NT_STATUS_NOT_FOUND },
+#endif
 
 	{ 0, 0, 0, NT_STATUS_OK }
 };
diff --git a/source/lib/util.c b/source/lib/util.c
index bc3eaa8..11f3660 100644
--- a/source/lib/util.c
+++ b/source/lib/util.c
@@ -3273,3 +3273,93 @@ void *talloc_zeronull(const void *context, size_t size, const char *name)
 	return talloc_named_const(context, size, name);
 }
 #endif
+
+/* Split a path name into filename and stream name components. Canonicalise
+ * such that an implicit $DATA token is always explicit.
+ *
+ * The "specification" of this function can be found in the
+ * run_local_stream_name() function in torture.c, I've tried those
+ * combinations against a W2k3 server.
+ */
+
+NTSTATUS split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname,
+				char **pbase, char **pstream)
+{
+	char *base = NULL;
+	char *stream = NULL;
+	char *sname; /* stream name */
+	const char *stype; /* stream type */
+
+	DEBUG(10, ("split_ntfs_stream_name called for [%s]\n", fname));
+
+	sname = strchr_m(fname, ':');
+
+	if (lp_posix_pathnames() || (sname == NULL)) {
+		if (pbase != NULL) {
+			base = talloc_strdup(mem_ctx, fname);
+			NT_STATUS_HAVE_NO_MEMORY(base);
+		}
+		goto done;
+	}
+
+	if (pbase != NULL) {
+		base = talloc_strndup(mem_ctx, fname, PTR_DIFF(sname, fname));
+		NT_STATUS_HAVE_NO_MEMORY(base);
+	}
+
+	sname += 1;
+
+	stype = strchr_m(sname, ':');
+
+	if (stype == NULL) {
+		sname = talloc_strdup(mem_ctx, sname);
+		stype = "$DATA";
+	}
+	else {
+		if (StrCaseCmp(stype, ":$DATA") != 0) {
+			/*
+			 * If there is an explicit stream type, so far we only
+			 * allow $DATA. Is there anything else allowed? -- vl
+			 */
+			DEBUG(10, ("[%s] is an invalid stream type\n", stype));
+			TALLOC_FREE(base);
+			return NT_STATUS_OBJECT_NAME_INVALID;
+		}
+		sname = talloc_strndup(mem_ctx, sname, PTR_DIFF(stype, sname));
+		stype += 1;
+	}
+
+	if (sname == NULL) {
+		TALLOC_FREE(base);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	if (sname[0] == '\0') {
+		/*
+		 * no stream name, so no stream
+		 */
+		goto done;
+	}
+
+	if (pstream != NULL) {
+		stream = talloc_asprintf(mem_ctx, "%s:%s", sname, stype);
+		if (stream == NULL) {
+			TALLOC_FREE(sname);
+			TALLOC_FREE(base);
+			return NT_STATUS_NO_MEMORY;
+		}
+		/*
+		 * upper-case the type field
+		 */
+		strupper_m(strchr_m(stream, ':')+1);
+	}
+
+ done:
+	if (pbase != NULL) {
+		*pbase = base;
+	}
+	if (pstream != NULL) {
+		*pstream = stream;
+	}
+	return NT_STATUS_OK;
+}
diff --git a/source/modules/vfs_default.c b/source/modules/vfs_default.c
index 31234f2..2e620d0 100644
--- a/source/modules/vfs_default.c
+++ b/source/modules/vfs_default.c
@@ -942,6 +942,63 @@ static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle, S
 	return file_id_create_dev(dev, inode);
 }
 
+static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle,
+				   struct files_struct *fsp,
+				   const char *fname,
+				   TALLOC_CTX *mem_ctx,
+				   unsigned int *pnum_streams,
+				   struct stream_struct **pstreams)
+{
+	SMB_STRUCT_STAT sbuf;
+	NTSTATUS status;
+	unsigned int num_streams = 0;
+	struct stream_struct *streams = NULL;
+	int ret;
+
+	if ((fsp != NULL) && (fsp->is_directory)) {
+		/*
+		 * No default streams on directories
+		 */
+		goto done;
+	}
+
+	if ((fsp != NULL) && (fsp->fh->fd != -1)) {
+		ret = SMB_VFS_FSTAT(fsp, &sbuf);
+	}
+	else {
+		ret = SMB_VFS_STAT(handle->conn, fname, &sbuf);
+	}
+
+	if (ret == -1) {
+		return map_nt_error_from_unix(errno);
+	}
+
+	if (S_ISDIR(sbuf.st_mode)) {
+		goto done;
+	}
+
+	streams = talloc(mem_ctx, struct stream_struct);
+
+	if (streams == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	streams->size = sbuf.st_size;
+	streams->alloc_size = get_allocation_size(handle->conn, fsp, &sbuf);
+
+	streams->name = talloc_strdup(streams, "::$DATA");
+	if (streams->name == NULL) {
+		TALLOC_FREE(streams);
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	num_streams = 1;
+ done:
+	*pnum_streams = num_streams;
+	*pstreams = streams;
+	return NT_STATUS_OK;
+}
+
 static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
 				    files_struct *fsp,
 				    uint32 security_info, SEC_DESC **ppdesc)
@@ -1367,6 +1424,8 @@ static vfs_op_tuple vfs_default_ops[] = {
 	 SMB_VFS_LAYER_OPAQUE},
 	{SMB_VFS_OP(vfswrap_file_id_create),	SMB_VFS_OP_FILE_ID_CREATE,
 	 SMB_VFS_LAYER_OPAQUE},
+	{SMB_VFS_OP(vfswrap_streaminfo),	SMB_VFS_OP_STREAMINFO,
+	 SMB_VFS_LAYER_OPAQUE},
 
 	/* NT ACL operations. */
 
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
index e8df732..9381174 100644
--- a/source/smbd/nttrans.c
+++ b/source/smbd/nttrans.c
@@ -271,6 +271,9 @@ void send_nt_replies(connection_struct *conn,
 
 /****************************************************************************
  Is it an NTFS stream name ?
+ An NTFS file name is <path>.<extention>:<stream name>:<stream type>
+ $DATA can be used as both a stream name and a stream type. A missing stream
+ name or type implies $DATA.
 ****************************************************************************/
 
 bool is_ntfs_stream_name(const char *fname)
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 53eff65..d56a0da 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -5,7 +5,7 @@
    Copyright (C) Stefan (metze) Metzmacher	2003
    Copyright (C) Volker Lendecke		2005-2007
    Copyright (C) Steve French			2005
-   Copyright (C) James Peach			2007
+   Copyright (C) James Peach			2006-2007
 
    Extensively modified by Andrew Tridgell, 1995
 
@@ -3568,6 +3568,72 @@ static char *store_file_unix_basic_info2(connection_struct *conn,
 	return pdata;
 }
 
+static NTSTATUS marshall_stream_info(unsigned int num_streams,
+				     const struct stream_struct *streams,
+				     char *data,
+				     unsigned int max_data_bytes,
+				     unsigned int *data_size)
+{
+	unsigned int i;
+	unsigned int ofs = 0;
+
+	for (i=0; i<num_streams; i++) {
+		unsigned int next_offset;
+		size_t namelen;
+		smb_ucs2_t *namebuf;
+
+		namelen = push_ucs2_talloc(talloc_tos(), &namebuf,
+					    streams[i].name);
+
+		if ((namelen == (size_t)-1) || (namelen <= 2)) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		/*
+		 * name_buf is now null-terminated, we need to marshall as not
+		 * terminated
+		 */
+
+		namelen -= 2;
+
+		if (ofs + 24 + namelen > max_data_bytes) {
+			TALLOC_FREE(namebuf);
+			return NT_STATUS_BUFFER_TOO_SMALL;
+		}
+
+		SIVAL(data, ofs+4, namelen);
+		SOFF_T(data, ofs+8, streams[i].size);
+		SOFF_T(data, ofs+16, streams[i].alloc_size);
+		memcpy(data+ofs+24, namebuf, namelen);
+		TALLOC_FREE(namebuf);
+
+		next_offset = ofs + 24 + namelen;
+
+		if (i == num_streams-1) {
+			SIVAL(data, ofs, 0);
+		}
+		else {
+			unsigned int align = ndr_align_size(next_offset, 8);
+
+			if (next_offset + align > max_data_bytes) {
+				return NT_STATUS_BUFFER_TOO_SMALL;
+			}
+
+			memset(data+next_offset, 0, align);
+			next_offset += align;
+
+			SIVAL(data, ofs, next_offset - ofs);
+			ofs = next_offset;
+		}
+
+		ofs = next_offset;
+	}
+
+	*data_size = ofs;
+
+	return NT_STATUS_OK;
+}
+
 /****************************************************************************
  Reply to a TRANSACT2_QFILEINFO on a PIPE !
 ****************************************************************************/
@@ -4273,20 +4339,40 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
 		 */
 		case SMB_QUERY_FILE_STREAM_INFO:
 #endif
-		case SMB_FILE_STREAM_INFORMATION:
-			DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_STREAM_INFORMATION\n"));
-			if (mode & aDIR) {
-				data_size = 0;
-			} else {
-				size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", (size_t)0xE, False);
-				SIVAL(pdata,0,0); /* ??? */
-				SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
-				SOFF_T(pdata,8,file_size);
-				SOFF_T(pdata,16,allocation_size);
-				data_size = 24 + byte_len;
+		case SMB_FILE_STREAM_INFORMATION: {
+			unsigned int num_streams;
+			struct stream_struct *streams;
+			NTSTATUS status;
+
+			DEBUG(10,("call_trans2qfilepathinfo: "
+				  "SMB_FILE_STREAM_INFORMATION\n"));
+
+			status = SMB_VFS_STREAMINFO(
+				conn, fsp, fname, talloc_tos(),
+				&num_streams, &streams);
+
+			if (!NT_STATUS_IS_OK(status)) {
+				DEBUG(10, ("could not get stream info: %s\n",
+					   nt_errstr(status)));
+				reply_nterror(req, status);
+				return;
 			}
-			break;
 
+			status = marshall_stream_info(num_streams, streams,
+						      pdata, max_data_bytes,
+						      &data_size);
+
+			if (!NT_STATUS_IS_OK(status)) {
+				DEBUG(10, ("marshall_stream_info failed: %s\n",
+					   nt_errstr(status)));
+				reply_nterror(req, status);
+				return;
+			}
+
+			TALLOC_FREE(streams);
+
+			break;
+		}
 		case SMB_QUERY_COMPRESSION_INFO:
 		case SMB_FILE_COMPRESSION_INFORMATION:
 			DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
diff --git a/source/torture/torture.c b/source/torture/torture.c
index 05b4141..070474c 100644
--- a/source/torture/torture.c
+++ b/source/torture/torture.c
@@ -5098,6 +5098,74 @@ static bool run_local_rbtree(int dummy)
 	return ret;
 }
 
+static bool test_stream_name(const char *fname, const char *expected_base,
+			     const char *expected_stream,
+			     NTSTATUS expected_status)
+{
+	NTSTATUS status;
+	char *base = NULL;
+	char *stream = NULL;
+
+	status = split_ntfs_stream_name(talloc_tos(), fname, &base, &stream);
+	if (!NT_STATUS_EQUAL(status, expected_status)) {
+		goto error;
+	}
+
+	if (!NT_STATUS_IS_OK(status)) {
+		return true;
+	}
+
+	if (base == NULL) goto error;
+
+	if (strcmp(expected_base, base) != 0) goto error;
+
+	if ((expected_stream != NULL) && (stream == NULL)) goto error;
+	if ((expected_stream == NULL) && (stream != NULL)) goto error;
+
+	if ((stream != NULL) && (strcmp(expected_stream, stream) != 0))
+		goto error;
+
+	TALLOC_FREE(base);
+	TALLOC_FREE(stream);
+	return true;
+
+ error:
+	d_fprintf(stderr, "test_stream(%s, %s, %s, %s)\n",
+		  fname, expected_base ? expected_base : "<NULL>",
+		  expected_stream ? expected_stream : "<NULL>",
+		  nt_errstr(expected_status));
+	d_fprintf(stderr, "-> base=%s, stream=%s, status=%s\n",
+		  base ? base : "<NULL>", stream ? stream : "<NULL>",
+		  nt_errstr(status));
+	TALLOC_FREE(base);
+	TALLOC_FREE(stream);
+	return false;
+}
+
+static bool run_local_stream_name(int dummy)
+{
+	bool ret = true;
+
+	ret &= test_stream_name(
+		"bla", "bla", NULL, NT_STATUS_OK);
+	ret &= test_stream_name(
+		"bla::$DATA", "bla", NULL, NT_STATUS_OK);
+	ret &= test_stream_name(
+		"bla:blub:", "bla", NULL, NT_STATUS_OBJECT_NAME_INVALID);
+	ret &= test_stream_name(
+		"bla::", NULL, NULL, NT_STATUS_OBJECT_NAME_INVALID);
+	ret &= test_stream_name(
+		"bla::123", "bla", NULL, NT_STATUS_OBJECT_NAME_INVALID);
+	ret &= test_stream_name(
+		"bla:$DATA", "bla", "$DATA:$DATA", NT_STATUS_OK);
+	ret &= test_stream_name(
+		"bla:x:$DATA", "bla", "x:$DATA", NT_STATUS_OK);
+	ret &= test_stream_name(
+		"bla:x", "bla", "x:$DATA", NT_STATUS_OK);
+
+	return ret;
+}
+
 static bool data_blob_equal(DATA_BLOB a, DATA_BLOB b)
 {
 	if (a.length != b.length) {
@@ -5328,6 +5396,7 @@ static struct {
 	{ "LOCAL-GENCACHE", run_local_gencache, 0},
 	{ "LOCAL-RBTREE", run_local_rbtree, 0},
 	{ "LOCAL-MEMCACHE", run_local_memcache, 0},
+	{ "LOCAL-STREAM-NAME", run_local_stream_name, 0},
 	{NULL, NULL, 0}};
 
 


-- 
Samba Shared Repository


More information about the samba-cvs mailing list