More const fixes. Remove CONST_DISCARD.
[kai/samba.git] / source3 / smbd / filename.c
index eadb977a72f742ea01ebcd31838613809c5db792..ec8d1139faa71ca187caf35500bda635ea772831 100644 (file)
@@ -25,7 +25,9 @@
  */
 
 #include "includes.h"
+#include "system/filesys.h"
 #include "fake_file.h"
+#include "smbd/smbd.h"
 
 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
                                  connection_struct *conn,
@@ -99,6 +101,91 @@ static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname)
        return NT_STATUS_OK;
 }
 
+/****************************************************************************
+ Optimization for common case where the missing part
+ is in the last component and the client already
+ sent the correct case.
+ Returns NT_STATUS_OK to mean continue the tree walk
+ (possibly with modified start pointer).
+ Any other NT_STATUS_XXX error means terminate the path
+ lookup here.
+****************************************************************************/
+
+static NTSTATUS check_parent_exists(TALLOC_CTX *ctx,
+                               connection_struct *conn,
+                               bool posix_pathnames,
+                               const struct smb_filename *smb_fname,
+                               char **pp_dirpath,
+                               char **pp_start)
+{
+       struct smb_filename parent_fname;
+       const char *last_component = NULL;
+       NTSTATUS status;
+       int ret;
+
+       ZERO_STRUCT(parent_fname);
+       if (!parent_dirname(ctx, smb_fname->base_name,
+                               &parent_fname.base_name,
+                               &last_component)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /*
+        * If there was no parent component in
+        * smb_fname->base_name of the parent name
+        * contained a wildcard then don't do this
+        * optimization.
+        */
+       if ((smb_fname->base_name == last_component) ||
+                       ms_has_wild(parent_fname.base_name)) {
+               return NT_STATUS_OK;
+       }
+
+       if (posix_pathnames) {
+               ret = SMB_VFS_LSTAT(conn, &parent_fname);
+       } else {
+               ret = SMB_VFS_STAT(conn, &parent_fname);
+       }
+
+       /* If the parent stat failed, just continue
+          with the normal tree walk. */
+
+       if (ret == -1) {
+               return NT_STATUS_OK;
+       }
+
+       status = check_for_dot_component(&parent_fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       /* Parent exists - set "start" to be the
+        * last compnent to shorten the tree walk. */
+
+       /*
+        * Safe to use discard_const_p
+        * here as last_component points
+        * into our smb_fname->base_name.
+        */
+       *pp_start = discard_const_p(char, last_component);
+
+       /* Update dirpath. */
+       TALLOC_FREE(*pp_dirpath);
+       *pp_dirpath = talloc_strdup(ctx, parent_fname.base_name);
+       if (!*pp_dirpath) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       DEBUG(5,("check_parent_exists: name "
+               "= %s, dirpath = %s, "
+               "start = %s\n",
+               smb_fname->base_name,
+               *pp_dirpath,
+               *pp_start));
+
+       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,
@@ -285,7 +372,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
        start = smb_fname->base_name;
 
        /*
-        * If we're providing case insentive semantics or
+        * If we're providing case insensitive semantics or
         * the underlying filesystem is case insensitive,
         * then a case-normalized hit in the stat-cache is
         * authoratitive. JRA.
@@ -303,7 +390,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 
        /*
         * Make sure "dirpath" is an allocated string, we use this for
-        * building the directories with asprintf and free it.
+        * building the directories with talloc_asprintf and free it.
         */
 
        if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) {
@@ -353,9 +440,26 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
                        goto done;
                }
 
+               /* Stat failed - ensure we don't use it. */
+               SET_STAT_INVALID(smb_fname->st);
+
+               if (errno == ENOENT) {
+                       /* Optimization when creating a new file - only
+                          the last component doesn't exist. */
+                       status = check_parent_exists(ctx,
+                                               conn,
+                                               posix_pathnames,
+                                               smb_fname,
+                                               &dirpath,
+                                               &start);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               goto fail;
+                       }
+               }
+
                /*
                 * 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
+                * sensitive or the underlying filesystem is case insensitive then searching
                 * won't help.
                 */
 
@@ -403,38 +507,6 @@ 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));
-                                       }
                                }
 
                                /*
@@ -453,53 +525,15 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
                 * 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;
+               status = check_parent_exists(ctx,
+                                       conn,
+                                       posix_pathnames,
+                                       smb_fname,
+                                       &dirpath,
+                                       &start);
+               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) &&
-                               !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));
-                       }
-               }
        }
 
        /*
@@ -828,8 +862,18 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
                 */
                if (VALID_STAT(smb_fname->st)) {
                        bool delete_pending;
+                       uint32_t name_hash;
+
+                       status = file_name_hash(conn,
+                                       smb_fname_str_dbg(smb_fname),
+                                       &name_hash);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               goto fail;
+                       }
+
                        get_file_infos(vfs_file_id_from_sbuf(conn,
                                                             &smb_fname->st),
+                                      name_hash,
                                       &delete_pending, NULL);
                        if (delete_pending) {
                                status = NT_STATUS_DELETE_PENDING;