Fix bug 7104 - "wide links" and "unix extensions" are incompatible.
[samba.git] / source3 / smbd / vfs.c
index e2c929885779f1a25695c64738e78810431220de..94bdb1f495c423ce3eb0c252ec3e0c6b3f0308b1 100644 (file)
@@ -659,10 +659,13 @@ SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
  A vfs_readdir wrapper which just returns the file name.
 ********************************************************************/
 
-char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf)
+const char *vfs_readdirname(connection_struct *conn, void *p,
+                           SMB_STRUCT_STAT *sbuf, char **talloced)
 {
        SMB_STRUCT_DIRENT *ptr= NULL;
-       char *dname;
+       const char *dname;
+       char *translated;
+       NTSTATUS status;
 
        if (!p)
                return(NULL);
@@ -673,6 +676,7 @@ char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf)
 
        dname = ptr->d_name;
 
+
 #ifdef NEXT2
        if (telldir(p) < 0)
                return(NULL);
@@ -683,7 +687,17 @@ char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf)
        dname = dname - 2;
 #endif
 
-       return(dname);
+       status = SMB_VFS_TRANSLATE_NAME(conn, dname, vfs_translate_to_windows,
+                                       talloc_tos(), &translated);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
+               *talloced = NULL;
+               return dname;
+       }
+       *talloced = translated;
+       if (!NT_STATUS_IS_OK(status)) {
+               return NULL;
+       }
+       return translated;
 }
 
 /*******************************************************************
@@ -692,26 +706,7 @@ char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf)
 
 int vfs_ChDir(connection_struct *conn, const char *path)
 {
-       int res;
-
-       if (!LastDir) {
-               LastDir = SMB_STRDUP("");
-       }
-
-       if (strcsequal(path,"."))
-               return(0);
-
-       if (*path == '/' && strcsequal(LastDir,path))
-               return(0);
-
-       DEBUG(4,("vfs_ChDir to %s\n",path));
-
-       res = SMB_VFS_CHDIR(conn,path);
-       if (!res) {
-               SAFE_FREE(LastDir);
-               LastDir = SMB_STRDUP(path);
-       }
-       return(res);
+       return SMB_VFS_CHDIR(conn,path);
 }
 
 /*******************************************************************
@@ -834,7 +829,7 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
        char *resolved_name = NULL;
        char *p = NULL;
 
-       DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
+       DEBUG(3,("check_reduced_name [%s] [%s]\n", fname, conn->connectpath));
 
 #ifdef REALPATH_TAKES_NULL
        resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
@@ -845,8 +840,10 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
        if (!resolved_name) {
                switch (errno) {
                        case ENOTDIR:
-                               DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
-                               return map_nt_error_from_unix(errno);
+                               DEBUG(3,("check_reduced_name: Component not a "
+                                        "directory in getting realpath for "
+                                        "%s\n", fname));
+                               return NT_STATUS_OBJECT_PATH_NOT_FOUND;
                        case ENOENT:
                        {
                                TALLOC_CTX *ctx = talloc_tos();
@@ -877,8 +874,18 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
                                resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
 #endif
                                if (!resolved_name) {
-                                       DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
-                                       return map_nt_error_from_unix(errno);
+                                       NTSTATUS status = map_nt_error_from_unix(errno);
+
+                                       if (errno == ENOENT || errno == ENOTDIR) {
+                                               status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+                                       }
+
+                                       DEBUG(3,("check_reduce_named: "
+                                                "couldn't get realpath for "
+                                                "%s (%s)\n",
+                                               fname,
+                                               nt_errstr(status)));
+                                       return status;
                                }
                                tmp_fname = talloc_asprintf(ctx,
                                                "%s/%s",
@@ -891,7 +898,8 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
                                SAFE_FREE(resolved_name);
                                resolved_name = SMB_STRDUP(tmp_fname);
                                if (!resolved_name) {
-                                       DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
+                                       DEBUG(0, ("check_reduced_name: malloc "
+                                                 "fail for %s\n", tmp_fname));
                                        return NT_STATUS_NO_MEMORY;
                                }
 #else
@@ -901,15 +909,18 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
                                break;
                        }
                        default:
-                               DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
+                               DEBUG(1,("check_reduced_name: couldn't get "
+                                        "realpath for %s\n", fname));
                                return map_nt_error_from_unix(errno);
                }
        }
 
-       DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
+       DEBUG(10,("check_reduced_name realpath [%s] -> [%s]\n", fname,
+                 resolved_name));
 
        if (*resolved_name != '/') {
-               DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
+               DEBUG(0,("check_reduced_name: realpath doesn't return "
+                        "absolute paths !\n"));
                if (free_resolved_name) {
                        SAFE_FREE(resolved_name);
                }
@@ -922,7 +933,8 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
 
                    conn_rootdir = SMB_VFS_CONNECTPATH(conn, fname);
                    if (conn_rootdir == NULL) {
-                           DEBUG(2, ("check_reduced_name: Could not get conn_rootdir\n"));
+                           DEBUG(2, ("check_reduced_name: Could not get "
+                                     "conn_rootdir\n"));
                            if (free_resolved_name) {
                                    SAFE_FREE(resolved_name);
                            }
@@ -931,9 +943,9 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
 
                    if (strncmp(conn_rootdir, resolved_name,
                                strlen(conn_rootdir)) != 0) {
-                           DEBUG(2, ("reduce_name: Bad access attempt: %s is "
-                                     "a symlink outside the share path",
-                                     fname));
+                           DEBUG(2, ("check_reduced_name: Bad access "
+                                     "attempt: %s is a symlink outside the "
+                                     "share path\n", fname));
                            if (free_resolved_name) {
                                    SAFE_FREE(resolved_name);
                            }
@@ -964,7 +976,8 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
                        if (free_resolved_name) {
                                SAFE_FREE(resolved_name);
                        }
-                        DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
+                        DEBUG(3,("check_reduced_name: denied: file path name "
+                                "%s is a symlink\n",resolved_name));
                        TALLOC_FREE(smb_fname);
                        return NT_STATUS_ACCESS_DENIED;
                 }
@@ -972,7 +985,8 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
         }
 #endif
 
-       DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
+       DEBUG(3,("check_reduced_name: %s reduced to %s\n", fname,
+                resolved_name));
        if (free_resolved_name) {
                SAFE_FREE(resolved_name);
        }
@@ -997,7 +1011,12 @@ int vfs_stat_smb_fname(struct connection_struct *conn, const char *fname,
                return -1;
        }
 
-       ret = SMB_VFS_STAT(conn, smb_fname);
+       if (lp_posix_pathnames()) {
+               ret = SMB_VFS_LSTAT(conn, smb_fname);
+       } else {
+               ret = SMB_VFS_STAT(conn, smb_fname);
+       }
+
        if (ret != -1) {
                *psbuf = smb_fname->st;
        }
@@ -1033,6 +1052,31 @@ int vfs_lstat_smb_fname(struct connection_struct *conn, const char *fname,
        return ret;
 }
 
+/**
+ * Ensure LSTAT is called for POSIX paths.
+ */
+
+NTSTATUS vfs_stat_fsp(files_struct *fsp)
+{
+       int ret;
+
+       if(fsp->is_directory || fsp->fh->fd == -1) {
+               if (fsp->posix_open) {
+                       ret = SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name);
+               } else {
+                       ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name);
+               }
+               if (ret == -1) {
+                       return map_nt_error_from_unix(errno);
+               }
+       } else {
+               if(SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) {
+                       return map_nt_error_from_unix(errno);
+               }
+       }
+       return NT_STATUS_OK;
+}
+
 /*
   generate a file_id from a stat structure
  */
@@ -1051,7 +1095,7 @@ int smb_vfs_call_connect(struct vfs_handle_struct *handle,
 void smb_vfs_call_disconnect(struct vfs_handle_struct *handle)
 {
        VFS_FIND(disconnect);
-       return handle->fns->disconnect(handle);
+       handle->fns->disconnect(handle);
 }
 
 uint64_t smb_vfs_call_disk_free(struct vfs_handle_struct *handle,
@@ -1096,10 +1140,11 @@ int smb_vfs_call_statvfs(struct vfs_handle_struct *handle, const char *path,
        return handle->fns->statvfs(handle, path, statbuf);
 }
 
-uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle)
+uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle,
+                       enum timestamp_set_resolution *p_ts_res)
 {
        VFS_FIND(fs_capabilities);
-       return handle->fns->fs_capabilities(handle);
+       return handle->fns->fs_capabilities(handle, p_ts_res);
 }
 
 SMB_STRUCT_DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle,
@@ -1122,7 +1167,7 @@ void smb_vfs_call_seekdir(struct vfs_handle_struct *handle,
                          SMB_STRUCT_DIR *dirp, long offset)
 {
        VFS_FIND(seekdir);
-       return handle->fns->seekdir(handle, dirp, offset);
+       handle->fns->seekdir(handle, dirp, offset);
 }
 
 long smb_vfs_call_telldir(struct vfs_handle_struct *handle,
@@ -1136,7 +1181,7 @@ void smb_vfs_call_rewind_dir(struct vfs_handle_struct *handle,
                             SMB_STRUCT_DIR *dirp)
 {
        VFS_FIND(rewind_dir);
-       return handle->fns->rewind_dir(handle, dirp);
+       handle->fns->rewind_dir(handle, dirp);
 }
 
 int smb_vfs_call_mkdir(struct vfs_handle_struct *handle, const char *path,
@@ -1163,7 +1208,7 @@ void smb_vfs_call_init_search_op(struct vfs_handle_struct *handle,
                                 SMB_STRUCT_DIR *dirp)
 {
        VFS_FIND(init_search_op);
-       return handle->fns->init_search_op(handle, dirp);
+       handle->fns->init_search_op(handle, dirp);
 }
 
 int smb_vfs_call_open(struct vfs_handle_struct *handle,
@@ -1375,10 +1420,12 @@ int smb_vfs_call_ftruncate(struct vfs_handle_struct *handle,
 }
 
 int smb_vfs_call_kernel_flock(struct vfs_handle_struct *handle,
-                             struct files_struct *fsp, uint32 share_mode)
+                             struct files_struct *fsp, uint32 share_mode,
+                             uint32_t access_mask)
 {
        VFS_FIND(kernel_flock);
-       return handle->fns->kernel_flock(handle, fsp, share_mode);
+       return handle->fns->kernel_flock(handle, fsp, share_mode,
+                                        access_mask);
 }
 
 int smb_vfs_call_linux_setlease(struct vfs_handle_struct *handle,
@@ -1491,7 +1538,18 @@ void smb_vfs_call_strict_unlock(struct vfs_handle_struct *handle,
                                struct lock_struct *plock)
 {
        VFS_FIND(strict_unlock);
-       return handle->fns->strict_unlock(handle, fsp, plock);
+       handle->fns->strict_unlock(handle, fsp, plock);
+}
+
+NTSTATUS smb_vfs_call_translate_name(struct vfs_handle_struct *handle,
+                                    const char *name,
+                                    enum vfs_translate_direction direction,
+                                    TALLOC_CTX *mem_ctx,
+                                    char **mapped_name)
+{
+       VFS_FIND(translate_name);
+       return handle->fns->translate_name(handle, name, direction, mem_ctx,
+                                          mapped_name);
 }
 
 NTSTATUS smb_vfs_call_fget_nt_acl(struct vfs_handle_struct *handle,