From fcac46a61245e6b05f88ed80ec4b554ffd55dc63 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 8 Sep 2010 16:55:24 -0700 Subject: Optimization suggested by Metze. Without this patch, 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 | 98 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 8f9b8558c1..eadb977a72 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -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. */ -- cgit