s3: Change unix_convert (and its callers) to use struct smb_filename
authorTim Prouty <tprouty@samba.org>
Tue, 7 Apr 2009 20:39:57 +0000 (13:39 -0700)
committerTim Prouty <tprouty@samba.org>
Thu, 21 May 2009 00:40:15 +0000 (17:40 -0700)
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().

source3/include/proto.h
source3/include/smb.h
source3/modules/onefs_open.c
source3/printing/nt_printing.c
source3/smbd/filename.c
source3/smbd/msdfs.c
source3/smbd/nttrans.c
source3/smbd/open.c
source3/smbd/reply.c
source3/smbd/trans2.c

index 6f298ad9a0e4c24119efe2d5391202ca030ed952..a45fa42e3d9fefa51101ea9a6c22594810118e6d 100644 (file)
@@ -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,
index abcd49451c2b9e6b0defe3386951d5483a88cd4d..9332df3cd27bb07f7fa9cc361f39339e451d3294 100644 (file)
@@ -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 */
index dc8bf10a948d0398e113512a0de63e268e565b92..7d4379f1fc8bc3b7497b965e2229dc7ab3ee8d6a 100644 (file)
@@ -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;
index 34b7a577f89ca1e37b5c37ed28d40edc331e6c8d..39e9661bd68e2b55f72da42ab27b43ca1d3189dd 100644 (file)
@@ -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;
 }
 
index 0d5529b6b0c338776c9042fb98d44ec1f63712c0..36503483a8f135e429204ef0518e87ae4f34c809 100644 (file)
 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;
 
index efbc05ceb00f332c96ddec132aac038e9364970f..7f99a186aa12c72b535f0539506c76cd7ae7cfeb 100644 (file)
@@ -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.
         */
 
-       status = unix_convert(ctx, conn, pdp->reqpath, search_flag, &localpath,
-                       NULL, &sbuf);
+       status = unix_convert(ctx, conn, pdp->reqpath, &smb_fname,
+                             search_flag ? UCF_ALLOW_WCARD_LCOMP : 0);
+
        if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status,
                                        NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
                return status;
        }
 
+       status = get_full_smb_filename(ctx, smb_fname, &localpath);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(smb_fname);
+               return status;
+       }
+
+       TALLOC_FREE(smb_fname);
+
        /* Optimization - check if we can redirect the whole path. */
 
        if (is_msdfs_link_internal(ctx, conn, localpath, pp_targetpath, NULL)) {
index 7e75eea6b4da93f4ae5faf238955e1c0f1ce17d6..d51c9a6d67ea1863edc7084a69c2e76938e1508d 100644 (file)
@@ -1155,11 +1155,10 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
                                const char *newname_in,
                                uint32 attrs)
 {
-       SMB_STRUCT_STAT sbuf1, sbuf2;
+       struct smb_filename *smb_fname = NULL;
+       struct smb_filename *smb_fname_new = NULL;
        char *oldname = NULL;
        char *newname = NULL;
-       char *last_component_oldname = NULL;
-       char *last_component_newname = NULL;
        files_struct *fsp1,*fsp2;
        uint32 fattr;
        int info;
@@ -1167,59 +1166,69 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
        NTSTATUS status = NT_STATUS_OK;
        char *parent;
 
-       ZERO_STRUCT(sbuf1);
-       ZERO_STRUCT(sbuf2);
-
        if (!CAN_WRITE(conn)) {
-               return NT_STATUS_MEDIA_WRITE_PROTECTED;
+               status = NT_STATUS_MEDIA_WRITE_PROTECTED;
+               goto out;
        }
 
-       status = unix_convert(ctx, conn, oldname_in, False, &oldname,
-                       &last_component_oldname, &sbuf1);
+       status = unix_convert(ctx, conn, oldname_in, &smb_fname, 0);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
+       }
+
+       status = get_full_smb_filename(ctx, smb_fname, &oldname);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
        }
 
        status = check_name(conn, oldname);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
         /* Source must already exist. */
-       if (!VALID_STAT(sbuf1)) {
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       if (!VALID_STAT(smb_fname->st)) {
+               status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               goto out;
        }
        /* Ensure attributes match. */
-       fattr = dos_mode(conn,oldname,&sbuf1);
+       fattr = dos_mode(conn, oldname, &smb_fname->st);
        if ((fattr & ~attrs) & (aHIDDEN | aSYSTEM)) {
-               return NT_STATUS_NO_SUCH_FILE;
+               status = NT_STATUS_NO_SUCH_FILE;
+               goto out;
        }
 
-       status = unix_convert(ctx, conn, newname_in, False, &newname,
-                       &last_component_newname, &sbuf2);
+       status = unix_convert(ctx, conn, newname_in, &smb_fname_new, 0);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
+       }
+
+       status = get_full_smb_filename(ctx, smb_fname_new, &newname);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
        }
 
        status = check_name(conn, newname);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
        /* Disallow if newname already exists. */
-       if (VALID_STAT(sbuf2)) {
-               return NT_STATUS_OBJECT_NAME_COLLISION;
+       if (VALID_STAT(smb_fname_new->st)) {
+               status = NT_STATUS_OBJECT_NAME_COLLISION;
+               goto out;
        }
 
        /* No links from a directory. */
-       if (S_ISDIR(sbuf1.st_mode)) {
-               return NT_STATUS_FILE_IS_A_DIRECTORY;
+       if (S_ISDIR(smb_fname->st.st_mode)) {
+               status = NT_STATUS_FILE_IS_A_DIRECTORY;
+               goto out;
        }
 
        /* Ensure this is within the share. */
        status = check_reduced_name(conn, oldname);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
        DEBUG(10,("copy_internals: doing file copy %s to %s\n",
@@ -1243,10 +1252,10 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
                NULL,                                   /* ea_list */
                &fsp1,                                  /* result */
                &info,                                  /* pinfo */
-               &sbuf1);                                /* psbuf */
+               &smb_fname->st);                        /* psbuf */
 
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
         status = SMB_VFS_CREATE_FILE(
@@ -1267,15 +1276,15 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
                NULL,                                   /* ea_list */
                &fsp2,                                  /* result */
                &info,                                  /* pinfo */
-               &sbuf2);                                /* psbuf */
+               &smb_fname_new->st);                    /* psbuf */
 
        if (!NT_STATUS_IS_OK(status)) {
                close_file(NULL, fsp1, ERROR_CLOSE);
-               return status;
+               goto out;
        }
 
-       if (sbuf1.st_size) {
-               ret = vfs_transfer_file(fsp1, fsp2, sbuf1.st_size);
+       if (smb_fname->st.st_size) {
+               ret = vfs_transfer_file(fsp1, fsp2, smb_fname->st.st_size);
        }
 
        /*
@@ -1287,7 +1296,7 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
        close_file(NULL, fsp1, NORMAL_CLOSE);
 
        /* Ensure the modtime is set correctly on the destination file. */
-       set_close_write_time(fsp2, get_mtimespec(&sbuf1));
+       set_close_write_time(fsp2, get_mtimespec(&smb_fname->st));
 
        status = close_file(NULL, fsp2, NORMAL_CLOSE);
 
@@ -1295,15 +1304,24 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
           creates the file. This isn't the correct thing to do in the copy
           case. JRA */
        if (!parent_dirname(talloc_tos(), newname, &parent, NULL)) {
-               return NT_STATUS_NO_MEMORY;
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
        }
-       file_set_dosmode(conn, newname, fattr, &sbuf2, parent, false);
+       file_set_dosmode(conn, newname, fattr, &smb_fname_new->st, parent,
+                        false);
        TALLOC_FREE(parent);
 
-       if (ret < (SMB_OFF_T)sbuf1.st_size) {
-               return NT_STATUS_DISK_FULL;
+       if (ret < (SMB_OFF_T)smb_fname->st.st_size) {
+               status = NT_STATUS_DISK_FULL;
+               goto out;
+       }
+ out:
+       if (smb_fname) {
+               TALLOC_FREE(smb_fname);
+       }
+       if (smb_fname_new) {
+               TALLOC_FREE(smb_fname_new);
        }
-
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(3,("copy_internals: Error %s copy file %s to %s\n",
                        nt_errstr(status), oldname, newname));
index a0ae82a73c1b1353828fc42d9a1bce8ae6c21c5a..e6f523a162e424dbd02e99187bc9e5cc98deb933 100644 (file)
@@ -3442,16 +3442,27 @@ NTSTATUS create_file_default(connection_struct *conn,
        }
 
        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;
index 879550bb2e8a45063aa998d3e4939d3930a7f952..c15ebbe35e34b903346d89cc0283f51f2991591d 100644 (file)
@@ -966,8 +966,8 @@ static NTSTATUS map_checkpath_error(uint16_t flags2, NTSTATUS status)
 void reply_checkpath(struct smb_request *req)
 {
        connection_struct *conn = req->conn;
+       struct smb_filename *smb_fname = NULL;
        char *name = NULL;
-       SMB_STRUCT_STAT sbuf;
        NTSTATUS status;
        TALLOC_CTX *ctx = talloc_tos();
 
@@ -999,7 +999,12 @@ void reply_checkpath(struct smb_request *req)
 
        DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->vwv+0, 0)));
 
-       status = unix_convert(ctx, conn, name, False, &name, NULL, &sbuf);
+       status = unix_convert(ctx, conn, name, &smb_fname, 0);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto path_err;
+       }
+
+       status = get_full_smb_filename(ctx, smb_fname, &name);
        if (!NT_STATUS_IS_OK(status)) {
                goto path_err;
        }
@@ -1010,25 +1015,32 @@ void reply_checkpath(struct smb_request *req)
                goto path_err;
        }
 
-       if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,name,&sbuf) != 0)) {
+       if (!VALID_STAT(smb_fname->st) &&
+           (SMB_VFS_STAT(conn, name, &smb_fname->st) != 0)) {
                DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",name,strerror(errno)));
                status = map_nt_error_from_unix(errno);
                goto path_err;
        }
 
-       if (!S_ISDIR(sbuf.st_mode)) {
+       if (!S_ISDIR(smb_fname->st.st_mode)) {
                reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
                                ERRDOS, ERRbadpath);
-               END_PROFILE(SMBcheckpath);
-               return;
+               goto out;
        }
 
        reply_outbuf(req, 0, 0);
-
+ out:
+       if (smb_fname) {
+               TALLOC_FREE(smb_fname);
+       }
        END_PROFILE(SMBcheckpath);
        return;
 
-  path_err:
+ path_err:
+
+       if (smb_fname) {
+               TALLOC_FREE(smb_fname);
+       }
 
        END_PROFILE(SMBcheckpath);
 
@@ -1061,8 +1073,8 @@ void reply_checkpath(struct smb_request *req)
 void reply_getatr(struct smb_request *req)
 {
        connection_struct *conn = req->conn;
+       struct smb_filename *smb_fname = NULL;
        char *fname = NULL;
-       SMB_STRUCT_STAT sbuf;
        int mode=0;
        SMB_OFF_T size=0;
        time_t mtime=0;
@@ -1076,8 +1088,7 @@ void reply_getatr(struct smb_request *req)
        p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBgetatr);
-               return;
+               goto out;
        }
 
        status = resolve_dfspath(ctx, conn,
@@ -1088,12 +1099,10 @@ void reply_getatr(struct smb_request *req)
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
                        reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
                                        ERRSRV, ERRbadpath);
-                       END_PROFILE(SMBgetatr);
-                       return;
+                       goto out;
                }
                reply_nterror(req, status);
-               END_PROFILE(SMBgetatr);
-               return;
+               goto out;
        }
 
        /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
@@ -1106,29 +1115,32 @@ void reply_getatr(struct smb_request *req)
                size = 0;
                mtime = 0;
        } else {
-               status = unix_convert(ctx, conn, fname, False, &fname, NULL,&sbuf);
+               status = unix_convert(ctx, conn, fname, &smb_fname, 0);
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
-                       END_PROFILE(SMBgetatr);
-                       return;
+                       goto out;
+               }
+               status = get_full_smb_filename(ctx, smb_fname, &fname);
+               if (!NT_STATUS_IS_OK(status)) {
+                       reply_nterror(req, status);
+                       goto out;
                }
                status = check_name(conn, fname);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(3,("reply_getatr: check_name of %s failed (%s)\n",fname,nt_errstr(status)));
                        reply_nterror(req, status);
-                       END_PROFILE(SMBgetatr);
-                       return;
+                       goto out;
                }
-               if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,fname,&sbuf) != 0)) {
+               if (!VALID_STAT(smb_fname->st) &&
+                   (SMB_VFS_STAT(conn, fname, &smb_fname->st) != 0)) {
                        DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno)));
                        reply_unixerror(req, ERRDOS,ERRbadfile);
-                       END_PROFILE(SMBgetatr);
-                       return;
+                       goto out;
                }
 
-               mode = dos_mode(conn,fname,&sbuf);
-               size = sbuf.st_size;
-               mtime = sbuf.st_mtime;
+               mode = dos_mode(conn, fname, &smb_fname->st);
+               size = smb_fname->st.st_size;
+               mtime = smb_fname->st.st_mtime;
                if (mode & aDIR) {
                        size = 0;
                }
@@ -1151,6 +1163,10 @@ void reply_getatr(struct smb_request *req)
 
        DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n", fname, mode, (unsigned int)size ) );
 
+ out:
+       if (smb_fname) {
+               TALLOC_FREE(smb_fname);
+       }
        END_PROFILE(SMBgetatr);
        return;
 }
@@ -1163,10 +1179,10 @@ void reply_setatr(struct smb_request *req)
 {
        struct smb_file_time ft;
        connection_struct *conn = req->conn;
+       struct smb_filename *smb_fname = NULL;
        char *fname = NULL;
        int mode;
        time_t mtime;
-       SMB_STRUCT_STAT sbuf;
        const char *p;
        NTSTATUS status;
        TALLOC_CTX *ctx = talloc_tos();
@@ -1177,15 +1193,14 @@ void reply_setatr(struct smb_request *req)
 
        if (req->wct < 2) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
-               return;
+               goto out;
        }
 
        p = (const char *)req->buf + 1;
        p += srvstr_get_path_req(ctx, req, &fname, p, STR_TERMINATE, &status);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBsetatr);
-               return;
+               goto out;
        }
 
        status = resolve_dfspath(ctx, conn,
@@ -1196,26 +1211,28 @@ void reply_setatr(struct smb_request *req)
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
                        reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
                                        ERRSRV, ERRbadpath);
-                       END_PROFILE(SMBsetatr);
-                       return;
+                       goto out;
                }
                reply_nterror(req, status);
-               END_PROFILE(SMBsetatr);
-               return;
+               goto out;
        }
 
-       status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
+       status = unix_convert(ctx, conn, fname, &smb_fname, 0);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBsetatr);
-               return;
+               goto out;
+       }
+
+       status = get_full_smb_filename(ctx, smb_fname, &fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
+               goto out;
        }
 
        status = check_name(conn, fname);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBsetatr);
-               return;
+               goto out;
        }
 
        if (fname[0] == '.' && fname[1] == '\0') {
@@ -1224,8 +1241,7 @@ void reply_setatr(struct smb_request *req)
                 * condition. Might be moved to somewhere else later -- vl
                 */
                reply_nterror(req, NT_STATUS_ACCESS_DENIED);
-               END_PROFILE(SMBsetatr);
-               return;
+               goto out;
        }
 
        mode = SVAL(req->vwv+0, 0);
@@ -1233,30 +1249,32 @@ void reply_setatr(struct smb_request *req)
 
        ft.mtime = convert_time_t_to_timespec(mtime);
        status = smb_set_file_time(conn, NULL, fname,
-                                  &sbuf, &ft, true);
+                                  &smb_fname->st, &ft, true);
        if (!NT_STATUS_IS_OK(status)) {
                reply_unixerror(req, ERRDOS, ERRnoaccess);
-               END_PROFILE(SMBsetatr);
-               return;
+               goto out;
        }
 
        if (mode != FILE_ATTRIBUTE_NORMAL) {
-               if (VALID_STAT_OF_DIR(sbuf))
+               if (VALID_STAT_OF_DIR(smb_fname->st))
                        mode |= aDIR;
                else
                        mode &= ~aDIR;
 
-               if (file_set_dosmode(conn,fname,mode,&sbuf,NULL,false) != 0) {
+               if (file_set_dosmode(conn, fname, mode, &smb_fname->st, NULL,
+                                    false) != 0) {
                        reply_unixerror(req, ERRDOS, ERRnoaccess);
-                       END_PROFILE(SMBsetatr);
-                       return;
+                       goto out;
                }
        }
 
        reply_outbuf(req, 0, 0);
 
        DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
-
+ out:
+       if (smb_fname) {
+               TALLOC_FREE(smb_fname);
+       }
        END_PROFILE(SMBsetatr);
        return;
 }
@@ -1399,10 +1417,18 @@ void reply_search(struct smb_request *req)
        /* dirtype &= ~aDIR; */
 
        if (status_len == 0) {
-               SMB_STRUCT_STAT sbuf;
+               struct smb_filename *smb_fname = NULL;
 
-               nt_status = unix_convert(ctx, conn, path, True,
-                               &directory, NULL, &sbuf);
+               nt_status = unix_convert(ctx, conn, path, &smb_fname,
+                                        UCF_ALLOW_WCARD_LCOMP);
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       reply_nterror(req, nt_status);
+                       END_PROFILE(SMBsearch);
+                       return;
+               }
+
+               nt_status = get_full_smb_filename(ctx, smb_fname, &directory);
+               TALLOC_FREE(smb_fname);
                if (!NT_STATUS_IS_OK(nt_status)) {
                        reply_nterror(req, nt_status);
                        END_PROFILE(SMBsearch);
@@ -2142,12 +2168,12 @@ void reply_mknew(struct smb_request *req)
 void reply_ctemp(struct smb_request *req)
 {
        connection_struct *conn = req->conn;
+       struct smb_filename *smb_fname = NULL;
        char *fname = NULL;
        uint32 fattr;
        files_struct *fsp;
        int oplock_request;
        int tmpfd;
-       SMB_STRUCT_STAT sbuf;
        char *s;
        NTSTATUS status;
        TALLOC_CTX *ctx = talloc_tos();
@@ -2156,8 +2182,7 @@ void reply_ctemp(struct smb_request *req)
 
        if (req->wct < 3) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
-               END_PROFILE(SMBctemp);
-               return;
+               goto out;
        }
 
        fattr = SVAL(req->vwv+0, 0);
@@ -2167,8 +2192,7 @@ void reply_ctemp(struct smb_request *req)
                            STR_TERMINATE, &status);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBctemp);
-               return;
+               goto out;
        }
        if (*fname) {
                fname = talloc_asprintf(ctx,
@@ -2180,8 +2204,7 @@ void reply_ctemp(struct smb_request *req)
 
        if (!fname) {
                reply_nterror(req, NT_STATUS_NO_MEMORY);
-               END_PROFILE(SMBctemp);
-               return;
+               goto out;
        }
 
        status = resolve_dfspath(ctx, conn,
@@ -2192,37 +2215,38 @@ void reply_ctemp(struct smb_request *req)
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
                        reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
                                        ERRSRV, ERRbadpath);
-                       END_PROFILE(SMBctemp);
-                       return;
+                       goto out;
                }
                reply_nterror(req, status);
-               END_PROFILE(SMBctemp);
-               return;
+               goto out;
        }
 
-       status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
+       status = unix_convert(ctx, conn, fname, &smb_fname, 0);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBctemp);
-               return;
+               goto out;
+       }
+
+       status = get_full_smb_filename(ctx, smb_fname, &fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
+               goto out;
        }
 
        status = check_name(conn, fname);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBctemp);
-               return;
+               goto out;
        }
 
        tmpfd = mkstemp(fname);
        if (tmpfd == -1) {
                reply_unixerror(req, ERRDOS, ERRnoaccess);
-               END_PROFILE(SMBctemp);
-               return;
+               goto out;
        }
 
-       SET_STAT_INVALID(sbuf);
-       SMB_VFS_STAT(conn,fname,&sbuf);
+       SET_STAT_INVALID(smb_fname->st);
+       SMB_VFS_STAT(conn, fname, &smb_fname->st);
 
        /* We should fail if file does not exist. */
        status = SMB_VFS_CREATE_FILE(
@@ -2242,7 +2266,7 @@ void reply_ctemp(struct smb_request *req)
                NULL,                                   /* ea_list */
                &fsp,                                   /* result */
                NULL,                                   /* pinfo */
-               &sbuf);                                 /* psbuf */
+               &smb_fname->st);                        /* psbuf */
 
        /* close fd from mkstemp() */
        close(tmpfd);
@@ -2250,12 +2274,10 @@ void reply_ctemp(struct smb_request *req)
        if (!NT_STATUS_IS_OK(status)) {
                if (open_was_deferred(req->mid)) {
                        /* We have re-scheduled this call. */
-                       END_PROFILE(SMBctemp);
-                       return;
+                       goto out;
                }
                reply_openerror(req, status);
-               END_PROFILE(SMBctemp);
-               return;
+               goto out;
        }
 
        reply_outbuf(req, 1, 0);
@@ -2277,8 +2299,7 @@ void reply_ctemp(struct smb_request *req)
        if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
            == -1) {
                reply_nterror(req, NT_STATUS_NO_MEMORY);
-               END_PROFILE(SMBctemp);
-               return;
+               goto out;
        }
 
        if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
@@ -2293,8 +2314,11 @@ void reply_ctemp(struct smb_request *req)
 
        DEBUG( 2, ( "reply_ctemp: created temp file %s\n", fsp->fsp_name ) );
        DEBUG( 3, ( "reply_ctemp %s fd=%d umode=0%o\n", fsp->fsp_name,
-                   fsp->fh->fd, (unsigned int)sbuf.st_mode ) );
-
+                   fsp->fh->fd, (unsigned int)smb_fname->st.st_mode));
+ out:
+       if (smb_fname) {
+               TALLOC_FREE(smb_fname);
+       }
        END_PROFILE(SMBctemp);
        return;
 }
@@ -2479,24 +2503,33 @@ static NTSTATUS do_unlink(connection_struct *conn,
 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
                          uint32 dirtype, const char *name_in, bool has_wild)
 {
+       struct smb_filename *smb_fname = NULL;
        const char *directory = NULL;
        char *mask = NULL;
        char *name = NULL;
        char *p = NULL;
        int count=0;
        NTSTATUS status = NT_STATUS_OK;
-       SMB_STRUCT_STAT sbuf, st;
+       SMB_STRUCT_STAT st;
        TALLOC_CTX *ctx = talloc_tos();
 
-       status = unix_convert(ctx, conn, name_in, has_wild, &name, NULL, &sbuf);
+       status = unix_convert(ctx, conn, name_in, &smb_fname,
+                             has_wild ? UCF_ALLOW_WCARD_LCOMP : 0);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
+       status = get_full_smb_filename(ctx, smb_fname, &name);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(smb_fname);
+               return status;
+       }
+
        p = strrchr_m(name,'/');
        if (!p) {
                directory = talloc_strdup(ctx, ".");
                if (!directory) {
+                       TALLOC_FREE(smb_fname);
                        return NT_STATUS_NO_MEMORY;
                }
                mask = name;
@@ -2515,7 +2548,7 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
-       if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params)) {
+       if (!VALID_STAT(smb_fname->st) && mangle_is_mangled(mask,conn->params)) {
                char *new_mask = NULL;
                mangle_lookup_name_from_8_3(ctx,
                                mask,
@@ -2525,6 +2558,7 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
                        mask = new_mask;
                }
        }
+       TALLOC_FREE(smb_fname);
 
        if (!has_wild) {
                directory = talloc_asprintf(ctx,
@@ -5141,9 +5175,9 @@ void reply_printwrite(struct smb_request *req)
 void reply_mkdir(struct smb_request *req)
 {
        connection_struct *conn = req->conn;
+       struct smb_filename *smb_dname = NULL;
        char *directory = NULL;
        NTSTATUS status;
-       SMB_STRUCT_STAT sbuf;
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBmkdir);
@@ -5152,8 +5186,7 @@ void reply_mkdir(struct smb_request *req)
                            STR_TERMINATE, &status);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBmkdir);
-               return;
+               goto out;
        }
 
        status = resolve_dfspath(ctx, conn,
@@ -5164,26 +5197,28 @@ void reply_mkdir(struct smb_request *req)
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
                        reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
                                        ERRSRV, ERRbadpath);
-                       END_PROFILE(SMBmkdir);
-                       return;
+                       goto out;
                }
                reply_nterror(req, status);
-               END_PROFILE(SMBmkdir);
-               return;
+               goto out;
        }
 
-       status = unix_convert(ctx, conn, directory, False, &directory, NULL, &sbuf);
+       status = unix_convert(ctx, conn, directory, &smb_dname, 0);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBmkdir);
-               return;
+               goto out;
+       }
+
+       status = get_full_smb_filename(ctx, smb_dname, &directory);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
+               goto out;
        }
 
        status = check_name(conn, directory);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBmkdir);
-               return;
+               goto out;
        }
 
        status = create_directory(conn, req, directory);
@@ -5204,14 +5239,16 @@ void reply_mkdir(struct smb_request *req)
                }
 
                reply_nterror(req, status);
-               END_PROFILE(SMBmkdir);
-               return;
+               goto out;
        }
 
        reply_outbuf(req, 0, 0);
 
        DEBUG( 3, ( "mkdir %s\n", directory ) );
-
+ out:
+       if (smb_dname) {
+               TALLOC_FREE(smb_dname);
+       }
        END_PROFILE(SMBmkdir);
        return;
 }
@@ -5418,8 +5455,8 @@ NTSTATUS rmdir_internals(TALLOC_CTX *ctx,
 void reply_rmdir(struct smb_request *req)
 {
        connection_struct *conn = req->conn;
+       struct smb_filename *smb_dname = NULL;
        char *directory = NULL;
-       SMB_STRUCT_STAT sbuf;
        NTSTATUS status;
        TALLOC_CTX *ctx = talloc_tos();
 
@@ -5429,8 +5466,7 @@ void reply_rmdir(struct smb_request *req)
                            STR_TERMINATE, &status);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBrmdir);
-               return;
+               goto out;
        }
 
        status = resolve_dfspath(ctx, conn,
@@ -5441,41 +5477,44 @@ void reply_rmdir(struct smb_request *req)
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
                        reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
                                        ERRSRV, ERRbadpath);
-                       END_PROFILE(SMBrmdir);
-                       return;
+                       goto out;
                }
                reply_nterror(req, status);
-               END_PROFILE(SMBrmdir);
-               return;
+               goto out;
        }
 
-       status = unix_convert(ctx, conn, directory, False, &directory,
-                       NULL, &sbuf);
+       status = unix_convert(ctx, conn, directory, &smb_dname, 0);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBrmdir);
-               return;
+               goto out;
+       }
+
+       status = get_full_smb_filename(ctx, smb_dname, &directory);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
+               goto out;
        }
 
        status = check_name(conn, directory);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBrmdir);
-               return;
+               goto out;
        }
 
        dptr_closepath(directory, req->smbpid);
        status = rmdir_internals(ctx, conn, directory);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBrmdir);
-               return;
+               goto out;
        }
 
        reply_outbuf(req, 0, 0);
 
        DEBUG( 3, ( "rmdir %s\n", directory ) );
-
+ out:
+       if (smb_dname) {
+               TALLOC_FREE(smb_dname);
+       }
        END_PROFILE(SMBrmdir);
        return;
 }
@@ -5936,35 +5975,42 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                        bool dest_has_wild,
                        uint32_t access_mask)
 {
+       struct smb_filename *smb_fname = NULL;
+       struct smb_filename *smb_fname_new = NULL;
        char *directory = NULL;
        char *mask = NULL;
-       char *last_component_src = NULL;
-       char *last_component_dest = NULL;
        char *name = NULL;
        char *newname = NULL;
        char *p;
        int count=0;
        NTSTATUS status = NT_STATUS_OK;
-       SMB_STRUCT_STAT sbuf1, sbuf2;
        struct smb_Dir *dir_hnd = NULL;
        const char *dname;
        long offset = 0;
        int create_options = 0;
        bool posix_pathnames = lp_posix_pathnames();
 
-       ZERO_STRUCT(sbuf1);
-       ZERO_STRUCT(sbuf2);
+       status = unix_convert(ctx, conn, name_in, &smb_fname,
+                             src_has_wild ? UCF_ALLOW_WCARD_LCOMP : 0);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
+       }
+
+       status = get_full_smb_filename(ctx, smb_fname, &name);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
+       }
 
-       status = unix_convert(ctx, conn, name_in, src_has_wild, &name,
-                       &last_component_src, &sbuf1);
+       status = unix_convert(ctx, conn, newname_in, &smb_fname_new,
+                             (UCF_SAVE_LCOMP |
+                              (dest_has_wild ? UCF_ALLOW_WCARD_LCOMP : 0)));
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
-       status = unix_convert(ctx, conn, newname_in, dest_has_wild, &newname,
-                       &last_component_dest, &sbuf2);
+       status = get_full_smb_filename(ctx, smb_fname_new, &newname);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
        /*
@@ -5980,14 +6026,16 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
        if (!p) {
                directory = talloc_strdup(ctx, ".");
                if (!directory) {
-                       return NT_STATUS_NO_MEMORY;
+                       status = NT_STATUS_NO_MEMORY;
+                       goto out;
                }
                mask = name;
        } else {
                *p = 0;
                directory = talloc_strdup(ctx, name);
                if (!directory) {
-                       return NT_STATUS_NO_MEMORY;
+                       status = NT_STATUS_NO_MEMORY;
+                       goto out;
                }
                mask = p+1;
                *p = '/'; /* Replace needed for exceptional test below. */
@@ -6002,7 +6050,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
-       if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
+       if (!VALID_STAT(smb_fname->st) && mangle_is_mangled(mask, conn->params)) {
                char *new_mask = NULL;
                mangle_lookup_name_from_8_3(ctx,
                                        mask,
@@ -6024,7 +6072,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                                "/%s",
                                mask);
                if (!directory) {
-                       return NT_STATUS_NO_MEMORY;
+                       status = NT_STATUS_NO_MEMORY;
+                       goto out;
                }
 
                /* Ensure newname contains a '/' also */
@@ -6033,7 +6082,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                                                "./%s",
                                                newname);
                        if (!newname) {
-                               return NT_STATUS_NO_MEMORY;
+                               status = NT_STATUS_NO_MEMORY;
+                               goto out;
                        }
                }
 
@@ -6043,7 +6093,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                          "last_component_dest = %s\n",
                          conn->case_sensitive, conn->case_preserve,
                          conn->short_case_preserve, directory,
-                         newname, last_component_dest));
+                         newname, smb_fname_new->original_lcomp));
 
                /* The dest name still may have wildcards. */
                if (dest_has_wild) {
@@ -6054,19 +6104,20 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                                        "%s %s failed\n",
                                        directory,
                                        newname));
-                               return NT_STATUS_NO_MEMORY;
+                               status = NT_STATUS_NO_MEMORY;
+                               goto out;
                        }
                        newname = mod_newname;
                }
 
-               ZERO_STRUCT(sbuf1);
+               ZERO_STRUCT(smb_fname->st);
                if (posix_pathnames) {
-                       SMB_VFS_LSTAT(conn, directory, &sbuf1);
+                       SMB_VFS_LSTAT(conn, directory, &smb_fname->st);
                } else {
-                       SMB_VFS_STAT(conn, directory, &sbuf1);
+                       SMB_VFS_STAT(conn, directory, &smb_fname->st);
                }
 
-               if (S_ISDIR(sbuf1.st_mode)) {
+               if (S_ISDIR(smb_fname->st.st_mode)) {
                        create_options |= FILE_DIRECTORY_FILE;
                }
 
@@ -6088,16 +6139,16 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                        NULL,                           /* ea_list */
                        &fsp,                           /* result */
                        NULL,                           /* pinfo */
-                       &sbuf1);                        /* psbuf */
+                       &smb_fname->st);                /* psbuf */
 
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(3, ("Could not open rename source %s: %s\n",
                                  directory, nt_errstr(status)));
-                       return status;
+                       goto out;
                }
 
                status = rename_internals_fsp(conn, fsp, newname,
-                                             last_component_dest,
+                                             smb_fname_new->original_lcomp,
                                              attrs, replace_if_exists);
 
                close_file(req, fsp, NORMAL_CLOSE);
@@ -6105,7 +6156,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
                          nt_errstr(status), directory,newname));
 
-               return status;
+               goto out;
        }
 
        /*
@@ -6118,12 +6169,13 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 
        status = check_name(conn, directory);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
        dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, attrs);
        if (dir_hnd == NULL) {
-               return map_nt_error_from_unix(errno);
+               status = map_nt_error_from_unix(errno);
+               goto out;
        }
 
        status = NT_STATUS_NO_SUCH_FILE;
@@ -6132,7 +6184,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
         * - gentest fix. JRA
         */
 
-       while ((dname = ReadDirName(dir_hnd, &offset, &sbuf1))) {
+       while ((dname = ReadDirName(dir_hnd, &offset, &smb_fname->st))) {
                files_struct *fsp = NULL;
                char *fname = NULL;
                char *destname = NULL;
@@ -6147,7 +6199,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                        }
                }
 
-               if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
+               if (!is_visible_file(conn, directory, dname, &smb_fname->st,
+                                    False)) {
                        continue;
                }
 
@@ -6165,7 +6218,8 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                                directory,
                                dname);
                if (!fname) {
-                       return NT_STATUS_NO_MEMORY;
+                       status = NT_STATUS_NO_MEMORY;
+                       goto out;
                }
 
                if (!resolve_wildcards(ctx,
@@ -6176,19 +6230,20 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                        continue;
                }
                if (!destname) {
-                       return NT_STATUS_NO_MEMORY;
+                       status = NT_STATUS_NO_MEMORY;
+                       goto out;
                }
 
-               ZERO_STRUCT(sbuf1);
+               ZERO_STRUCT(smb_fname->st);
                if (posix_pathnames) {
-                       SMB_VFS_LSTAT(conn, fname, &sbuf1);
+                       SMB_VFS_LSTAT(conn, fname, &smb_fname->st);
                } else {
-                       SMB_VFS_STAT(conn, fname, &sbuf1);
+                       SMB_VFS_STAT(conn, fname, &smb_fname->st);
                }
 
                create_options = 0;
 
-               if (S_ISDIR(sbuf1.st_mode)) {
+               if (S_ISDIR(smb_fname->st.st_mode)) {
                        create_options |= FILE_DIRECTORY_FILE;
                }
 
@@ -6210,7 +6265,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                        NULL,                           /* ea_list */
                        &fsp,                           /* result */
                        NULL,                           /* pinfo */
-                       &sbuf1);                        /* psbuf */
+                       &smb_fname->st);                /* psbuf */
 
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(3,("rename_internals: SMB_VFS_CREATE_FILE "
@@ -6245,6 +6300,13 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                status = map_nt_error_from_unix(errno);
        }
 
+ out:
+       if (smb_fname) {
+               TALLOC_FREE(smb_fname);
+       }
+       if (smb_fname_new) {
+               TALLOC_FREE(smb_fname_new);
+       }
        return status;
 }
 
@@ -6505,6 +6567,8 @@ NTSTATUS copy_file(TALLOC_CTX *ctx,
 void reply_copy(struct smb_request *req)
 {
        connection_struct *conn = req->conn;
+       struct smb_filename *smb_fname = NULL;
+       struct smb_filename *smb_fname_new = NULL;
        char *name = NULL;
        char *newname = NULL;
        char *directory = NULL;
@@ -6520,7 +6584,6 @@ void reply_copy(struct smb_request *req)
        bool target_is_directory=False;
        bool source_has_wild = False;
        bool dest_has_wild = False;
-       SMB_STRUCT_STAT sbuf1, sbuf2;
        NTSTATUS status;
        TALLOC_CTX *ctx = talloc_tos();
 
@@ -6528,8 +6591,7 @@ void reply_copy(struct smb_request *req)
 
        if (req->wct < 3) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
-               END_PROFILE(SMBcopy);
-               return;
+               goto out;
        }
 
        tid2 = SVAL(req->vwv+0, 0);
@@ -6541,15 +6603,13 @@ void reply_copy(struct smb_request *req)
                                       &status, &source_has_wild);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBcopy);
-               return;
+               goto out;
        }
        p += srvstr_get_path_req_wcard(ctx, req, &newname, p, STR_TERMINATE,
                                       &status, &dest_has_wild);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBcopy);
-               return;
+               goto out;
        }
 
        DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
@@ -6558,8 +6618,7 @@ void reply_copy(struct smb_request *req)
                /* can't currently handle inter share copies XXXX */
                DEBUG(3,("Rejecting inter-share copy\n"));
                reply_doserror(req, ERRSRV, ERRinvdevice);
-               END_PROFILE(SMBcopy);
-               return;
+               goto out;
        }
 
        status = resolve_dfspath_wcard(ctx, conn,
@@ -6571,12 +6630,10 @@ void reply_copy(struct smb_request *req)
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
                        reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
                                        ERRSRV, ERRbadpath);
-                       END_PROFILE(SMBcopy);
-                       return;
+                       goto out;
                }
                reply_nterror(req, status);
-               END_PROFILE(SMBcopy);
-               return;
+               goto out;
        }
 
        status = resolve_dfspath_wcard(ctx, conn,
@@ -6588,50 +6645,55 @@ void reply_copy(struct smb_request *req)
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
                        reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
                                        ERRSRV, ERRbadpath);
-                       END_PROFILE(SMBcopy);
-                       return;
+                       goto out;
                }
                reply_nterror(req, status);
-               END_PROFILE(SMBcopy);
-               return;
+               goto out;
        }
 
-       status = unix_convert(ctx, conn, name, source_has_wild,
-                       &name, NULL, &sbuf1);
+       status = unix_convert(ctx, conn, name, &smb_fname,
+                             source_has_wild ? UCF_ALLOW_WCARD_LCOMP : 0);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBcopy);
-               return;
+               goto out;
        }
 
-       status = unix_convert(ctx, conn, newname, dest_has_wild,
-                       &newname, NULL, &sbuf2);
+       status = get_full_smb_filename(ctx, smb_fname, &name);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
-               END_PROFILE(SMBcopy);
-               return;
+               goto out;
+       }
+
+       status = unix_convert(ctx, conn, newname, &smb_fname_new,
+                             dest_has_wild ? UCF_ALLOW_WCARD_LCOMP : 0);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
+               goto out;
+       }
+
+       status = get_full_smb_filename(ctx, smb_fname_new, &newname);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
+               goto out;
        }
 
-       target_is_directory = VALID_STAT_OF_DIR(sbuf2);
+       target_is_directory = VALID_STAT_OF_DIR(smb_fname_new->st);
 
        if ((flags&1) && target_is_directory) {
                reply_doserror(req, ERRDOS, ERRbadfile);
-               END_PROFILE(SMBcopy);
-               return;
+               goto out;
        }
 
        if ((flags&2) && !target_is_directory) {
                reply_doserror(req, ERRDOS, ERRbadpath);
-               END_PROFILE(SMBcopy);
-               return;
+               goto out;
        }
 
-       if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) {
+       if ((flags&(1<<5)) && VALID_STAT_OF_DIR(smb_fname->st)) {
                /* wants a tree copy! XXXX */
                DEBUG(3,("Rejecting tree copy\n"));
                reply_doserror(req, ERRSRV, ERRerror);
-               END_PROFILE(SMBcopy);
-               return;
+               goto out;
        }
 
        p = strrchr_m(name,'/');
@@ -6645,8 +6707,7 @@ void reply_copy(struct smb_request *req)
 
        if (!directory) {
                reply_nterror(req, NT_STATUS_NO_MEMORY);
-               END_PROFILE(SMBcopy);
-               return;
+               goto out;
        }
 
        /*
@@ -6658,7 +6719,8 @@ void reply_copy(struct smb_request *req)
         * Tine Smukavec <valentin.smukavec@hermes.si>.
         */
 
-       if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
+       if (!VALID_STAT(smb_fname->st) &&
+           mangle_is_mangled(mask, conn->params)) {
                char *new_mask = NULL;
                mangle_lookup_name_from_8_3(ctx,
                                        mask,
@@ -6678,8 +6740,7 @@ void reply_copy(struct smb_request *req)
                        if (!resolve_wildcards(ctx,
                                        directory,newname,&mod_newname)) {
                                reply_nterror(req, NT_STATUS_NO_MEMORY);
-                               END_PROFILE(SMBcopy);
-                               return;
+                               goto out;
                        }
                        newname = mod_newname;
                }
@@ -6687,15 +6748,13 @@ void reply_copy(struct smb_request *req)
                status = check_name(conn, directory);
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
-                       END_PROFILE(SMBcopy);
-                       return;
+                       goto out;
                }
 
                status = check_name(conn, newname);
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
-                       END_PROFILE(SMBcopy);
-                       return;
+                       goto out;
                }
 
                status = copy_file(ctx,conn,directory,newname,ofun,
@@ -6703,8 +6762,7 @@ void reply_copy(struct smb_request *req)
 
                if(!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
-                       END_PROFILE(SMBcopy);
-                       return;
+                       goto out;
                } else {
                        count++;
                }
@@ -6720,21 +6778,20 @@ void reply_copy(struct smb_request *req)
                status = check_name(conn, directory);
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
-                       END_PROFILE(SMBcopy);
-                       return;
+                       goto out;
                }
 
                dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, 0);
                if (dir_hnd == NULL) {
                        status = map_nt_error_from_unix(errno);
                        reply_nterror(req, status);
-                       END_PROFILE(SMBcopy);
-                       return;
+                       goto out;
                }
 
                error = ERRbadfile;
 
-               while ((dname = ReadDirName(dir_hnd, &offset, &sbuf1))) {
+               while ((dname = ReadDirName(dir_hnd, &offset,
+                                           &smb_fname->st))) {
                        char *destname = NULL;
                        char *fname = NULL;
 
@@ -6742,7 +6799,8 @@ void reply_copy(struct smb_request *req)
                                continue;
                        }
 
-                       if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
+                       if (!is_visible_file(conn, directory, dname,
+                                            &smb_fname->st, False)) {
                                continue;
                        }
 
@@ -6758,8 +6816,7 @@ void reply_copy(struct smb_request *req)
                        if (!fname) {
                                TALLOC_FREE(dir_hnd);
                                reply_nterror(req, NT_STATUS_NO_MEMORY);
-                               END_PROFILE(SMBcopy);
-                               return;
+                               goto out;
                        }
 
                        if (!resolve_wildcards(ctx,
@@ -6769,24 +6826,21 @@ void reply_copy(struct smb_request *req)
                        if (!destname) {
                                TALLOC_FREE(dir_hnd);
                                reply_nterror(req, NT_STATUS_NO_MEMORY);
-                               END_PROFILE(SMBcopy);
-                               return;
+                               goto out;
                        }
 
                        status = check_name(conn, fname);
                        if (!NT_STATUS_IS_OK(status)) {
                                TALLOC_FREE(dir_hnd);
                                reply_nterror(req, status);
-                               END_PROFILE(SMBcopy);
-                               return;
+                               goto out;
                        }
 
                        status = check_name(conn, destname);
                        if (!NT_STATUS_IS_OK(status)) {
                                TALLOC_FREE(dir_hnd);
                                reply_nterror(req, status);
-                               END_PROFILE(SMBcopy);
-                               return;
+                               goto out;
                        }
 
                        DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname, destname));
@@ -6807,18 +6861,22 @@ void reply_copy(struct smb_request *req)
                        /* Error on close... */
                        errno = err;
                        reply_unixerror(req, ERRHRD, ERRgeneral);
-                       END_PROFILE(SMBcopy);
-                       return;
+                       goto out;
                }
 
                reply_doserror(req, ERRDOS, error);
-               END_PROFILE(SMBcopy);
-               return;
+               goto out;
        }
 
        reply_outbuf(req, 1, 0);
        SSVAL(req->outbuf,smb_vwv0,count);
-
+ out:
+       if (smb_fname) {
+               TALLOC_FREE(smb_fname);
+       }
+       if (smb_fname_new) {
+               TALLOC_FREE(smb_fname_new);
+       }
        END_PROFILE(SMBcopy);
        return;
 }
index edbb0dfc4d0217950681950898899342affdf2d6..a498e24d740837a9e0af7d27132de126652a85a6 100644 (file)
@@ -1882,6 +1882,7 @@ static void call_trans2findfirst(connection_struct *conn,
                maxentries then so be it. We assume that the redirector has
                enough room for the fixed number of parameter bytes it has
                requested. */
+       struct smb_filename *smb_dname = NULL;
        char *params = *pparams;
        char *pdata = *ppdata;
        char *data_end;
@@ -1904,7 +1905,6 @@ static void call_trans2findfirst(connection_struct *conn,
        bool out_of_space = False;
        int space_remaining;
        bool mask_contains_wcard = False;
-       SMB_STRUCT_STAT sbuf;
        struct ea_list *ea_list = NULL;
        NTSTATUS ntstatus = NT_STATUS_OK;
        bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true);
@@ -1981,7 +1981,17 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
                return;
        }
 
-       ntstatus = unix_convert(ctx, conn, directory, True, &directory, &mask, &sbuf);
+       ntstatus = unix_convert(ctx, conn, directory, &smb_dname,
+                               (UCF_SAVE_LCOMP | UCF_ALLOW_WCARD_LCOMP));
+       if (!NT_STATUS_IS_OK(ntstatus)) {
+               reply_nterror(req, ntstatus);
+               return;
+       }
+
+       mask = smb_dname->original_lcomp;
+
+       ntstatus = get_full_smb_filename(ctx, smb_dname, &directory);
+       TALLOC_FREE(smb_dname);
        if (!NT_STATUS_IS_OK(ntstatus)) {
                reply_nterror(req, ntstatus);
                return;
@@ -3834,6 +3844,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
        SMB_STRUCT_STAT sbuf;
        char *dos_fname = NULL;
        char *fname = NULL;
+       struct smb_filename *smb_fname = NULL;
        char *fullpathname;
        char *base_name;
        char *p;
@@ -3981,11 +3992,20 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
                        return;
                }
 
-               status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
+               status = unix_convert(ctx, conn, fname, &smb_fname, 0);
+               if (!NT_STATUS_IS_OK(status)) {
+                       reply_nterror(req, status);
+                       return;
+               }
+               sbuf = smb_fname->st;
+
+               status = get_full_smb_filename(ctx, smb_fname, &fname);
+               TALLOC_FREE(smb_fname);
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
                        return;
                }
+
                status = check_name(conn, fname);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,nt_errstr(status)));
@@ -4821,57 +4841,64 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
                const char *oldname_in,
                const char *newname_in)
 {
-       SMB_STRUCT_STAT sbuf1, sbuf2;
-       char *last_component_oldname = NULL;
-       char *last_component_newname = NULL;
+       struct smb_filename *smb_fname = NULL;
+       struct smb_filename *smb_fname_new = NULL;
        char *oldname = NULL;
        char *newname = NULL;
        NTSTATUS status = NT_STATUS_OK;
 
-       ZERO_STRUCT(sbuf1);
-       ZERO_STRUCT(sbuf2);
+       status = unix_convert(ctx, conn, oldname_in, &smb_fname, 0);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
+       }
 
-       status = unix_convert(ctx, conn, oldname_in, False, &oldname,
-                       &last_component_oldname, &sbuf1);
+       status = get_full_smb_filename(ctx, smb_fname, &oldname);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
        status = check_name(conn, oldname);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
        /* source must already exist. */
-       if (!VALID_STAT(sbuf1)) {
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       if (!VALID_STAT(smb_fname->st)) {
+               status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               goto out;
        }
 
-       status = unix_convert(ctx, conn, newname_in, False, &newname,
-                       &last_component_newname, &sbuf2);
+       status = unix_convert(ctx, conn, newname_in, &smb_fname_new, 0);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
+       }
+
+       status = get_full_smb_filename(ctx, smb_fname_new, &newname);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
        }
 
        status = check_name(conn, newname);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
        /* Disallow if newname already exists. */
-       if (VALID_STAT(sbuf2)) {
-               return NT_STATUS_OBJECT_NAME_COLLISION;
+       if (VALID_STAT(smb_fname_new->st)) {
+               status = NT_STATUS_OBJECT_NAME_COLLISION;
+               goto out;
        }
 
        /* No links from a directory. */
-       if (S_ISDIR(sbuf1.st_mode)) {
-               return NT_STATUS_FILE_IS_A_DIRECTORY;
+       if (S_ISDIR(smb_fname->st.st_mode)) {
+               status = NT_STATUS_FILE_IS_A_DIRECTORY;
+               goto out;
        }
 
        /* Ensure this is within the share. */
        status = check_reduced_name(conn, oldname);
        if (!NT_STATUS_IS_OK(status)) {
-               return status;
+               goto out;
        }
 
        DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", newname, oldname ));
@@ -4879,9 +4906,15 @@ NTSTATUS hardlink_internals(TALLOC_CTX *ctx,
        if (SMB_VFS_LINK(conn,oldname,newname) != 0) {
                status = map_nt_error_from_unix(errno);
                DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
-                                nt_errstr(status), newname, oldname));
+                                nt_errstr(status), newname, oldname));
+       }
+ out:
+       if (smb_fname) {
+               TALLOC_FREE(smb_fname);
+       }
+       if (smb_fname_new) {
+               TALLOC_FREE(smb_fname_new);
        }
-
        return status;
 }
 
@@ -5382,9 +5415,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
        uint32 len;
        char *newname = NULL;
        char *base_name = NULL;
+       struct smb_filename *smb_fname = NULL;
        bool dest_has_wcard = False;
-       SMB_STRUCT_STAT sbuf;
-       char *newname_last_component = NULL;
        NTSTATUS status = NT_STATUS_OK;
        char *p;
        TALLOC_CTX *ctx = talloc_tos();
@@ -5393,8 +5425,6 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       ZERO_STRUCT(sbuf);
-
        overwrite = (CVAL(pdata,0) ? True : False);
        root_fid = IVAL(pdata,4);
        len = IVAL(pdata,8);
@@ -5466,10 +5496,8 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                        return NT_STATUS_NO_MEMORY;
                }
 
-               status = unix_convert(ctx, conn, newname, False,
-                               &newname,
-                               &newname_last_component,
-                               &sbuf);
+               status = unix_convert(ctx, conn, newname, &smb_fname,
+                                     UCF_SAVE_LCOMP);
 
                /* If an error we expect this to be
                 * NT_STATUS_OBJECT_PATH_NOT_FOUND */
@@ -5477,7 +5505,7 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                if (!NT_STATUS_IS_OK(status)
                    && !NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND,
                                        status)) {
-                       return status;
+                       goto out;
                }
        }
 
@@ -5485,8 +5513,9 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n",
                        fsp->fnum, fsp->fsp_name, base_name ));
                status = rename_internals_fsp(conn, fsp, base_name,
-                                             newname_last_component, 0,
-                                             overwrite);
+                                             smb_fname ?
+                                             smb_fname->original_lcomp : NULL,
+                                             0, overwrite);
        } else {
                DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n",
                        fname, base_name ));
@@ -5494,7 +5523,10 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                                        overwrite, False, dest_has_wcard,
                                        FILE_WRITE_ATTRIBUTES);
        }
-
+ out:
+       if (smb_fname) {
+               TALLOC_FREE(smb_fname);
+       }
        return status;
 }
 
@@ -6700,6 +6732,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
        uint16 info_level;
        SMB_STRUCT_STAT sbuf;
        char *fname = NULL;
+       struct smb_filename *smb_fname = NULL;
        files_struct *fsp = NULL;
        NTSTATUS status = NT_STATUS_OK;
        int data_return_size = 0;
@@ -6814,8 +6847,15 @@ static void call_trans2setfilepathinfo(connection_struct *conn,
                        return;
                }
 
-               status = unix_convert(ctx, conn, fname, False,
-                               &fname, NULL, &sbuf);
+               status = unix_convert(ctx, conn, fname, &smb_fname, 0);
+               if (!NT_STATUS_IS_OK(status)) {
+                       reply_nterror(req, status);
+                       return;
+               }
+               sbuf = smb_fname->st;
+
+               status = get_full_smb_filename(ctx, smb_fname, &fname);
+               TALLOC_FREE(smb_fname);
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
                        return;
@@ -7129,10 +7169,10 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
                             char **ppdata, int total_data,
                             unsigned int max_data_bytes)
 {
+       struct smb_filename *smb_dname = NULL;
        char *params = *pparams;
        char *pdata = *ppdata;
        char *directory = NULL;
-       SMB_STRUCT_STAT sbuf;
        NTSTATUS status = NT_STATUS_OK;
        struct ea_list *ea_list = NULL;
        TALLOC_CTX *ctx = talloc_tos();
@@ -7157,7 +7197,13 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req,
 
        DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
 
-       status = unix_convert(ctx, conn, directory, False, &directory, NULL, &sbuf);
+       status = unix_convert(ctx, conn, directory, &smb_dname, 0);
+       if (!NT_STATUS_IS_OK(status)) {
+               reply_nterror(req, status);
+               return;
+       }
+
+       status = get_full_smb_filename(ctx, smb_dname, &directory);
        if (!NT_STATUS_IS_OK(status)) {
                reply_nterror(req, status);
                return;