[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha7-1731-gc1a21d0

Tim Prouty tprouty at samba.org
Thu May 21 01:15:09 GMT 2009


The branch, master has been updated
       via  c1a21d085d758284fe6997a05396f225da683352 (commit)
      from  5d3d51e9ad1e4db8d9580ce7f2ba4e86e658bb13 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit c1a21d085d758284fe6997a05396f225da683352
Author: Tim Prouty <tprouty at samba.org>
Date:   Tue Apr 7 13:39:57 2009 -0700

    s3: Change unix_convert (and its callers) to use struct smb_filename
    
    This is the first of a series of patches that change path based
    operations to operate on a struct smb_filename instead of a char *.
    This same concept already exists in source4.
    
    My goals for this series of patches are to eventually:
    
    1) Solve the stream vs. posix filename that contains a colon ambiguity
       that currently exists.
    2) Make unix_convert the only function that parses the stream name.
    3) Clean up the unix_convert API.
    4) Change all path based vfs operation to take a struct smb_filename.
    5) Make is_ntfs_stream_name() a constant operation that can simply
       check the state of struct smb_filename rather than re-parse the
       filename.
    6) Eliminate the need for split_ntfs_stream_name() to exist.
    
    My strategy is to start from the inside at unix_convert() and work my
    way out through the vfs layer, call by call.  This first patch does
    just that, by changing unix_convert and all of its callers to operate
    on struct smb_filename.  Since this is such a large change, I plan on
    pushing the patches in phases, where each phase keeps full
    compatibility and passes make test.
    
    The API of unix_convert has been simplified from:
    
    NTSTATUS unix_convert(TALLOC_CTX *ctx,
    		      connection_struct *conn,
    		      const char *orig_path,
    		      bool allow_wcard_last_component,
    		      char **pp_conv_path,
    		      char **pp_saved_last_component,
    		      SMB_STRUCT_STAT *pst)
    to:
    
    NTSTATUS unix_convert(TALLOC_CTX *ctx,
    		      connection_struct *conn,
    		      const char *orig_path,
    		      struct smb_filename *smb_fname,
    		      uint32_t ucf_flags)
    
    Currently the smb_filename struct looks like:
    
    struct smb_filename {
           char *base_name;
           char *stream_name;
           char *original_lcomp;
           SMB_STRUCT_STAT st;
    };
    
    One key point here is the decision to break up the base_name and
    stream_name.  I have introduced a helper function called
    get_full_smb_filename() that takes an smb_filename struct and
    allocates the full_name.  I changed the callers of unix_convert() to
    subsequently call get_full_smb_filename() for the time being, but I
    plan to eventually eliminate get_full_smb_filename().

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

Summary of changes:
 source3/include/proto.h        |   12 +-
 source3/include/smb.h          |   16 ++
 source3/modules/onefs_open.c   |   15 +-
 source3/printing/nt_printing.c |   17 ++-
 source3/smbd/filename.c        |  175 ++++++++-------
 source3/smbd/msdfs.c           |   15 +-
 source3/smbd/nttrans.c         |   90 +++++---
 source3/smbd/open.c            |   15 +-
 source3/smbd/reply.c           |  488 ++++++++++++++++++++++------------------
 source3/smbd/trans2.c          |  128 +++++++----
 10 files changed, 588 insertions(+), 383 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 6f298ad..a45fa42 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -6264,13 +6264,13 @@ int fsp_stat(files_struct *fsp, SMB_STRUCT_STAT *pst);
 
 /* The following definitions come from smbd/filename.c  */
 
+NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx, const struct smb_filename *smb_fname,
+			      char **full_name);
 NTSTATUS unix_convert(TALLOC_CTX *ctx,
-			connection_struct *conn,
-			const char *orig_path,
-			bool allow_wcard_last_component,
-			char **pp_conv_path,
-			char **pp_saved_last_component,
-			SMB_STRUCT_STAT *pst);
+		      connection_struct *conn,
+		      const char *orig_path,
+		      struct smb_filename **smb_fname,
+		      uint32_t ucf_flags);
 NTSTATUS check_name(connection_struct *conn, const char *name);
 int get_real_filename(connection_struct *conn, const char *path,
 		      const char *name, TALLOC_CTX *mem_ctx,
diff --git a/source3/include/smb.h b/source3/include/smb.h
index abcd494..9332df3 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -1925,4 +1925,20 @@ struct smb_file_time {
 	struct timespec create_time;
 };
 
+/*
+ * unix_convert_flags
+ */
+#define UCF_SAVE_LCOMP			0x00000001
+#define UCF_ALLOW_WCARD_LCOMP		0x00000002
+
+/*
+ * smb_filename
+ */
+struct smb_filename {
+	char *base_name;
+	char *stream_name;
+	char *original_lcomp;
+	SMB_STRUCT_STAT st;
+};
+
 #endif /* _SMB_H */
diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c
index dc8bf10..7d4379f 100644
--- a/source3/modules/onefs_open.c
+++ b/source3/modules/onefs_open.c
@@ -2058,16 +2058,27 @@ NTSTATUS onefs_create_file(vfs_handle_struct *handle,
 
 	/* Convert dos path to unix path if it hasn't already been done. */
 	if (create_file_flags & CFF_DOS_PATH) {
+		struct smb_filename *smb_fname = NULL;
 		char *converted_fname;
 
 		SET_STAT_INVALID(sbuf);
 
-		status = unix_convert(talloc_tos(), conn, fname, False,
-				      &converted_fname, NULL, &sbuf);
+		status = unix_convert(talloc_tos(), conn, fname, &smb_fname,
+				      0);
 		if (!NT_STATUS_IS_OK(status)) {
 			goto fail;
 		}
+
+		status = get_full_smb_filename(talloc_tos(), &smb_fname,
+					       &converted_fname);
+		if (!NT_STATUS_IS_OK(status)) {
+			TALLOC_FREE(smb_fname);
+			goto fail;
+		}
+
+		sbuf = smb_fname->st;
 		fname = converted_fname;
+		TALLOC_FREE(smb_fname);
 	} else {
 		if (psbuf != NULL) {
 			sbuf = *psbuf;
diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c
index 34b7a57..39e9661 100644
--- a/source3/printing/nt_printing.c
+++ b/source3/printing/nt_printing.c
@@ -638,7 +638,9 @@ static char *driver_unix_convert(connection_struct *conn,
 		const char *old_name,
 		SMB_STRUCT_STAT *pst)
 {
+	NTSTATUS status;
 	TALLOC_CTX *ctx = talloc_tos();
+	struct smb_filename *smb_fname = NULL;
 	char *name = talloc_strdup(ctx, old_name);
 	char *new_name = NULL;
 
@@ -651,7 +653,20 @@ static char *driver_unix_convert(connection_struct *conn,
 		return NULL;
 	}
 	trim_string(name,"/","/");
-	unix_convert(ctx,conn, name, false, &new_name, NULL, pst);
+
+	status = unix_convert(ctx, conn, name, &smb_fname, 0);
+	if (!NT_STATUS_IS_OK(status)) {
+		return NULL;
+	}
+
+	*pst = smb_fname->st;
+	status = get_full_smb_filename(ctx, smb_fname, &new_name);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(smb_fname);
+		return NULL;
+	}
+
+	TALLOC_FREE(smb_fname);
 	return new_name;
 }
 
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 0d5529b..3650348 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -29,10 +29,7 @@
 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
 				  connection_struct *conn,
 				  const char *orig_path,
-				  const char *basepath,
-				  const char *streamname,
-				  SMB_STRUCT_STAT *pst,
-				  char **path);
+				  struct smb_filename *smb_fname);
 
 /****************************************************************************
  Mangle the 2nd name and check if it is then equal to the first name.
@@ -83,10 +80,27 @@ static NTSTATUS determine_path_error(const char *name,
 	}
 }
 
+NTSTATUS get_full_smb_filename(TALLOC_CTX *ctx, const struct smb_filename *smb_fname,
+			       char **full_name)
+{
+	if (smb_fname->stream_name) {
+		*full_name = talloc_asprintf(ctx, "%s%s", smb_fname->base_name,
+					     smb_fname->stream_name);
+	} else {
+		*full_name = talloc_strdup(ctx, smb_fname->base_name);
+	}
+
+	if (!*full_name) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	return NT_STATUS_OK;
+}
+
 /****************************************************************************
 This routine is called to convert names from the dos namespace to unix
-namespace. It needs to handle any case conversions, mangling, format
-changes etc.
+namespace. It needs to handle any case conversions, mangling, format changes,
+streams etc.
 
 We assume that we have already done a chdir() to the right "root" directory
 for this service.
@@ -94,32 +108,34 @@ for this service.
 The function will return an NTSTATUS error if some part of the name except for
 the last part cannot be resolved, else NT_STATUS_OK.
 
-Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we didn't
-get any fatal errors that should immediately terminate the calling
-SMB processing whilst resolving.
+Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we
+didn't get any fatal errors that should immediately terminate the calling SMB
+processing whilst resolving.
 
-If the saved_last_component != 0, then the unmodified last component
-of the pathname is returned there. If saved_last_component == 0 then nothing
-is returned there.
+If the UCF_SAVE_LCOMP flag is passed in, then the unmodified last component
+of the pathname is set in smb_filename->original_lcomp.
 
-If last_component_wcard is true then a MS wildcard was detected and
+If UCF_ALLOW_WCARD_LCOMP is passed in, then a MS wildcard was detected and
 should be allowed in the last component of the path only.
 
-On exit from unix_convert, if *pst was not null, then the file stat
-struct will be returned if the file exists and was found, if not this
-stat struct will be filled with zeros (and this can be detected by checking
-for nlinks = 0, which can never be true for any file).
+If the orig_path was a stream, smb_filename->base_name will point to the base
+filename, and smb_filename->stream_name will point to the stream name.  If
+orig_path was not a stream, then smb_filename->stream_name will be NULL.
+
+On exit from unix_convert, the smb_filename->st stat struct will be populated
+if the file exists and was found, if not this stat struct will be filled with
+zeros (and this can be detected by checking for nlinks = 0, which can never be
+true for any file).
 ****************************************************************************/
 
 NTSTATUS unix_convert(TALLOC_CTX *ctx,
-			connection_struct *conn,
-			const char *orig_path,
-			bool allow_wcard_last_component,
-			char **pp_conv_path,
-			char **pp_saved_last_component,
-			SMB_STRUCT_STAT *pst)
+		      connection_struct *conn,
+		      const char *orig_path,
+		      struct smb_filename **smb_fname_out,
+		      uint32_t ucf_flags)
 {
 	SMB_STRUCT_STAT st;
+	struct smb_filename *smb_fname = NULL;
 	char *start, *end;
 	char *dirpath = NULL;
 	char *name = NULL;
@@ -127,21 +143,26 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 	bool component_was_mangled = False;
 	bool name_has_wildcard = False;
 	bool posix_pathnames = false;
+	bool allow_wcard_last_component = ucf_flags & UCF_ALLOW_WCARD_LCOMP;
+	bool save_last_component = ucf_flags & UCF_SAVE_LCOMP;
 	NTSTATUS result;
 	int ret = -1;
 
-	SET_STAT_INVALID(*pst);
-	*pp_conv_path = NULL;
-	if(pp_saved_last_component) {
-		*pp_saved_last_component = NULL;
+	*smb_fname_out = NULL;
+
+	smb_fname = TALLOC_ZERO_P(talloc_tos(), struct smb_filename);
+	if (smb_fname == NULL) {
+		return NT_STATUS_NO_MEMORY;
 	}
 
 	if (conn->printer) {
 		/* we don't ever use the filenames on a printer share as a
 			filename - so don't convert them */
-		if (!(*pp_conv_path = talloc_strdup(ctx,orig_path))) {
+		if (!(smb_fname->base_name = talloc_strdup(smb_fname,
+							   orig_path))) {
 			return NT_STATUS_NO_MEMORY;
 		}
+		*smb_fname_out = smb_fname;
 		return NT_STATUS_OK;
 	}
 
@@ -174,7 +195,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 			return NT_STATUS_NO_MEMORY;
 		}
 		if (SMB_VFS_STAT(conn,name,&st) == 0) {
-			*pst = st;
+			smb_fname->st = st;
 		} else {
 			return map_nt_error_from_unix(errno);
 		}
@@ -217,18 +238,20 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 	 * Ensure saved_last_component is valid even if file exists.
 	 */
 
-	if(pp_saved_last_component) {
+	if(save_last_component) {
 		end = strrchr_m(name, '/');
 		if (end) {
-			*pp_saved_last_component = talloc_strdup(ctx, end + 1);
+			smb_fname->original_lcomp = talloc_strdup(ctx,
+								  end + 1);
 		} else {
-			*pp_saved_last_component = talloc_strdup(ctx,
-							name);
+			smb_fname->original_lcomp = talloc_strdup(ctx, name);
 		}
 	}
 
 	posix_pathnames = lp_posix_pathnames();
 
+	/* Strip off the stream. Should we use any of the other stream parsing
+	 * at this point? Also, should we set the is_stream bit? */
 	if (!posix_pathnames) {
 		stream = strchr_m(name, ':');
 
@@ -253,7 +276,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 
 	if((!conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) &&
 			stat_cache_lookup(conn, &name, &dirpath, &start, &st)) {
-		*pst = st;
+		smb_fname->st = st;
 		goto done;
 	}
 
@@ -295,7 +318,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 		}
 		stat_cache_add(orig_path, name, conn->case_sensitive);
 		DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
-		*pst = st;
+		smb_fname->st = st;
 		goto done;
 	}
 
@@ -346,11 +369,11 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 			*end = 0;
 		}
 
-		if (pp_saved_last_component) {
-			TALLOC_FREE(*pp_saved_last_component);
-			*pp_saved_last_component = talloc_strdup(ctx,
+		if (save_last_component) {
+			TALLOC_FREE(smb_fname->original_lcomp);
+			smb_fname->original_lcomp = talloc_strdup(ctx,
 							end ? end + 1 : start);
-			if (!*pp_saved_last_component) {
+			if (!smb_fname->original_lcomp) {
 				DEBUG(0, ("talloc failed\n"));
 				return NT_STATUS_NO_MEMORY;
 			}
@@ -427,7 +450,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 				 * struct. JRA.
 				 */
 
-				*pst = st;
+				smb_fname->st = st;
 			}
 
 		} else {
@@ -621,7 +644,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 				}
 
 				if (ret == 0) {
-					*pst = st;
+					smb_fname->st = st;
 				} else {
 					SET_STAT_INVALID(st);
 				}
@@ -703,35 +726,34 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 	DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
 
  done:
+	smb_fname->base_name = name;
+
 	if (stream != NULL) {
-		char *tmp = NULL;
+		smb_fname->stream_name = stream;
 
-		result = build_stream_path(ctx, conn, orig_path, name, stream,
-					   pst, &tmp);
+		/* Check path now that the base_name has been converted. */
+		result = build_stream_path(ctx, conn, orig_path, smb_fname);
 		if (!NT_STATUS_IS_OK(result)) {
 			goto fail;
 		}
-
-		DEBUG(10, ("build_stream_path returned %s\n", tmp));
-
-		TALLOC_FREE(name);
-		name = tmp;
 	}
-	*pp_conv_path = name;
 	TALLOC_FREE(dirpath);
+	*smb_fname_out = smb_fname;
 	return NT_STATUS_OK;
  fail:
 	DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start));
 	if (*dirpath != '\0') {
-		*pp_conv_path = talloc_asprintf(ctx,
-				"%s/%s", dirpath, start);
+		smb_fname->base_name = talloc_asprintf(ctx, "%s/%s", dirpath,
+						       start);
 	} else {
-		*pp_conv_path = talloc_strdup(ctx, start);
+		smb_fname->base_name = talloc_strdup(ctx, start);
 	}
-	if (!*pp_conv_path) {
+	if (!smb_fname->base_name) {
 		DEBUG(0, ("talloc_asprintf failed\n"));
 		return NT_STATUS_NO_MEMORY;
 	}
+
+	*smb_fname_out = smb_fname;
 	TALLOC_FREE(name);
 	TALLOC_FREE(dirpath);
 	return result;
@@ -923,25 +945,19 @@ int get_real_filename(connection_struct *conn, const char *path,
 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
 				  connection_struct *conn,
 				  const char *orig_path,
-				  const char *basepath,
-				  const char *streamname,
-				  SMB_STRUCT_STAT *pst,
-				  char **path)
+				  struct smb_filename *smb_fname)
 {
-	SMB_STRUCT_STAT st;
 	char *result = NULL;
 	NTSTATUS status;
 	unsigned int i, num_streams;
 	struct stream_struct *streams = NULL;
 
-	result = talloc_asprintf(mem_ctx, "%s%s", basepath, streamname);
-	if (result == NULL) {
+	status = get_full_smb_filename(mem_ctx, smb_fname, &result);
+	if (!NT_STATUS_IS_OK(status)) {
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	if (SMB_VFS_STAT(conn, result, &st) == 0) {
-		*pst = st;
-		*path = result;
+	if (SMB_VFS_STAT(conn, result, &smb_fname->st) == 0) {
 		return NT_STATUS_OK;
 	}
 
@@ -951,12 +967,12 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
 		goto fail;
 	}
 
-	status = SMB_VFS_STREAMINFO(conn, NULL, basepath, mem_ctx,
+	/* Fall back to a case-insensitive scan of all streams on the file. */
+	status = SMB_VFS_STREAMINFO(conn, NULL, smb_fname->base_name, mem_ctx,
 				    &num_streams, &streams);
 
 	if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
-		SET_STAT_INVALID(*pst);
-		*path = result;
+		SET_STAT_INVALID(smb_fname->st);
 		return NT_STATUS_OK;
 	}
 
@@ -967,8 +983,8 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
 
 	for (i=0; i<num_streams; i++) {
 		DEBUG(10, ("comparing [%s] and [%s]: ",
-			   streamname, streams[i].name));
-		if (fname_equal(streamname, streams[i].name,
+			   smb_fname->stream_name, streams[i].name));
+		if (fname_equal(smb_fname->stream_name, streams[i].name,
 				conn->case_sensitive)) {
 			DEBUGADD(10, ("equal\n"));
 			break;
@@ -976,28 +992,33 @@ static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
 		DEBUGADD(10, ("not equal\n"));
 	}
 
+	/* Couldn't find the stream. */
 	if (i == num_streams) {
-		SET_STAT_INVALID(*pst);
-		*path = result;
+		SET_STAT_INVALID(smb_fname->st);
 		TALLOC_FREE(streams);
 		return NT_STATUS_OK;
 	}
 
-	TALLOC_FREE(result);
+	DEBUG(10, ("case insensitive stream. requested: %s, actual: %s\n",
+		smb_fname->stream_name, streams[i].name));
+
 
-	result = talloc_asprintf(mem_ctx, "%s%s", basepath, streams[i].name);
-	if (result == NULL) {
+	TALLOC_FREE(smb_fname->stream_name);
+	smb_fname->stream_name = talloc_strdup(mem_ctx, streams[i].name);
+
+	TALLOC_FREE(result);
+	status = get_full_smb_filename(mem_ctx, smb_fname, &result);
+	if (!NT_STATUS_IS_OK(status)) {
 		status = NT_STATUS_NO_MEMORY;
 		goto fail;
 	}
 
-	SET_STAT_INVALID(*pst);
+	SET_STAT_INVALID(smb_fname->st);
 
-	if (SMB_VFS_STAT(conn, result, pst) == 0) {
+	if (SMB_VFS_STAT(conn, result, &smb_fname->st) == 0) {
 		stat_cache_add(orig_path, result, conn->case_sensitive);
 	}
 
-	*path = result;
 	TALLOC_FREE(streams);
 	return NT_STATUS_OK;
 
diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c
index efbc05c..7f99a18 100644
--- a/source3/smbd/msdfs.c
+++ b/source3/smbd/msdfs.c
@@ -515,8 +515,8 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
 {
 	char *p = NULL;
 	char *q = NULL;
-	SMB_STRUCT_STAT sbuf;
 	NTSTATUS status;
+	struct smb_filename *smb_fname = NULL;
 	char *localpath = NULL;
 	char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/'
 				  components). */
@@ -536,13 +536,22 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
 	 * think this is needed. JRA.
 	 */
 


-- 
Samba Shared Repository


More information about the samba-cvs mailing list