Optimization suggested by Metze. Without this patch,
authorJeremy Allison <jra@samba.org>
Wed, 8 Sep 2010 23:55:24 +0000 (16:55 -0700)
committerJeremy Allison <jra@samba.org>
Wed, 8 Sep 2010 23:55:24 +0000 (16:55 -0700)
FindFirst with 'path\to\some\dir\with\files\*'

triggers the following stat calls

path\to\some\dir\with\files\* => ENOENT
path\
path\to\
path\to\some\
path\to\some\dir\
path\to\some\dir\with\
path\to\some\dir\with\files\
path\to\some\dir\with\files\* => ENOENT

With this patch we get :

path\to\some\dir\with\files\* => ENOENT
path\to\some\dir\with\files = OK

Jeremy.

source3/smbd/filename.c

index 8f9b8558c12974d57c7d9a065f2576898a682308..eadb977a72f742ea01ebcd31838613809c5db792 100644 (file)
@@ -382,10 +382,12 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
                                 * or a missing intermediate component ?
                                 */
                                struct smb_filename parent_fname;
+                               const char *last_component = NULL;
+
                                ZERO_STRUCT(parent_fname);
                                if (!parent_dirname(ctx, smb_fname->base_name,
                                                        &parent_fname.base_name,
-                                                       NULL)) {
+                                                       &last_component)) {
                                        status = NT_STATUS_NO_MEMORY;
                                        goto fail;
                                }
@@ -401,7 +403,40 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
                                                status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
                                                goto fail;
                                        }
+                               } else if (ret == 0) {
+                                       /*
+                                        * stat() or lstat() of the parent dir
+                                        * succeeded. So start the walk
+                                        * at this point.
+                                        */
+                                       status = check_for_dot_component(&parent_fname);
+                                       if (!NT_STATUS_IS_OK(status)) {
+                                               goto fail;
+                                       }
+
+                                       /*
+                                        * If there was no parent component in
+                                        * smb_fname->base_name then
+                                        * don't do this optimization.
+                                        */
+                                       if (smb_fname->base_name != last_component) {
+                                               /*
+                                                * Safe to use CONST_DISCARD
+                                                * here as last_component points
+                                                * into our smb_fname->base_name.
+                                                */
+                                               start = CONST_DISCARD(char *,
+                                                       last_component);
+
+                                               DEBUG(5,("unix_convert optimize1: name "
+                                                       "= %s, dirpath = %s, "
+                                                       "start = %s\n",
+                                                       smb_fname->base_name,
+                                                       dirpath,
+                                                       start));
+                                       }
                                }
+
                                /*
                                 * Missing last component is ok - new file.
                                 * Also deal with permission denied elsewhere.
@@ -410,6 +445,61 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
                                goto done;
                        }
                }
+       } else {
+               /*
+                * We have a wildcard in the pathname.
+                *
+                * Optimization for common case where the wildcard
+                * is in the last component and the client already
+                * sent the correct case.
+                */
+               struct smb_filename parent_fname;
+               const char *last_component = NULL;
+
+               ZERO_STRUCT(parent_fname);
+               if (!parent_dirname(ctx, smb_fname->base_name,
+                                       &parent_fname.base_name,
+                                       &last_component)) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto fail;
+               }
+               /*
+                * If there was no parent component in
+                * smb_fname->base_name then
+                * don't do this optimization.
+                */
+               if ((smb_fname->base_name != last_component) &&
+                               !ms_has_wild(parent_fname.base_name)) {
+                       /*
+                        * Wildcard isn't in the parent, i.e.
+                        * it must be in the last component.
+                        */
+                       if (posix_pathnames) {
+                               ret = SMB_VFS_LSTAT(conn, &parent_fname);
+                       } else {
+                               ret = SMB_VFS_STAT(conn, &parent_fname);
+                       }
+                       if (ret == 0) {
+                               status = check_for_dot_component(&parent_fname);
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       goto fail;
+                               }
+
+                               /*
+                                * Safe to use CONST_DISCARD
+                                * here as last_component points
+                                * into our smb_fname->base_name.
+                                */
+                               start = CONST_DISCARD(char *,last_component);
+
+                               DEBUG(5,("unix_convert optimize2: name "
+                                       "= %s, dirpath = %s, "
+                                       "start = %s\n",
+                                       smb_fname->base_name,
+                                       dirpath,
+                                       start));
+                       }
+               }
        }
 
        /*
@@ -480,6 +570,12 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
                        goto fail;
                }
 
+               /* Skip the stat call if it's a wildcard end. */
+               if (name_has_wildcard) {
+                       DEBUG(5,("Wildcard %s\n",start));
+                       goto done;
+               }
+
                /*
                 * Check if the name exists up to this point.
                 */