vfs: Add SMB_VFS_GET_REAL_FILENAME_AT
[bbaumbach/samba-autobuild/.git] / source3 / modules / vfs_default.c
index 059a38a1320f772af16e8c510b42f2d7f7c14b24..ca928ded260a002f95117eccd27b3c412c2167de 100644 (file)
@@ -437,8 +437,6 @@ static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
 #endif
        int ret;
 
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
-
        if (is_named_stream(smb_fname)) {
                status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
                goto err;
@@ -459,7 +457,7 @@ static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
                }
        }
 
-       referral_len = readlinkat(fsp_get_io_fd(dirfsp),
+       referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
                                smb_fname->base_name,
                                link_target,
                                bufsize - 1);
@@ -499,9 +497,11 @@ static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
                goto err;
        }
 
-       ret = sys_lstat(smb_fname->base_name,
-                       &smb_fname->st,
-                       lp_fake_directory_create_times(SNUM(handle->conn)));
+       ret = sys_fstatat(fsp_get_pathref_fd(dirfsp),
+                        smb_fname->base_name,
+                        &smb_fname->st,
+                        AT_SYMLINK_NOFOLLOW,
+                        lp_fake_directory_create_times(SNUM(handle->conn)));
        if (ret < 0) {
                status = map_nt_error_from_unix(errno);
                goto err;
@@ -1314,6 +1314,33 @@ static int vfswrap_lstat(vfs_handle_struct *handle,
        return result;
 }
 
+static int vfswrap_fstatat(
+       struct vfs_handle_struct *handle,
+       const struct files_struct *dirfsp,
+       const struct smb_filename *smb_fname,
+       SMB_STRUCT_STAT *sbuf,
+       int flags)
+{
+       int result = -1;
+
+       START_PROFILE(syscall_fstatat);
+
+       if (is_named_stream(smb_fname)) {
+               errno = ENOENT;
+               goto out;
+       }
+
+       result = sys_fstatat(
+               fsp_get_pathref_fd(dirfsp),
+               smb_fname->base_name,
+               sbuf,
+               flags,
+               lp_fake_directory_create_times(SNUM(handle->conn)));
+ out:
+       END_PROFILE(syscall_fstatat);
+       return result;
+}
+
 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
                                       const char *name,
                                       enum vfs_translate_direction direction,
@@ -1326,7 +1353,7 @@ static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
 /**
  * Return allocated parent directory and basename of path
  *
- * Note: if requesting name, it is returned as talloc child of the
+ * Note: if requesting atname, it is returned as talloc child of the
  * parent. Freeing the parent is thus sufficient to free both.
  */
 static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
@@ -1340,12 +1367,11 @@ static NTSTATUS vfswrap_parent_pathname(struct vfs_handle_struct *handle,
        struct smb_filename *name = NULL;
        char *p = NULL;
 
-       parent = cp_smb_filename(frame, smb_fname_in);
+       parent = cp_smb_filename_nostream(frame, smb_fname_in);
        if (parent == NULL) {
                TALLOC_FREE(frame);
                return NT_STATUS_NO_MEMORY;
        }
-       TALLOC_FREE(parent->stream_name);
        SET_STAT_INVALID(parent->st);
 
        p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
@@ -1785,6 +1811,14 @@ static struct tevent_req *vfswrap_get_dos_attributes_send(
                .smb_fname = smb_fname,
        };
 
+       if (!lp_store_dos_attributes(SNUM(dir_fsp->conn))) {
+               DBG_ERR("%s: \"smbd async dosmode\" enabled, but "
+                       "\"store dos attributes\" is disabled\n",
+                       dir_fsp->conn->connectpath);
+               tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
+               return tevent_req_post(req, ev);
+       }
+
        subreq = SMB_VFS_GETXATTRAT_SEND(state,
                                         ev,
                                         dir_fsp,
@@ -1990,6 +2024,8 @@ static struct tevent_req *vfswrap_offload_read_send(
 static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
                                          struct vfs_handle_struct *handle,
                                          TALLOC_CTX *mem_ctx,
+                                         uint32_t *flags,
+                                         uint64_t *xferlen,
                                          DATA_BLOB *token)
 {
        struct vfswrap_offload_read_state *state = tevent_req_data(
@@ -2001,6 +2037,8 @@ static NTSTATUS vfswrap_offload_read_recv(struct tevent_req *req,
                return status;
        }
 
+       *flags = 0;
+       *xferlen = 0;
        token->length = state->token.length;
        token->data = talloc_move(mem_ctx, &state->token.data);
 
@@ -2214,10 +2252,11 @@ static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
        NTSTATUS status;
        bool same_file;
        bool ok;
+       static bool try_copy_file_range = true;
 
-#ifndef USE_COPY_FILE_RANGE
-       return NT_STATUS_MORE_PROCESSING_REQUIRED;
-#endif
+       if (!try_copy_file_range) {
+               return NT_STATUS_MORE_PROCESSING_REQUIRED;
+       }
 
        same_file = file_id_equal(&state->src_fsp->file_id,
                                  &state->dst_fsp->file_id);
@@ -2230,8 +2269,8 @@ static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
                return NT_STATUS_MORE_PROCESSING_REQUIRED;
        }
 
-       if (is_named_stream(state->src_fsp->fsp_name) ||
-           is_named_stream(state->dst_fsp->fsp_name))
+       if (fsp_is_alternate_stream(state->src_fsp) ||
+           fsp_is_alternate_stream(state->dst_fsp))
        {
                return NT_STATUS_MORE_PROCESSING_REQUIRED;
        }
@@ -2241,6 +2280,7 @@ static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
                                state->src_off,
                                state->remaining,
                                READ_LOCK,
+                               lp_posix_cifsu_locktype(state->src_fsp),
                                &lck);
 
        ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
@@ -2260,6 +2300,7 @@ static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
                                state->dst_off,
                                state->remaining,
                                WRITE_LOCK,
+                               lp_posix_cifsu_locktype(state->dst_fsp),
                                &lck);
 
        ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
@@ -2286,6 +2327,11 @@ static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
                                  (intmax_t)state->remaining,
                                  strerror(errno));
                        switch (errno) {
+                       case EOPNOTSUPP:
+                       case ENOSYS:
+                               try_copy_file_range = false;
+                               status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+                               break;
                        case EXDEV:
                                status = NT_STATUS_MORE_PROCESSING_REQUIRED;
                                break;
@@ -2349,6 +2395,7 @@ static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
                                state->src_off,
                                state->next_io_size,
                                READ_LOCK,
+                               lp_posix_cifsu_locktype(state->src_fsp),
                                &read_lck);
 
        ok = SMB_VFS_STRICT_LOCK_CHECK(state->src_fsp->conn,
@@ -2412,6 +2459,7 @@ static void vfswrap_offload_write_read_done(struct tevent_req *subreq)
                                state->dst_off,
                                state->next_io_size,
                                WRITE_LOCK,
+                               lp_posix_cifsu_locktype(state->dst_fsp),
                                &write_lck);
 
        ok = SMB_VFS_STRICT_LOCK_CHECK(state->dst_fsp->conn,
@@ -2748,7 +2796,7 @@ static int vfswrap_fntimes(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_fntimes);
 
-       if (is_named_stream(fsp->fsp_name)) {
+       if (fsp_is_alternate_stream(fsp)) {
                errno = ENOENT;
                goto out;
        }
@@ -3009,13 +3057,13 @@ static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, o
        return result;
 }
 
-static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
-                               uint32_t share_access, uint32_t access_mask)
+static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
+                                       files_struct *fsp,
+                                       uint32_t share_access,
+                                       uint32_t access_mask)
 {
-       START_PROFILE(syscall_kernel_flock);
-       kernel_flock(fsp_get_io_fd(fsp), share_access, access_mask);
-       END_PROFILE(syscall_kernel_flock);
-       return 0;
+       errno = ENOTSUP;
+       return -1;
 }
 
 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
@@ -3246,10 +3294,6 @@ static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
 {
        uint64_t file_id;
 
-       if (!(psbuf->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) {
-               return psbuf->st_ex_file_id;
-       }
-
        if (handle->conn->base_share_dev == psbuf->st_ex_dev) {
                return (uint64_t)psbuf->st_ex_ino;
        }
@@ -3314,18 +3358,31 @@ static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
        return NT_STATUS_OK;
 }
 
-static int vfswrap_get_real_filename(struct vfs_handle_struct *handle,
-                                    const struct smb_filename *path,
-                                    const char *name,
-                                    TALLOC_CTX *mem_ctx,
-                                    char **found_name)
+static NTSTATUS vfswrap_get_real_filename(struct vfs_handle_struct *handle,
+                                         const struct smb_filename *path,
+                                         const char *name,
+                                         TALLOC_CTX *mem_ctx,
+                                         char **found_name)
 {
        /*
         * Don't fall back to get_real_filename so callers can differentiate
         * between a full directory scan and an actual case-insensitive stat.
         */
-       errno = EOPNOTSUPP;
-       return -1;
+       return NT_STATUS_NOT_SUPPORTED;
+}
+
+static NTSTATUS vfswrap_get_real_filename_at(
+       struct vfs_handle_struct *handle,
+       struct files_struct *dirfsp,
+       const char *name,
+       TALLOC_CTX *mem_ctx,
+       char **found_name)
+{
+       /*
+        * Don't fall back to get_real_filename so callers can differentiate
+        * between a full directory scan and an actual case-insensitive stat.
+        */
+       return NT_STATUS_NOT_SUPPORTED;
 }
 
 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
@@ -3425,8 +3482,39 @@ static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
  Extended attribute operations.
 *****************************************************************/
 
+static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
+                                struct files_struct *fsp,
+                                const char *name,
+                                void *value,
+                                size_t size)
+{
+       int fd = fsp_get_pathref_fd(fsp);
+
+       if (!fsp->fsp_flags.is_pathref) {
+               return fgetxattr(fd, name, value, size);
+       }
+
+       if (fsp->fsp_flags.have_proc_fds) {
+               const char *p = NULL;
+               char buf[PATH_MAX];
+
+               p = sys_proc_fd_path(fd, buf, sizeof(buf));
+               if (p == NULL) {
+                       return -1;
+               }
+
+               return getxattr(p, name, value, size);
+       }
+
+       /*
+        * This is no longer a handle based call.
+        */
+       return getxattr(fsp->fsp_name->base_name, name, value, size);
+}
+
 struct vfswrap_getxattrat_state {
        struct tevent_context *ev;
+       struct vfs_handle_struct *handle;
        files_struct *dir_fsp;
        const struct smb_filename *smb_fname;
 
@@ -3479,6 +3567,7 @@ static struct tevent_req *vfswrap_getxattrat_send(
        }
        *state = (struct vfswrap_getxattrat_state) {
                .ev = ev,
+               .handle = handle,
                .dir_fsp = dir_fsp,
                .smb_fname = smb_fname,
        };
@@ -3577,31 +3666,15 @@ static void vfswrap_getxattrat_do_sync(struct tevent_req *req)
 {
        struct vfswrap_getxattrat_state *state = tevent_req_data(
                req, struct vfswrap_getxattrat_state);
-       char *path = NULL;
-       char *tofree = NULL;
-       char pathbuf[PATH_MAX+1];
-       ssize_t pathlen;
-       int err;
+       struct files_struct *fsp = metadata_fsp(state->smb_fname->fsp);
 
-       pathlen = full_path_tos(state->dir_fsp->fsp_name->base_name,
-                               state->smb_fname->base_name,
-                               pathbuf,
-                               sizeof(pathbuf),
-                               &path,
-                               &tofree);
-       if (pathlen == -1) {
-               tevent_req_error(req, ENOMEM);
-               return;
-       }
-
-       state->xattr_size = getxattr(path,
-                                    state->xattr_name,
-                                    state->xattr_value,
-                                    talloc_array_length(state->xattr_value));
-       err = errno;
-       TALLOC_FREE(tofree);
+       state->xattr_size = vfswrap_fgetxattr(state->handle,
+                                             fsp,
+                                             state->xattr_name,
+                                             state->xattr_value,
+                                             talloc_array_length(state->xattr_value));
        if (state->xattr_size == -1) {
-               tevent_req_error(req, err);
+               tevent_req_error(req, errno);
                return;
        }
 
@@ -3616,6 +3689,7 @@ static void vfswrap_getxattrat_do_async(void *private_data)
        struct timespec start_time;
        struct timespec end_time;
        int ret;
+       struct files_struct *fsp = metadata_fsp(state->smb_fname->fsp);
 
        PROFILE_TIMESTAMP(&start_time);
        SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes);
@@ -3638,17 +3712,11 @@ static void vfswrap_getxattrat_do_async(void *private_data)
                goto end_profile;
        }
 
-       ret = fchdir(fsp_get_pathref_fd(state->dir_fsp));
-       if (ret == -1) {
-               state->xattr_size = -1;
-               state->vfs_aio_state.error = errno;
-               goto end_profile;
-       }
-
-       state->xattr_size = getxattr(state->name,
-                                    state->xattr_name,
-                                    state->xattr_value,
-                                    talloc_array_length(state->xattr_value));
+       state->xattr_size = vfswrap_fgetxattr(state->handle,
+                                             fsp,
+                                             state->xattr_name,
+                                             state->xattr_value,
+                                             talloc_array_length(state->xattr_value));
        if (state->xattr_size == -1) {
                state->vfs_aio_state.error = errno;
        }
@@ -3742,36 +3810,6 @@ static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
        return xattr_size;
 }
 
-static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
-                                struct files_struct *fsp,
-                                const char *name,
-                                void *value,
-                                size_t size)
-{
-       int fd = fsp_get_pathref_fd(fsp);
-
-       if (!fsp->fsp_flags.is_pathref) {
-               return fgetxattr(fd, name, value, size);
-       }
-
-       if (fsp->fsp_flags.have_proc_fds) {
-               const char *p = NULL;
-               char buf[PATH_MAX];
-
-               p = sys_proc_fd_path(fd, buf, sizeof(buf));
-               if (p == NULL) {
-                       return -1;
-               }
-
-               return getxattr(p, name, value, size);
-       }
-
-       /*
-        * This is no longer a handle based call.
-        */
-       return getxattr(fsp->fsp_name->base_name, name, value, size);
-}
-
 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
 {
        int fd = fsp_get_pathref_fd(fsp);
@@ -3966,6 +4004,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .stat_fn = vfswrap_stat,
        .fstat_fn = vfswrap_fstat,
        .lstat_fn = vfswrap_lstat,
+       .fstatat_fn = vfswrap_fstatat,
        .get_alloc_size_fn = vfswrap_get_alloc_size,
        .unlinkat_fn = vfswrap_unlinkat,
        .fchmod_fn = vfswrap_fchmod,
@@ -3977,7 +4016,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .ftruncate_fn = vfswrap_ftruncate,
        .fallocate_fn = vfswrap_fallocate,
        .lock_fn = vfswrap_lock,
-       .kernel_flock_fn = vfswrap_kernel_flock,
+       .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
        .fcntl_fn = vfswrap_fcntl,
        .linux_setlease_fn = vfswrap_linux_setlease,
        .getlock_fn = vfswrap_getlock,
@@ -3991,6 +4030,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .fs_file_id_fn = vfswrap_fs_file_id,
        .fstreaminfo_fn = vfswrap_fstreaminfo,
        .get_real_filename_fn = vfswrap_get_real_filename,
+       .get_real_filename_at_fn = vfswrap_get_real_filename_at,
        .connectpath_fn = vfswrap_connectpath,
        .brl_lock_windows_fn = vfswrap_brl_lock_windows,
        .brl_unlock_windows_fn = vfswrap_brl_unlock_windows,