The branch, master has been updated
       via  c96d487... Make us pass RAW-CHKPATH with a case sensitive share. I 
know Volker will look at this closely so here's the explaination :-). 
Originally on a case-sensitive share we simply did a stat (or lstat) call and 
returned success of fail based on the result. However this failed to take 
account of incoming paths with a wildcard (which must always fail, and with 
different error messages depending on whether the wildcard is the last 
component or in the path). Also it failed to take account of a stat fail with 
ENOENT due to a missing component of the path as the last component (which is 
ok as it could be a new file)  or if the ENOENT was due to the missing 
component within the path (not the last component) - which must return the 
correct error. What this means is that with "case sensitive = yes" we do one 
more talloc call (to get the parent directory) and one more stat call (on the 
parent directory) in the case where the stat call fails. I think this is an 
acceptabl
 e overhead to enable case sensitive shares to return the correct error 
messages for applications. Volker please examine carefully :-). Jeremy.
      from  108da2a... Add RAW-CHKPATH test with case-sensitive share. Jeremy.

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


- Log -----------------------------------------------------------------
commit c96d487ae3c65c17b377bb316adac4b5775448f3
Author: Jeremy Allison <j...@samba.org>
Date:   Wed Nov 25 13:17:56 2009 -0800

    Make us pass RAW-CHKPATH with a case sensitive share.
    I know Volker will look at this closely so here's the explaination :-).
    Originally on a case-sensitive share we simply did a stat (or lstat)
    call and returned success of fail based on the result. However this
    failed to take account of incoming paths with a wildcard (which must
    always fail, and with different error messages depending on whether
    the wildcard is the last component or in the path). Also it failed
    to take account of a stat fail with ENOENT due to a missing component
    of the path as the last component (which is ok as it could be a new
    file)  or if the ENOENT was due to the missing component within
    the path (not the last component) - which must return the correct
    error. What this means is that with "case sensitive = yes" we do
    one more talloc call (to get the parent directory) and one more
    stat call (on the parent directory) in the case where the stat
    call fails. I think this is an acceptable overhead to enable
    case sensitive shares to return the correct error messages for
    applications. Volker please examine carefully :-).
    Jeremy.

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

Summary of changes:
 source3/smbd/filename.c |  147 +++++++++++++++++++++++++++++++++-------------
 1 files changed, 105 insertions(+), 42 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 16e3631..ab79dfd 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -80,6 +80,24 @@ static NTSTATUS determine_path_error(const char *name,
        }
 }
 
+static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname)
+{
+       /* Ensure we catch all names with in "/."
+          this is disallowed under Windows and
+          in POSIX they've already been removed. */
+       const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/
+       if (p) {
+               if (p[2] == '/') {
+                       /* Error code within a pathname. */
+                       return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+               } else if (p[2] == '\0') {
+                       /* Error code at the end of a pathname. */
+                       return NT_STATUS_OBJECT_NAME_INVALID;
+               }
+       }
+       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,
@@ -294,52 +312,103 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
        }
 
        /*
-        * stat the name - if it exists then we can add the stream back (if
-        * there was one) and be done!
+        * If we have a wildcard we must walk the path to
+        * find where the error is, even if case sensitive
+        * is true.
         */
 
-       if (posix_pathnames) {
-               ret = SMB_VFS_LSTAT(conn, smb_fname);
-       } else {
-               ret = SMB_VFS_STAT(conn, smb_fname);
+       name_has_wildcard = ms_has_wild(smb_fname->base_name);
+       if (name_has_wildcard && !allow_wcard_last_component) {
+               /* Wildcard not valid anywhere. */
+               status = NT_STATUS_OBJECT_NAME_INVALID;
+               goto fail;
        }
 
-       if (ret == 0) {
-               /* Ensure we catch all names with in "/."
-                  this is disallowed under Windows. */
-               const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/
-               if (p) {
-                       if (p[2] == '/') {
-                               /* Error code within a pathname. */
-                               status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
-                               goto fail;
-                       } else if (p[2] == '\0') {
-                               /* Error code at the end of a pathname. */
-                               status = NT_STATUS_OBJECT_NAME_INVALID;
+       DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
+                smb_fname->base_name, dirpath, start));
+
+       if (!name_has_wildcard) {
+               /*
+                * stat the name - if it exists then we can add the stream back 
(if
+                * there was one) and be done!
+                */
+
+               if (posix_pathnames) {
+                       ret = SMB_VFS_LSTAT(conn, smb_fname);
+               } else {
+                       ret = SMB_VFS_STAT(conn, smb_fname);
+               }
+
+               if (ret == 0) {
+                       status = check_for_dot_component(smb_fname);
+                       if (!NT_STATUS_IS_OK(status)) {
                                goto fail;
                        }
+                       /* Add the path (not including the stream) to the 
cache. */
+                       stat_cache_add(orig_path, smb_fname->base_name,
+                                      conn->case_sensitive);
+                       DEBUG(5,("conversion of base_name finished %s -> %s\n",
+                                orig_path, smb_fname->base_name));
+                       goto done;
                }
-               /* Add the path (not including the stream) to the cache. */
-               stat_cache_add(orig_path, smb_fname->base_name,
-                              conn->case_sensitive);
-               DEBUG(5,("conversion of base_name finished %s -> %s\n",
-                        orig_path, smb_fname->base_name));
-               goto done;
-       }
 
-       DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
-                smb_fname->base_name, dirpath, start));
+               /*
+                * A special case - if we don't have any wildcards or mangling 
chars and are case
+                * sensitive or the underlying filesystem is case insentive 
then searching
+                * won't help.
+                */
 
-       /*
-        * A special case - if we don't have any mangling chars and are case
-        * sensitive or the underlying filesystem is case insentive then 
searching
-        * won't help.
-        */
+               if ((conn->case_sensitive || !(conn->fs_capabilities &
+                                       FILE_CASE_SENSITIVE_SEARCH)) &&
+                               !mangle_is_mangled(smb_fname->base_name, 
conn->params)) {
 
-       if ((conn->case_sensitive || !(conn->fs_capabilities &
-                                      FILE_CASE_SENSITIVE_SEARCH)) &&
-           !mangle_is_mangled(smb_fname->base_name, conn->params)) {
-               goto done;
+                       status = check_for_dot_component(smb_fname);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               goto fail;
+                       }
+
+                       /*
+                        * The stat failed. Could be ok as it could be
+                        * a new file.
+                        */
+
+                       if (errno == ENOTDIR || errno == ELOOP) {
+                               status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+                               goto fail;
+                       } else if (errno == ENOENT) {
+                               /*
+                                * Was it a missing last component ?
+                                * or a missing intermediate component ?
+                                */
+                               struct smb_filename parent_fname;
+                               ZERO_STRUCT(parent_fname);
+                               if (!parent_dirname(ctx, smb_fname->base_name,
+                                                       &parent_fname.base_name,
+                                                       NULL)) {
+                                       status = NT_STATUS_NO_MEMORY;
+                                       goto fail;
+                               }
+                               if (posix_pathnames) {
+                                       ret = SMB_VFS_LSTAT(conn, 
&parent_fname);
+                               } else {
+                                       ret = SMB_VFS_STAT(conn, &parent_fname);
+                               }
+                               if (ret == -1) {
+                                       if (errno == ENOTDIR ||
+                                                       errno == ENOENT ||
+                                                       errno == ELOOP) {
+                                               status = 
NT_STATUS_OBJECT_PATH_NOT_FOUND;
+                                               goto fail;
+                                       }
+                               }
+                               /*
+                                * Missing last component is ok - new file.
+                                * Also deal with permission denied elsewhere.
+                                * Just drop out to done.
+                                */
+                               goto done;
+                       }
+               }
        }
 
        /*
@@ -404,12 +473,6 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 
                name_has_wildcard = ms_has_wild(start);
 
-               /* Wildcard not valid anywhere. */
-               if (name_has_wildcard && !allow_wcard_last_component) {
-                       status = NT_STATUS_OBJECT_NAME_INVALID;
-                       goto fail;
-               }
-
                /* Wildcards never valid within a pathname. */
                if (name_has_wildcard && end) {
                        status = NT_STATUS_OBJECT_NAME_INVALID;


-- 
Samba Shared Repository

Reply via email to