vfs: Add SMB_VFS_GET_REAL_FILENAME_AT
[bbaumbach/samba-autobuild/.git] / source3 / modules / vfs_default.c
index bce50b990c119833d03693baec15fa3ae9d2e296..ca928ded260a002f95117eccd27b3c412c2167de 100644 (file)
@@ -35,6 +35,8 @@
 #include "lib/pthreadpool/pthreadpool_tevent.h"
 #include "librpc/gen_ndr/ndr_ioctl.h"
 #include "offload_token.h"
+#include "util_reparse.h"
+#include "lib/util/string_wrappers.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -47,7 +49,8 @@
 
 static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
 {
-    return 0;    /* Return >= 0 for success */
+       handle->conn->have_proc_fds = sys_have_proc_fds();
+       return 0;    /* Return >= 0 for success */
 }
 
 static void vfswrap_disconnect(vfs_handle_struct *handle)
@@ -383,8 +386,6 @@ static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
        int ret;
        char *msdfs_link = NULL;
 
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
-
        /* Form the msdfs_link contents */
        msdfs_link = msdfs_link_string(frame,
                                        reflist,
@@ -394,7 +395,7 @@ static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
        }
 
        ret = symlinkat(msdfs_link,
-                       dirfsp->fh->fd,
+                       fsp_get_pathref_fd(dirfsp),
                        smb_fname->base_name);
        if (ret == 0) {
                status = NT_STATUS_OK;
@@ -420,7 +421,7 @@ static NTSTATUS vfswrap_create_dfs_pathat(struct vfs_handle_struct *handle,
 static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
                                TALLOC_CTX *mem_ctx,
                                struct files_struct *dirfsp,
-                               const struct smb_filename *smb_fname,
+                               struct smb_filename *smb_fname,
                                struct referral **ppreflist,
                                size_t *preferral_count)
 {
@@ -434,8 +435,12 @@ static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
 #else
        char link_target_buf[7];
 #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;
+       }
 
        if (ppreflist == NULL && preferral_count == NULL) {
                /*
@@ -452,7 +457,7 @@ static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
                }
        }
 
-       referral_len = readlinkat(dirfsp->fh->fd,
+       referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
                                smb_fname->base_name,
                                link_target,
                                bufsize - 1);
@@ -467,10 +472,17 @@ static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
                        status = NT_STATUS_OBJECT_TYPE_MISMATCH;
                } else {
                        status = map_nt_error_from_unix(errno);
-                       DBG_ERR("Error reading "
-                               "msdfs link %s: %s\n",
-                               smb_fname->base_name,
-                               strerror(errno));
+                       if (errno == ENOENT) {
+                               DBG_NOTICE("Error reading "
+                                        "msdfs link %s: %s\n",
+                                        smb_fname->base_name,
+                                        strerror(errno));
+                       } else {
+                               DBG_ERR("Error reading "
+                                       "msdfs link %s: %s\n",
+                                       smb_fname->base_name,
+                                       strerror(errno));
+                       }
                }
                 goto err;
         }
@@ -485,6 +497,16 @@ static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
                goto err;
        }
 
+       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;
+       }
+
        if (ppreflist == NULL && preferral_count == NULL) {
                /* Early return for checking if this is a DFS link. */
                return NT_STATUS_OK;
@@ -547,58 +569,70 @@ static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
        DIR *result;
 
        START_PROFILE(syscall_fdopendir);
-       result = sys_fdopendir(fsp->fh->fd);
+       result = sys_fdopendir(fsp_get_io_fd(fsp));
        END_PROFILE(syscall_fdopendir);
        return result;
 }
 
 
 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
-                                         DIR *dirp,
-                                         SMB_STRUCT_STAT *sbuf)
+                                     struct files_struct *dirfsp,
+                                     DIR *dirp,
+                                     SMB_STRUCT_STAT *sbuf)
 {
        struct dirent *result;
+       bool fake_ctime = lp_fake_directory_create_times(SNUM(handle->conn));
+       int flags = AT_SYMLINK_NOFOLLOW;
+       SMB_STRUCT_STAT st;
+       int ret;
 
        START_PROFILE(syscall_readdir);
+
        result = readdir(dirp);
        END_PROFILE(syscall_readdir);
-       if (sbuf) {
-               /* Default Posix readdir() does not give us stat info.
-                * Set to invalid to indicate we didn't return this info. */
-               SET_STAT_INVALID(*sbuf);
-#if defined(HAVE_DIRFD) && defined(HAVE_FSTATAT)
-               if (result != NULL) {
-                       /* See if we can efficiently return this. */
-                       struct stat st;
-                       int flags = AT_SYMLINK_NOFOLLOW;
-                       int ret = fstatat(dirfd(dirp),
-                                       result->d_name,
-                                       &st,
-                                       flags);
-                       /*
-                        * As this is an optimization,
-                        * ignore it if we stat'ed a
-                        * symlink. Make the caller
-                        * do it again as we don't
-                        * know if they wanted the link
-                        * info, or its target info.
-                        */
-                       if ((ret == 0) && (!S_ISLNK(st.st_mode))) {
-                               init_stat_ex_from_stat(sbuf,
-                                       &st,
-                                       lp_fake_directory_create_times(
-                                               SNUM(handle->conn)));
-                       }
-               }
-#endif
+
+       if (sbuf == NULL) {
+               return result;
+       }
+       if (result == NULL) {
+               return NULL;
        }
+
+       /*
+        * Default Posix readdir() does not give us stat info.
+        * Set to invalid to indicate we didn't return this info.
+        */
+       SET_STAT_INVALID(*sbuf);
+
+       ret = sys_fstatat(dirfd(dirp),
+                     result->d_name,
+                     &st,
+                     flags,
+                     fake_ctime);
+       if (ret != 0) {
+               return result;
+       }
+
+       /*
+        * As this is an optimization, ignore it if we stat'ed a
+        * symlink for non-POSIX context. Make the caller do it again
+        * as we don't know if they wanted the link info, or its
+        * target info.
+        */
+       if (S_ISLNK(st.st_ex_mode) &&
+           !(dirfsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH))
+       {
+               return result;
+       }
+       *sbuf = st;
+
        return result;
 }
 
-static NTSTATUS vfswrap_readdir_attr(struct vfs_handle_struct *handle,
-                                    const struct smb_filename *fname,
-                                    TALLOC_CTX *mem_ctx,
-                                    struct readdir_attr_data **attr_data)
+static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
+                                     struct files_struct *fsp,
+                                     TALLOC_CTX *mem_ctx,
+                                     struct readdir_attr_data **attr_data)
 {
        return NT_STATUS_NOT_SUPPORTED;
 }
@@ -632,26 +666,10 @@ static int vfswrap_mkdirat(vfs_handle_struct *handle,
                        mode_t mode)
 {
        int result;
-       struct smb_filename *parent = NULL;
-       bool ok;
 
        START_PROFILE(syscall_mkdirat);
 
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
-
-       if (lp_inherit_acls(SNUM(handle->conn))) {
-               ok = parent_smb_fname(talloc_tos(), smb_fname, &parent, NULL);
-               if (ok && directory_has_default_acl(handle->conn,
-                               dirfsp,
-                               parent))
-               {
-                       mode = (0777 & lp_directory_mask(SNUM(handle->conn)));
-               }
-       }
-
-       TALLOC_FREE(parent);
-
-       result = mkdirat(dirfsp->fh->fd, smb_fname->base_name, mode);
+       result = mkdirat(fsp_get_pathref_fd(dirfsp), smb_fname->base_name, mode);
 
        END_PROFILE(syscall_mkdirat);
        return result;
@@ -669,28 +687,54 @@ static int vfswrap_closedir(vfs_handle_struct *handle, DIR *dirp)
 
 /* File operations */
 
-static int vfswrap_open(vfs_handle_struct *handle,
-                       struct smb_filename *smb_fname,
-                       files_struct *fsp, int flags, mode_t mode)
+static int vfswrap_openat(vfs_handle_struct *handle,
+                         const struct files_struct *dirfsp,
+                         const struct smb_filename *smb_fname,
+                         files_struct *fsp,
+                         int flags,
+                         mode_t mode)
 {
-       int result = -1;
+       bool have_opath = false;
+       bool became_root = false;
+       int result;
 
-       START_PROFILE(syscall_open);
+       START_PROFILE(syscall_openat);
 
        if (is_named_stream(smb_fname)) {
                errno = ENOENT;
+               result = -1;
                goto out;
        }
 
-       result = open(smb_fname->base_name, flags, mode);
- out:
-       END_PROFILE(syscall_open);
+#ifdef O_PATH
+       have_opath = true;
+       if (fsp->fsp_flags.is_pathref) {
+               flags |= O_PATH;
+       }
+#endif
+
+       if (fsp->fsp_flags.is_pathref && !have_opath) {
+               become_root();
+               became_root = true;
+       }
+
+       result = openat(fsp_get_pathref_fd(dirfsp),
+                       smb_fname->base_name,
+                       flags,
+                       mode);
+
+       if (became_root) {
+               unbecome_root();
+       }
+
+       fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
+
+out:
+       END_PROFILE(syscall_openat);
        return result;
 }
-
 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
                                    struct smb_request *req,
-                                   uint16_t root_dir_fid,
                                    struct smb_filename *smb_fname,
                                    uint32_t access_mask,
                                    uint32_t share_access,
@@ -708,7 +752,7 @@ static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
                                    const struct smb2_create_blobs *in_context_blobs,
                                    struct smb2_create_blobs *out_context_blobs)
 {
-       return create_file_default(handle->conn, req, root_dir_fid, smb_fname,
+       return create_file_default(handle->conn, req, smb_fname,
                                   access_mask, share_access,
                                   create_disposition, create_options,
                                   file_attributes, oplock_request, lease,
@@ -734,13 +778,13 @@ static ssize_t vfswrap_pread(vfs_handle_struct *handle, files_struct *fsp, void
 
 #if defined(HAVE_PREAD) || defined(HAVE_PREAD64)
        START_PROFILE_BYTES(syscall_pread, n);
-       result = sys_pread_full(fsp->fh->fd, data, n, offset);
+       result = sys_pread_full(fsp_get_io_fd(fsp), data, n, offset);
        END_PROFILE_BYTES(syscall_pread);
 
        if (result == -1 && errno == ESPIPE) {
                /* Maintain the fiction that pipes can be seeked (sought?) on. */
-               result = sys_read(fsp->fh->fd, data, n);
-               fsp->fh->pos = 0;
+               result = sys_read(fsp_get_io_fd(fsp), data, n);
+               fh_set_pos(fsp->fh, 0);
        }
 
 #else /* HAVE_PREAD */
@@ -758,12 +802,12 @@ static ssize_t vfswrap_pwrite(vfs_handle_struct *handle, files_struct *fsp, cons
 
 #if defined(HAVE_PWRITE) || defined(HAVE_PRWITE64)
        START_PROFILE_BYTES(syscall_pwrite, n);
-       result = sys_pwrite_full(fsp->fh->fd, data, n, offset);
+       result = sys_pwrite_full(fsp_get_io_fd(fsp), data, n, offset);
        END_PROFILE_BYTES(syscall_pwrite);
 
        if (result == -1 && errno == ESPIPE) {
                /* Maintain the fiction that pipes can be sought on. */
-               result = sys_write(fsp->fh->fd, data, n);
+               result = sys_write(fsp_get_io_fd(fsp), data, n);
        }
 
 #else /* HAVE_PWRITE */
@@ -805,7 +849,7 @@ static struct tevent_req *vfswrap_pread_send(struct vfs_handle_struct *handle,
        }
 
        state->ret = -1;
-       state->fd = fsp->fh->fd;
+       state->fd = fsp_get_io_fd(fsp);
        state->buf = data;
        state->count = n;
        state->offset = offset;
@@ -933,7 +977,7 @@ static struct tevent_req *vfswrap_pwrite_send(struct vfs_handle_struct *handle,
        }
 
        state->ret = -1;
-       state->fd = fsp->fh->fd;
+       state->fd = fsp_get_io_fd(fsp);
        state->buf = data;
        state->count = n;
        state->offset = offset;
@@ -966,10 +1010,10 @@ static void vfs_pwrite_do(void *private_data)
 
        PROFILE_TIMESTAMP(&start_time);
 
-       do {
-               state->ret = pwrite(state->fd, state->buf, state->count,
-                                  state->offset);
-       } while ((state->ret == -1) && (errno == EINTR));
+       state->ret = sys_pwrite_full(state->fd,
+                                    state->buf,
+                                    state->count,
+                                    state->offset);
 
        if (state->ret == -1) {
                state->vfs_aio_state.error = errno;
@@ -1056,7 +1100,7 @@ static struct tevent_req *vfswrap_fsync_send(struct vfs_handle_struct *handle,
        }
 
        state->ret = -1;
-       state->fd = fsp->fh->fd;
+       state->fd = fsp_get_io_fd(fsp);
 
        SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p,
                                     state->profile_bytes, 0);
@@ -1154,7 +1198,7 @@ static off_t vfswrap_lseek(vfs_handle_struct *handle, files_struct *fsp, off_t o
 
        START_PROFILE(syscall_lseek);
 
-       result = lseek(fsp->fh->fd, offset, whence);
+       result = lseek(fsp_get_io_fd(fsp), offset, whence);
        /*
         * We want to maintain the fiction that we can seek
         * on a fifo for file system purposes. This allows
@@ -1177,7 +1221,7 @@ static ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struc
        ssize_t result;
 
        START_PROFILE_BYTES(syscall_sendfile, n);
-       result = sys_sendfile(tofd, fromfsp->fh->fd, hdr, offset, n);
+       result = sys_sendfile(tofd, fsp_get_io_fd(fromfsp), hdr, offset, n);
        END_PROFILE_BYTES(syscall_sendfile);
        return result;
 }
@@ -1191,7 +1235,7 @@ static ssize_t vfswrap_recvfile(vfs_handle_struct *handle,
        ssize_t result;
 
        START_PROFILE_BYTES(syscall_recvfile, n);
-       result = sys_recvfile(fromfd, tofsp->fh->fd, offset, n);
+       result = sys_recvfile(fromfd, fsp_get_io_fd(tofsp), offset, n);
        END_PROFILE_BYTES(syscall_recvfile);
        return result;
 }
@@ -1211,9 +1255,9 @@ static int vfswrap_renameat(vfs_handle_struct *handle,
                goto out;
        }
 
-       result = renameat(srcfsp->fh->fd,
+       result = renameat(fsp_get_pathref_fd(srcfsp),
                        smb_fname_src->base_name,
-                       dstfsp->fh->fd,
+                       fsp_get_pathref_fd(dstfsp),
                        smb_fname_dst->base_name);
 
  out:
@@ -1245,7 +1289,7 @@ static int vfswrap_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUC
        int result;
 
        START_PROFILE(syscall_fstat);
-       result = sys_fstat(fsp->fh->fd,
+       result = sys_fstat(fsp_get_pathref_fd(fsp),
                           sbuf, lp_fake_directory_create_times(SNUM(handle->conn)));
        END_PROFILE(syscall_fstat);
        return result;
@@ -1270,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,
@@ -1279,6 +1350,69 @@ static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
        return NT_STATUS_NONE_MAPPED;
 }
 
+/**
+ * Return allocated parent directory and basename of path
+ *
+ * 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,
+                                       TALLOC_CTX *mem_ctx,
+                                       const struct smb_filename *smb_fname_in,
+                                       struct smb_filename **parent_dir_out,
+                                       struct smb_filename **atname_out)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct smb_filename *parent = NULL;
+       struct smb_filename *name = NULL;
+       char *p = NULL;
+
+       parent = cp_smb_filename_nostream(frame, smb_fname_in);
+       if (parent == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
+       SET_STAT_INVALID(parent->st);
+
+       p = strrchr_m(parent->base_name, '/'); /* Find final '/', if any */
+       if (p == NULL) {
+               TALLOC_FREE(parent->base_name);
+               parent->base_name = talloc_strdup(parent, ".");
+               if (parent->base_name == NULL) {
+                       TALLOC_FREE(frame);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               p = smb_fname_in->base_name;
+       } else {
+               *p = '\0';
+               p++;
+       }
+
+       if (atname_out == NULL) {
+               *parent_dir_out = talloc_move(mem_ctx, &parent);
+               TALLOC_FREE(frame);
+               return NT_STATUS_OK;
+       }
+
+       name = cp_smb_filename(frame, smb_fname_in);
+       if (name == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
+       TALLOC_FREE(name->base_name);
+
+       name->base_name = talloc_strdup(name, p);
+       if (name->base_name == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       *parent_dir_out = talloc_move(mem_ctx, &parent);
+       *atname_out = talloc_move(*parent_dir_out, &name);
+       TALLOC_FREE(frame);
+       return NT_STATUS_OK;
+}
+
 /*
  * Implement the default fsctl operation.
  */
@@ -1349,18 +1483,21 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
 
        case FSCTL_GET_REPARSE_POINT:
        {
-               /* Fail it with STATUS_NOT_A_REPARSE_POINT */
-               DEBUG(10, ("FSCTL_GET_REPARSE_POINT: called on %s. "
-                          "Status: NOT_IMPLEMENTED\n", fsp_fnum_dbg(fsp)));
-               return NT_STATUS_NOT_A_REPARSE_POINT;
+               status = fsctl_get_reparse_point(
+                       fsp, ctx, out_data, max_out_len, out_len);
+               return status;
        }
 
        case FSCTL_SET_REPARSE_POINT:
        {
-               /* Fail it with STATUS_NOT_A_REPARSE_POINT */
-               DEBUG(10, ("FSCTL_SET_REPARSE_POINT: called on %s. "
-                          "Status: NOT_IMPLEMENTED\n", fsp_fnum_dbg(fsp)));
-               return NT_STATUS_NOT_A_REPARSE_POINT;
+               status = fsctl_set_reparse_point(fsp, ctx, _in_data, in_len);
+               return status;
+       }
+
+       case FSCTL_DELETE_REPARSE_POINT:
+       {
+               status = fsctl_del_reparse_point(fsp, ctx, _in_data, in_len);
+               return status;
        }
 
        case FSCTL_GET_SHADOW_COPY_DATA:
@@ -1636,20 +1773,6 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
 static bool vfswrap_is_offline(struct connection_struct *conn,
                               const struct smb_filename *fname);
 
-static NTSTATUS vfswrap_get_dos_attributes(struct vfs_handle_struct *handle,
-                                          struct smb_filename *smb_fname,
-                                          uint32_t *dosmode)
-{
-       bool offline;
-
-       offline = vfswrap_is_offline(handle->conn, smb_fname);
-       if (offline) {
-               *dosmode |= FILE_ATTRIBUTE_OFFLINE;
-       }
-
-       return get_ea_dos_attribute(handle->conn, smb_fname, dosmode);
-}
-
 struct vfswrap_get_dos_attributes_state {
        struct vfs_aio_state aio_state;
        connection_struct *conn;
@@ -1688,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,
@@ -1827,14 +1958,7 @@ static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
                *dosmode |= FILE_ATTRIBUTE_OFFLINE;
        }
 
-       return get_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
-}
-
-static NTSTATUS vfswrap_set_dos_attributes(struct vfs_handle_struct *handle,
-                                          const struct smb_filename *smb_fname,
-                                          uint32_t dosmode)
-{
-       return set_ea_dos_attribute(handle->conn, smb_fname, dosmode);
+       return fget_ea_dos_attribute(fsp, dosmode);
 }
 
 static NTSTATUS vfswrap_fset_dos_attributes(struct vfs_handle_struct *handle,
@@ -1900,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(
@@ -1911,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);
 
@@ -1931,6 +2059,7 @@ struct vfswrap_offload_write_state {
        off_t dst_off;
        off_t to_copy;
        off_t remaining;
+       off_t copied;
        size_t next_io_size;
 };
 
@@ -1950,6 +2079,7 @@ static void vfswrap_offload_write_cleanup(struct tevent_req *req,
        state->dst_fsp = NULL;
 }
 
+static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req);
 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req);
 
 static struct tevent_req *vfswrap_offload_write_send(
@@ -2089,6 +2219,16 @@ static struct tevent_req *vfswrap_offload_write_send(
                return tevent_req_post(req, ev);
        }
 
+       status = vfswrap_offload_copy_file_range(req);
+       if (NT_STATUS_IS_OK(status)) {
+               tevent_req_done(req);
+               return tevent_req_post(req, ev);
+       }
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               tevent_req_nterror(req, status);
+               return tevent_req_post(req, ev);
+       }
+
        state->buf = talloc_array(state, uint8_t, num);
        if (tevent_req_nomem(state->buf, req)) {
                return tevent_req_post(req, ev);
@@ -2103,6 +2243,137 @@ static struct tevent_req *vfswrap_offload_write_send(
        return req;
 }
 
+static NTSTATUS vfswrap_offload_copy_file_range(struct tevent_req *req)
+{
+       struct vfswrap_offload_write_state *state = tevent_req_data(
+               req, struct vfswrap_offload_write_state);
+       struct lock_struct lck;
+       ssize_t nwritten;
+       NTSTATUS status;
+       bool same_file;
+       bool ok;
+       static bool try_copy_file_range = true;
+
+       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);
+       if (same_file &&
+           sys_io_ranges_overlap(state->remaining,
+                                 state->src_off,
+                                 state->remaining,
+                                 state->dst_off))
+       {
+               return NT_STATUS_MORE_PROCESSING_REQUIRED;
+       }
+
+       if (fsp_is_alternate_stream(state->src_fsp) ||
+           fsp_is_alternate_stream(state->dst_fsp))
+       {
+               return NT_STATUS_MORE_PROCESSING_REQUIRED;
+       }
+
+       init_strict_lock_struct(state->src_fsp,
+                               state->src_fsp->op->global->open_persistent_id,
+                               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,
+                                state->src_fsp,
+                                &lck);
+       if (!ok) {
+               return NT_STATUS_FILE_LOCK_CONFLICT;
+       }
+
+       ok = change_to_user_and_service_by_fsp(state->dst_fsp);
+       if (!ok) {
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       init_strict_lock_struct(state->dst_fsp,
+                               state->dst_fsp->op->global->open_persistent_id,
+                               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,
+                                      state->dst_fsp,
+                                      &lck);
+       if (!ok) {
+               return NT_STATUS_FILE_LOCK_CONFLICT;
+       }
+
+       while (state->remaining > 0) {
+               nwritten = copy_file_range(fsp_get_io_fd(state->src_fsp),
+                                          &state->src_off,
+                                          fsp_get_io_fd(state->dst_fsp),
+                                          &state->dst_off,
+                                          state->remaining,
+                                          0);
+               if (nwritten == -1) {
+                       DBG_DEBUG("copy_file_range src [%s]:[%jd] dst [%s]:[%jd] "
+                                 "n [%jd] failed: %s\n",
+                                 fsp_str_dbg(state->src_fsp),
+                                 (intmax_t)state->src_off,
+                                 fsp_str_dbg(state->dst_fsp),
+                                 (intmax_t)state->dst_off,
+                                 (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;
+                       default:
+                               status = map_nt_error_from_unix(errno);
+                               if (NT_STATUS_EQUAL(
+                                           status,
+                                           NT_STATUS_MORE_PROCESSING_REQUIRED))
+                               {
+                                       /* Avoid triggering the fallback */
+                                       status = NT_STATUS_INTERNAL_ERROR;
+                               }
+                               break;
+                       }
+                       return status;
+               }
+
+               if (state->remaining < nwritten) {
+                       DBG_DEBUG("copy_file_range src [%s] dst [%s] "
+                                 "n [%jd] remaining [%jd]\n",
+                                 fsp_str_dbg(state->src_fsp),
+                                 fsp_str_dbg(state->dst_fsp),
+                                 (intmax_t)nwritten,
+                                 (intmax_t)state->remaining);
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+
+               if (nwritten == 0) {
+                       break;
+               }
+               state->copied += nwritten;
+               state->remaining -= nwritten;
+       }
+
+       /*
+        * Tell the req cleanup function there's no need to call
+        * change_to_user_and_service_by_fsp() on the dst handle.
+        */
+       state->dst_fsp = NULL;
+       return NT_STATUS_OK;
+}
+
 static void vfswrap_offload_write_read_done(struct tevent_req *subreq);
 
 static NTSTATUS vfswrap_offload_write_loop(struct tevent_req *req)
@@ -2124,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,
@@ -2187,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,
@@ -2241,6 +2514,7 @@ static void vfswrap_offload_write_write_done(struct tevent_req *subreq)
                tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
                return;
        }
+       state->copied += nwritten;
        state->remaining -= nwritten;
        if (state->remaining == 0) {
                tevent_req_done(req);
@@ -2277,17 +2551,16 @@ static NTSTATUS vfswrap_offload_write_recv(struct vfs_handle_struct *handle,
                return status;
        }
 
-       *copied = state->to_copy;
+       *copied = state->copied;
        DBG_DEBUG("copy chunk copied %lu\n", (unsigned long)*copied);
        tevent_req_received(req);
 
        return NT_STATUS_OK;
 }
 
-static NTSTATUS vfswrap_get_compression(struct vfs_handle_struct *handle,
+static NTSTATUS vfswrap_fget_compression(struct vfs_handle_struct *handle,
                                        TALLOC_CTX *mem_ctx,
                                        struct files_struct *fsp,
-                                       struct smb_filename *smb_fname,
                                        uint16_t *_compression_fmt)
 {
        return NT_STATUS_INVALID_DEVICE_REQUEST;
@@ -2368,13 +2641,11 @@ static int vfswrap_unlinkat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_unlinkat);
 
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
-
        if (is_named_stream(smb_fname)) {
                errno = ENOENT;
                goto out;
        }
-       result = unlinkat(dirfsp->fh->fd,
+       result = unlinkat(fsp_get_pathref_fd(dirfsp),
                        smb_fname->base_name,
                        flags);
 
@@ -2383,29 +2654,37 @@ static int vfswrap_unlinkat(vfs_handle_struct *handle,
        return result;
 }
 
-static int vfswrap_chmod(vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname,
-                       mode_t mode)
-{
-       int result;
-
-       START_PROFILE(syscall_chmod);
-       result = chmod(smb_fname->base_name, mode);
-       END_PROFILE(syscall_chmod);
-       return result;
-}
-
 static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
 {
        int result;
 
        START_PROFILE(syscall_fchmod);
-#if defined(HAVE_FCHMOD)
-       result = fchmod(fsp->fh->fd, mode);
-#else
-       result = -1;
-       errno = ENOSYS;
-#endif
+
+       if (!fsp->fsp_flags.is_pathref) {
+               result = fchmod(fsp_get_io_fd(fsp), mode);
+               END_PROFILE(syscall_fchmod);
+               return result;
+       }
+
+       if (fsp->fsp_flags.have_proc_fds) {
+               int fd = fsp_get_pathref_fd(fsp);
+               const char *p = NULL;
+               char buf[PATH_MAX];
+
+               p = sys_proc_fd_path(fd, buf, sizeof(buf));
+               if (p != NULL) {
+                       result = chmod(p, mode);
+               } else {
+                       result = -1;
+               }
+               END_PROFILE(syscall_fchmod);
+               return result;
+       }
+
+       /*
+        * This is no longer a handle based call.
+        */
+       result = chmod(fsp->fsp_name->base_name, mode);
 
        END_PROFILE(syscall_fchmod);
        return result;
@@ -2417,7 +2696,31 @@ static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t ui
        int result;
 
        START_PROFILE(syscall_fchown);
-       result = fchown(fsp->fh->fd, uid, gid);
+       if (!fsp->fsp_flags.is_pathref) {
+               result = fchown(fsp_get_io_fd(fsp), uid, gid);
+               END_PROFILE(syscall_fchown);
+               return result;
+       }
+
+       if (fsp->fsp_flags.have_proc_fds) {
+               int fd = fsp_get_pathref_fd(fsp);
+               const char *p = NULL;
+               char buf[PATH_MAX];
+
+               p = sys_proc_fd_path(fd, buf, sizeof(buf));
+               if (p != NULL) {
+                       result = chown(p, uid, gid);
+               } else {
+                       result = -1;
+               }
+               END_PROFILE(syscall_fchown);
+               return result;
+       }
+
+       /*
+        * This is no longer a handle based call.
+        */
+       result = chown(fsp->fsp_name->base_name, uid, gid);
        END_PROFILE(syscall_fchown);
        return result;
 #else
@@ -2483,89 +2786,87 @@ static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle,
  system will support.
 **********************************************************************/
 
-static int vfswrap_ntimes(vfs_handle_struct *handle,
-                         const struct smb_filename *smb_fname,
-                         struct smb_file_time *ft)
+static int vfswrap_fntimes(vfs_handle_struct *handle,
+                          files_struct *fsp,
+                          struct smb_file_time *ft)
 {
        int result = -1;
+       struct timespec ts[2];
+       struct timespec *times = NULL;
 
-       START_PROFILE(syscall_ntimes);
+       START_PROFILE(syscall_fntimes);
 
-       if (is_named_stream(smb_fname)) {
+       if (fsp_is_alternate_stream(fsp)) {
                errno = ENOENT;
                goto out;
        }
 
        if (ft != NULL) {
                if (is_omit_timespec(&ft->atime)) {
-                       ft->atime= smb_fname->st.st_ex_atime;
+                       ft->atime = fsp->fsp_name->st.st_ex_atime;
                }
 
                if (is_omit_timespec(&ft->mtime)) {
-                       ft->mtime = smb_fname->st.st_ex_mtime;
+                       ft->mtime = fsp->fsp_name->st.st_ex_mtime;
                }
 
                if (!is_omit_timespec(&ft->create_time)) {
-                       set_create_timespec_ea(handle->conn,
-                                              smb_fname,
+                       set_create_timespec_ea(fsp,
                                               ft->create_time);
                }
 
                if ((timespec_compare(&ft->atime,
-                                     &smb_fname->st.st_ex_atime) == 0) &&
+                                     &fsp->fsp_name->st.st_ex_atime) == 0) &&
                    (timespec_compare(&ft->mtime,
-                                     &smb_fname->st.st_ex_mtime) == 0)) {
-                       return 0;
+                                     &fsp->fsp_name->st.st_ex_mtime) == 0)) {
+                       result = 0;
+                       goto out;
                }
-       }
 
-#if defined(HAVE_UTIMENSAT)
-       if (ft != NULL) {
-               struct timespec ts[2];
                ts[0] = ft->atime;
                ts[1] = ft->mtime;
-               result = utimensat(AT_FDCWD, smb_fname->base_name, ts, 0);
+               times = ts;
        } else {
-               result = utimensat(AT_FDCWD, smb_fname->base_name, NULL, 0);
+               times = NULL;
        }
-       if (!((result == -1) && (errno == ENOSYS))) {
-               goto out;
-       }
-#endif
-#if defined(HAVE_UTIMES)
-       if (ft != NULL) {
-               struct timeval tv[2];
-               tv[0] = convert_timespec_to_timeval(ft->atime);
-               tv[1] = convert_timespec_to_timeval(ft->mtime);
-               result = utimes(smb_fname->base_name, tv);
-       } else {
-               result = utimes(smb_fname->base_name, NULL);
-       }
-       if (!((result == -1) && (errno == ENOSYS))) {
+
+       if (!fsp->fsp_flags.is_pathref) {
+               result = futimens(fsp_get_io_fd(fsp), times);
                goto out;
        }
-#endif
-#if defined(HAVE_UTIME)
-       if (ft != NULL) {
-               struct utimbuf times;
-               times.actime = convert_timespec_to_time_t(ft->atime);
-               times.modtime = convert_timespec_to_time_t(ft->mtime);
-               result = utime(smb_fname->base_name, &times);
-       } else {
-               result = utime(smb_fname->base_name, NULL);
-       }
-       if (!((result == -1) && (errno == ENOSYS))) {
+
+       if (fsp->fsp_flags.have_proc_fds) {
+               int fd = fsp_get_pathref_fd(fsp);
+               const char *p = NULL;
+               char buf[PATH_MAX];
+
+               p = sys_proc_fd_path(fd, buf, sizeof(buf));
+               if (p != NULL) {
+                       /*
+                        * The dirfd argument of utimensat is ignored when
+                        * pathname is an absolute path
+                        */
+                       result = utimensat(AT_FDCWD, p, times, 0);
+               } else {
+                       result = -1;
+               }
+
                goto out;
        }
-#endif
-       errno = ENOSYS;
-       result = -1;
 
- out:
-       END_PROFILE(syscall_ntimes);
+       /*
+        * The fd is a pathref (opened with O_PATH) and there isn't fd to
+        * path translation mechanism. Fallback to path based call.
+        */
+       result = utimensat(AT_FDCWD, fsp->fsp_name->base_name, times, 0);
+
+out:
+       END_PROFILE(syscall_fntimes);
+
        return result;
 }
 
+
 /*********************************************************************
  A version of ftruncate that will write the space on disk if strict
  allocate is set.
@@ -2603,7 +2904,7 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs
 
        /* Shrink - just ftruncate. */
        if (pst->st_ex_size > len)
-               return ftruncate(fsp->fh->fd, len);
+               return ftruncate(fsp_get_io_fd(fsp), len);
 
        space_to_write = len - pst->st_ex_size;
 
@@ -2662,7 +2963,7 @@ static int vfswrap_ftruncate(vfs_handle_struct *handle, files_struct *fsp, off_t
           expansion and some that don't! On Linux fat can't do
           ftruncate extend but ext2 can. */
 
-       result = ftruncate(fsp->fh->fd, len);
+       result = ftruncate(fsp_get_io_fd(fsp), len);
 
        /* According to W. R. Stevens advanced UNIX prog. Pure 4.3 BSD cannot
           extend a file with ftruncate. Provide alternate implementation
@@ -2723,7 +3024,7 @@ static int vfswrap_fallocate(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_fallocate);
        if (mode == 0) {
-               result = sys_posix_fallocate(fsp->fh->fd, offset, len);
+               result = sys_posix_fallocate(fsp_get_io_fd(fsp), offset, len);
                /*
                 * posix_fallocate returns 0 on success, errno on error
                 * and doesn't set errno. Make it behave like fallocate()
@@ -2735,7 +3036,7 @@ static int vfswrap_fallocate(vfs_handle_struct *handle,
                }
        } else {
                /* sys_fallocate handles filtering of unsupported mode flags */
-               result = sys_fallocate(fsp->fh->fd, mode, offset, len);
+               result = sys_fallocate(fsp_get_io_fd(fsp), mode, offset, len);
        }
        END_PROFILE(syscall_fallocate);
        return result;
@@ -2751,18 +3052,18 @@ static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, o
                op = map_process_lock_to_ofd_lock(op);
        }
 
-       result =  fcntl_lock(fsp->fh->fd, op, offset, count, type);
+       result =  fcntl_lock(fsp_get_io_fd(fsp), op, offset, count, type);
        END_PROFILE(syscall_fcntl_lock);
        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->fh->fd, 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,
@@ -2797,11 +3098,11 @@ static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
        case F_SET_FILE_RW_HINT:
 #endif
                argp = va_arg(dup_cmd_arg, void *);
-               result = sys_fcntl_ptr(fsp->fh->fd, cmd, argp);
+               result = sys_fcntl_ptr(fsp_get_io_fd(fsp), cmd, argp);
                break;
        default:
                val = va_arg(dup_cmd_arg, int);
-               result = sys_fcntl_int(fsp->fh->fd, cmd, val);
+               result = sys_fcntl_int(fsp_get_io_fd(fsp), cmd, val);
        }
 
        va_end(dup_cmd_arg);
@@ -2821,7 +3122,7 @@ static bool vfswrap_getlock(vfs_handle_struct *handle, files_struct *fsp, off_t
                op = map_process_lock_to_ofd_lock(op);
        }
 
-       result = fcntl_getlock(fsp->fh->fd, op, poffset, pcount, ptype, ppid);
+       result = fcntl_getlock(fsp_get_io_fd(fsp), op, poffset, pcount, ptype, ppid);
        END_PROFILE(syscall_fcntl_getlock);
        return result;
 }
@@ -2834,7 +3135,7 @@ static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
        START_PROFILE(syscall_linux_setlease);
 
 #ifdef HAVE_KERNEL_OPLOCKS_LINUX
-       result = linux_setlease(fsp->fh->fd, leasetype);
+       result = linux_setlease(fsp_get_io_fd(fsp), leasetype);
 #else
        errno = ENOSYS;
 #endif
@@ -2851,17 +3152,15 @@ static int vfswrap_symlinkat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_symlinkat);
 
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
-
        result = symlinkat(link_target->base_name,
-                       dirfsp->fh->fd,
+                       fsp_get_pathref_fd(dirfsp),
                        new_smb_fname->base_name);
        END_PROFILE(syscall_symlinkat);
        return result;
 }
 
 static int vfswrap_readlinkat(vfs_handle_struct *handle,
-                       files_struct *dirfsp,
+                       const struct files_struct *dirfsp,
                        const struct smb_filename *smb_fname,
                        char *buf,
                        size_t bufsiz)
@@ -2870,9 +3169,7 @@ static int vfswrap_readlinkat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_readlinkat);
 
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
-
-       result = readlinkat(dirfsp->fh->fd,
+       result = readlinkat(fsp_get_pathref_fd(dirfsp),
                        smb_fname->base_name,
                        buf,
                        bufsiz);
@@ -2892,12 +3189,9 @@ static int vfswrap_linkat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_linkat);
 
-       SMB_ASSERT(srcfsp == srcfsp->conn->cwd_fsp);
-       SMB_ASSERT(dstfsp == dstfsp->conn->cwd_fsp);
-
-       result = linkat(srcfsp->fh->fd,
+       result = linkat(fsp_get_pathref_fd(srcfsp),
                        old_smb_fname->base_name,
-                       dstfsp->fh->fd,
+                       fsp_get_pathref_fd(dstfsp),
                        new_smb_fname->base_name,
                        flags);
 
@@ -2915,9 +3209,7 @@ static int vfswrap_mknodat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_mknodat);
 
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
-
-       result = sys_mknodat(dirfsp->fh->fd,
+       result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
                        smb_fname->base_name,
                        mode,
                        dev);
@@ -2948,12 +3240,33 @@ static struct smb_filename *vfswrap_realpath(vfs_handle_struct *handle,
        return result_fname;
 }
 
-static int vfswrap_chflags(vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname,
+static int vfswrap_fchflags(vfs_handle_struct *handle,
+                       struct files_struct *fsp,
                        unsigned int flags)
 {
-#ifdef HAVE_CHFLAGS
-       return chflags(smb_fname->base_name, flags);
+#ifdef HAVE_FCHFLAGS
+       int fd = fsp_get_pathref_fd(fsp);
+
+       if (!fsp->fsp_flags.is_pathref) {
+               return fchflags(fd, flags);
+       }
+
+       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 chflags(p, flags);
+       }
+
+       /*
+        * This is no longer a handle based call.
+        */
+       return chflags(fsp->fsp_name->base_name, flags);
 #else
        errno = ENOSYS;
        return -1;
@@ -2981,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;
        }
@@ -2998,82 +3307,82 @@ static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle,
        return file_id;
 }
 
-static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle,
+static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
                                   struct files_struct *fsp,
-                                  const struct smb_filename *smb_fname,
                                   TALLOC_CTX *mem_ctx,
                                   unsigned int *pnum_streams,
                                   struct stream_struct **pstreams)
 {
-       SMB_STRUCT_STAT sbuf;
        struct stream_struct *tmp_streams = NULL;
-       int ret;
+       unsigned int num_streams = *pnum_streams;
+       struct stream_struct *streams = *pstreams;
+       NTSTATUS status;
 
-       if ((fsp != NULL) && (fsp->fsp_flags.is_directory)) {
+       if (fsp->fsp_flags.is_directory) {
                /*
                 * No default streams on directories
                 */
                goto done;
        }
-
-       if ((fsp != NULL) && (fsp->fh->fd != -1)) {
-               ret = SMB_VFS_FSTAT(fsp, &sbuf);
-       }
-       else {
-               struct smb_filename *smb_fname_cp = NULL;
-
-               smb_fname_cp = cp_smb_filename_nostream(talloc_tos(), smb_fname);
-               if (smb_fname_cp == NULL) {
-                       return NT_STATUS_NO_MEMORY;
-               }
-
-               if (smb_fname_cp->flags & SMB_FILENAME_POSIX_PATH) {
-                       ret = SMB_VFS_LSTAT(handle->conn, smb_fname_cp);
-               } else {
-                       ret = SMB_VFS_STAT(handle->conn, smb_fname_cp);
-               }
-               sbuf = smb_fname_cp->st;
-               TALLOC_FREE(smb_fname_cp);
-       }
-
-       if (ret == -1) {
-               return map_nt_error_from_unix(errno);
+       status = vfs_stat_fsp(fsp);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
-       if (S_ISDIR(sbuf.st_ex_mode)) {
-               goto done;
+       if (num_streams + 1 < 1) {
+               /* Integer wrap. */
+               return NT_STATUS_INVALID_PARAMETER;
        }
 
-       tmp_streams = talloc_realloc(mem_ctx, *pstreams, struct stream_struct,
-                                       (*pnum_streams) + 1);
+       tmp_streams = talloc_realloc(mem_ctx,
+                                       streams,
+                                       struct stream_struct,
+                                       num_streams + 1);
        if (tmp_streams == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
-       tmp_streams[*pnum_streams].name = talloc_strdup(tmp_streams, "::$DATA");
-       if (tmp_streams[*pnum_streams].name == NULL) {
+       tmp_streams[num_streams].name = talloc_strdup(tmp_streams, "::$DATA");
+       if (tmp_streams[num_streams].name == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
-       tmp_streams[*pnum_streams].size = sbuf.st_ex_size;
-       tmp_streams[*pnum_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(handle->conn, fsp, &sbuf);
+       tmp_streams[num_streams].size = fsp->fsp_name->st.st_ex_size;
+       tmp_streams[num_streams].alloc_size = SMB_VFS_GET_ALLOC_SIZE(
+                                               handle->conn,
+                                               fsp,
+                                               &fsp->fsp_name->st);
+       num_streams += 1;
 
-       *pnum_streams += 1;
+       *pnum_streams = num_streams;
        *pstreams = tmp_streams;
  done:
        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,
@@ -3128,28 +3437,6 @@ static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
        return result;
 }
 
-static NTSTATUS vfswrap_get_nt_acl_at(vfs_handle_struct *handle,
-                       struct files_struct *dirfsp,
-                       const struct smb_filename *smb_fname,
-                       uint32_t security_info,
-                       TALLOC_CTX *mem_ctx,
-                       struct security_descriptor **ppdesc)
-{
-       NTSTATUS result;
-
-       START_PROFILE(get_nt_acl_at);
-
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
-
-       result = posix_get_nt_acl(handle->conn,
-                               smb_fname,
-                               security_info,
-                               mem_ctx,
-                               ppdesc);
-       END_PROFILE(get_nt_acl_at);
-       return result;
-}
-
 static NTSTATUS vfswrap_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd)
 {
        NTSTATUS result;
@@ -3169,58 +3456,67 @@ static NTSTATUS vfswrap_audit_file(struct vfs_handle_struct *handle,
        return NT_STATUS_OK; /* Nothing to do here ... */
 }
 
-static SMB_ACL_T vfswrap_sys_acl_get_file(vfs_handle_struct *handle,
-                                         const struct smb_filename *smb_fname,
-                                         SMB_ACL_TYPE_T type,
-                                         TALLOC_CTX *mem_ctx)
-{
-       return sys_acl_get_file(handle, smb_fname, type, mem_ctx);
-}
-
 static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle,
                                        files_struct *fsp,
+                                       SMB_ACL_TYPE_T type,
                                        TALLOC_CTX *mem_ctx)
 {
-       return sys_acl_get_fd(handle, fsp, mem_ctx);
+       return sys_acl_get_fd(handle, fsp, type, mem_ctx);
 }
 
-static int vfswrap_sys_acl_set_file(vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
-                               SMB_ACL_TYPE_T acltype,
-                               SMB_ACL_T theacl)
+static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
+                                 files_struct *fsp,
+                                 SMB_ACL_TYPE_T type,
+                                 SMB_ACL_T theacl)
 {
-       return sys_acl_set_file(handle, smb_fname, acltype, theacl);
+       return sys_acl_set_fd(handle, fsp, type, theacl);
 }
 
-static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, SMB_ACL_T theacl)
+static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
+                                        files_struct *fsp)
 {
-       return sys_acl_set_fd(handle, fsp, theacl);
-}
-
-static int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname)
-{
-       return sys_acl_delete_def_file(handle, smb_fname);
+       return sys_acl_delete_def_fd(handle, fsp);
 }
 
 /****************************************************************
  Extended attribute operations.
 *****************************************************************/
 
-static ssize_t vfswrap_getxattr(struct vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname,
-                       const char *name,
-                       void *value,
-                       size_t size)
+static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
+                                struct files_struct *fsp,
+                                const char *name,
+                                void *value,
+                                size_t size)
 {
-       return getxattr(smb_fname->base_name, name, value, 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;
-       struct tevent_req *req;
 
        /*
         * The following variables are talloced off "state" which is protected
@@ -3271,9 +3567,9 @@ static struct tevent_req *vfswrap_getxattrat_send(
        }
        *state = (struct vfswrap_getxattrat_state) {
                .ev = ev,
+               .handle = handle,
                .dir_fsp = dir_fsp,
                .smb_fname = smb_fname,
-               .req = req,
        };
 
        max_threads = pthreadpool_tevent_max_threads(dir_fsp->conn->sconn->pool);
@@ -3293,7 +3589,7 @@ static struct tevent_req *vfswrap_getxattrat_send(
        SMBPROFILE_BYTES_ASYNC_START(syscall_asys_getxattrat, profile_p,
                                     state->profile_bytes, 0);
 
-       if (dir_fsp->fh->fd == -1) {
+       if (fsp_get_pathref_fd(dir_fsp) == -1) {
                DBG_ERR("Need a valid directory fd\n");
                tevent_req_error(req, EINVAL);
                return tevent_req_post(req, ev);
@@ -3370,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;
        }
 
@@ -3409,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);
@@ -3431,17 +3712,11 @@ static void vfswrap_getxattrat_do_async(void *private_data)
                goto end_profile;
        }
 
-       ret = fchdir(state->dir_fsp->fh->fd);
-       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;
        }
@@ -3535,49 +3810,82 @@ 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)
+static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
 {
-       return fgetxattr(fsp->fh->fd, name, value, size);
-}
+       int fd = fsp_get_pathref_fd(fsp);
 
-static ssize_t vfswrap_listxattr(struct vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname,
-                       char *list,
-                       size_t size)
-{
-       return listxattr(smb_fname->base_name, list, size);
-}
+       if (!fsp->fsp_flags.is_pathref) {
+               return flistxattr(fd, list, size);
+       }
 
-static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
-{
-       return flistxattr(fsp->fh->fd, list, size);
-}
+       if (fsp->fsp_flags.have_proc_fds) {
+               const char *p = NULL;
+               char buf[PATH_MAX];
 
-static int vfswrap_removexattr(struct vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
-                               const char *name)
-{
-       return removexattr(smb_fname->base_name, name);
+               p = sys_proc_fd_path(fd, buf, sizeof(buf));
+               if (p == NULL) {
+                       return -1;
+               }
+
+               return listxattr(p, list, size);
+       }
+
+       /*
+        * This is no longer a handle based call.
+        */
+       return listxattr(fsp->fsp_name->base_name, list, size);
 }
 
 static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name)
 {
-       return fremovexattr(fsp->fh->fd, name);
-}
+       int fd = fsp_get_pathref_fd(fsp);
 
-static int vfswrap_setxattr(struct vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
-                               const char *name,
-                               const void *value,
-                               size_t size,
-                               int flags)
-{
-       return setxattr(smb_fname->base_name, name, value, size, flags);
+       if (!fsp->fsp_flags.is_pathref) {
+               return fremovexattr(fd, name);
+       }
+
+       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 removexattr(p, name);
+       }
+
+       /*
+        * This is no longer a handle based call.
+        */
+       return removexattr(fsp->fsp_name->base_name, name);
 }
 
 static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, const char *name, const void *value, size_t size, int flags)
 {
-       return fsetxattr(fsp->fh->fd, name, value, size, flags);
+       int fd = fsp_get_pathref_fd(fsp);
+
+       if (!fsp->fsp_flags.is_pathref) {
+               return fsetxattr(fd, name, value, size, flags);
+       }
+
+       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 setxattr(p, name, value, size, flags);
+       }
+
+       /*
+        * This is no longer a handle based call.
+        */
+       return setxattr(fsp->fsp_name->base_name, name, value, size, flags);
 }
 
 static bool vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
@@ -3669,7 +3977,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
 
        .fdopendir_fn = vfswrap_fdopendir,
        .readdir_fn = vfswrap_readdir,
-       .readdir_attr_fn = vfswrap_readdir_attr,
+       .freaddir_attr_fn = vfswrap_freaddir_attr,
        .seekdir_fn = vfswrap_seekdir,
        .telldir_fn = vfswrap_telldir,
        .rewind_dir_fn = vfswrap_rewinddir,
@@ -3678,7 +3986,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
 
        /* File operations */
 
-       .open_fn = vfswrap_open,
+       .openat_fn = vfswrap_openat,
        .create_file_fn = vfswrap_create_file,
        .close_fn = vfswrap_close,
        .pread_fn = vfswrap_pread,
@@ -3696,19 +4004,19 @@ 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,
-       .chmod_fn = vfswrap_chmod,
        .fchmod_fn = vfswrap_fchmod,
        .fchown_fn = vfswrap_fchown,
        .lchown_fn = vfswrap_lchown,
        .chdir_fn = vfswrap_chdir,
        .getwd_fn = vfswrap_getwd,
-       .ntimes_fn = vfswrap_ntimes,
+       .fntimes_fn = vfswrap_fntimes,
        .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,
@@ -3717,20 +4025,20 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .linkat_fn = vfswrap_linkat,
        .mknodat_fn = vfswrap_mknodat,
        .realpath_fn = vfswrap_realpath,
-       .chflags_fn = vfswrap_chflags,
+       .fchflags_fn = vfswrap_fchflags,
        .file_id_create_fn = vfswrap_file_id_create,
        .fs_file_id_fn = vfswrap_fs_file_id,
-       .streaminfo_fn = vfswrap_streaminfo,
+       .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,
        .strict_lock_check_fn = vfswrap_strict_lock_check,
        .translate_name_fn = vfswrap_translate_name,
+       .parent_pathname_fn = vfswrap_parent_pathname,
        .fsctl_fn = vfswrap_fsctl,
-       .set_dos_attributes_fn = vfswrap_set_dos_attributes,
        .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
-       .get_dos_attributes_fn = vfswrap_get_dos_attributes,
        .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
        .get_dos_attributes_recv_fn = vfswrap_get_dos_attributes_recv,
        .fget_dos_attributes_fn = vfswrap_fget_dos_attributes,
@@ -3738,36 +4046,28 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .offload_read_recv_fn = vfswrap_offload_read_recv,
        .offload_write_send_fn = vfswrap_offload_write_send,
        .offload_write_recv_fn = vfswrap_offload_write_recv,
-       .get_compression_fn = vfswrap_get_compression,
+       .fget_compression_fn = vfswrap_fget_compression,
        .set_compression_fn = vfswrap_set_compression,
 
        /* NT ACL operations. */
 
        .fget_nt_acl_fn = vfswrap_fget_nt_acl,
-       .get_nt_acl_at_fn = vfswrap_get_nt_acl_at,
        .fset_nt_acl_fn = vfswrap_fset_nt_acl,
        .audit_file_fn = vfswrap_audit_file,
 
        /* POSIX ACL operations. */
 
-       .sys_acl_get_file_fn = vfswrap_sys_acl_get_file,
        .sys_acl_get_fd_fn = vfswrap_sys_acl_get_fd,
-       .sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
        .sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
-       .sys_acl_set_file_fn = vfswrap_sys_acl_set_file,
        .sys_acl_set_fd_fn = vfswrap_sys_acl_set_fd,
-       .sys_acl_delete_def_file_fn = vfswrap_sys_acl_delete_def_file,
+       .sys_acl_delete_def_fd_fn = vfswrap_sys_acl_delete_def_fd,
 
        /* EA operations. */
-       .getxattr_fn = vfswrap_getxattr,
        .getxattrat_send_fn = vfswrap_getxattrat_send,
        .getxattrat_recv_fn = vfswrap_getxattrat_recv,
        .fgetxattr_fn = vfswrap_fgetxattr,
-       .listxattr_fn = vfswrap_listxattr,
        .flistxattr_fn = vfswrap_flistxattr,
-       .removexattr_fn = vfswrap_removexattr,
        .fremovexattr_fn = vfswrap_fremovexattr,
-       .setxattr_fn = vfswrap_setxattr,
        .fsetxattr_fn = vfswrap_fsetxattr,
 
        /* aio operations */