ctdb-scripts: Do not de-duplicate the interfaces list
[samba.git] / source3 / modules / vfs_default.c
index d42706a0fff41cff4f680662f81980f59a96c864..62ad5063af0f4cb2cb78a9184f72c655a723edc7 100644 (file)
 
 static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
 {
-    return 0;    /* Return >= 0 for success */
+       bool bval;
+
+       handle->conn->have_proc_fds = sys_have_proc_fds();
+#ifdef DISABLE_PROC_FDS
+       handle->conn->have_proc_fds = false;
+#endif
+
+       /*
+        * assume the kernel will support openat2(),
+        * it will be reset on the first ENOSYS.
+        *
+        * Note that libreplace will always provide openat2(),
+        * but return -1/errno = ENOSYS...
+        *
+        * The option is only there to test the fallback code.
+        */
+       bval = lp_parm_bool(SNUM(handle->conn),
+                           "vfs_default",
+                           "VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS",
+                           true);
+       if (bval) {
+               handle->conn->open_how_resolve |=
+                       VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
+       }
+#ifdef DISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
+       handle->conn->open_how_resolve &= ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
+#endif
+
+       return 0;    /* Return >= 0 for success */
 }
 
 static void vfswrap_disconnect(vfs_handle_struct *handle)
@@ -116,8 +144,8 @@ static int vfswrap_get_shadow_copy_data(struct vfs_handle_struct *handle,
 }
 
 static int vfswrap_statvfs(struct vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname,
-                               vfs_statvfs_struct *statbuf)
+                          const struct smb_filename *smb_fname,
+                          struct vfs_statvfs_struct *statbuf)
 {
        return sys_statvfs(smb_fname->base_name, statbuf);
 }
@@ -178,12 +206,12 @@ static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
                *p_ts_res = TIMESTAMP_SET_SECONDS;
 #endif
 
-               DEBUG(10,("vfswrap_fs_capabilities: timestamp "
+               DBG_DEBUG("vfswrap_fs_capabilities: timestamp "
                        "resolution of %s "
                        "available on share %s, directory %s\n",
                        *p_ts_res == TIMESTAMP_SET_MSEC ? "msec" : "sec",
                        lp_servicename(talloc_tos(), lp_sub, conn->params->service),
-                       conn->connectpath ));
+                       conn->connectpath );
        }
        TALLOC_FREE(smb_fname_cpath);
        return caps;
@@ -193,7 +221,7 @@ static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
                                          struct dfs_GetDFSReferral *r)
 {
        struct junction_map *junction = NULL;
-       int consumedcnt = 0;
+       size_t consumedcnt = 0;
        bool self_referral = false;
        char *pathnamep = NULL;
        char *local_dfs_path = NULL;
@@ -201,7 +229,7 @@ static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
        size_t i;
        uint16_t max_referral_level = r->in.req.max_referral_level;
 
-       if (DEBUGLVL(10)) {
+       if (DEBUGLVL(DBGLVL_DEBUG)) {
                NDR_PRINT_IN_DEBUG(dfs_GetDFSReferral, r);
        }
 
@@ -236,7 +264,6 @@ static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
                                   pathnamep,
                                   handle->conn->sconn->remote_address,
                                   handle->conn->sconn->local_address,
-                                  !handle->conn->sconn->using_smb2,
                                   junction, &consumedcnt, &self_referral);
        if (!NT_STATUS_IS_OK(status)) {
                struct smb_filename connectpath_fname = {
@@ -255,7 +282,7 @@ static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
        if (!self_referral) {
                pathnamep[consumedcnt] = '\0';
 
-               if (DEBUGLVL(3)) {
+               if (DEBUGLVL(DBGLVL_INFO)) {
                        dbgtext("Path %s to alternate path(s):",
                                pathnamep);
                        for (i=0; i < junction->referral_count; i++) {
@@ -362,12 +389,12 @@ static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle,
                }
                break;
        default:
-               DEBUG(0,("Invalid dfs referral version: %d\n",
-                       max_referral_level));
+               DBG_ERR("Invalid dfs referral version: %d\n",
+                       max_referral_level);
                return NT_STATUS_INVALID_LEVEL;
        }
 
-       if (DEBUGLVL(10)) {
+       if (DEBUGLVL(DBGLVL_DEBUG)) {
                NDR_PRINT_OUT_DEBUG(dfs_GetDFSReferral, r);
        }
 
@@ -385,8 +412,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,
@@ -396,7 +421,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;
@@ -438,8 +463,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;
@@ -460,7 +483,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);
@@ -475,10 +498,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;
         }
@@ -493,9 +523,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;
@@ -563,78 +595,33 @@ 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)
 {
        struct dirent *result;
 
        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
-       }
+
        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;
 }
 
-static void vfswrap_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
-{
-       START_PROFILE(syscall_seekdir);
-       seekdir(dirp, offset);
-       END_PROFILE(syscall_seekdir);
-}
-
-static long vfswrap_telldir(vfs_handle_struct *handle, DIR *dirp)
-{
-       long result;
-       START_PROFILE(syscall_telldir);
-       result = telldir(dirp);
-       END_PROFILE(syscall_telldir);
-       return result;
-}
-
 static void vfswrap_rewinddir(vfs_handle_struct *handle, DIR *dirp)
 {
        START_PROFILE(syscall_rewinddir);
@@ -648,26 +635,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;
@@ -689,20 +660,106 @@ 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)
+                         const struct vfs_open_how *how)
 {
+       int flags = how->flags;
+       mode_t mode = how->mode;
+       bool have_opath = false;
+       bool became_root = false;
        int result;
 
        START_PROFILE(syscall_openat);
 
-       if (is_named_stream(smb_fname)) {
-               errno = ENOENT;
+       if (how->resolve & ~(VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS |
+                            VFS_OPEN_HOW_WITH_BACKUP_INTENT)) {
+               errno = ENOSYS;
                result = -1;
                goto out;
        }
 
-       result = openat(dirfsp->fh->fd, smb_fname->base_name, flags, mode);
+       SMB_ASSERT(!is_named_stream(smb_fname));
+
+#ifdef O_PATH
+       have_opath = true;
+       if (fsp->fsp_flags.is_pathref) {
+               flags |= O_PATH;
+       }
+       if (flags & O_PATH) {
+               /*
+                * From "man 2 openat":
+                *
+                *   When O_PATH is specified in flags, flag bits other than
+                *   O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored.
+                *
+                * From "man 2 openat2":
+                *
+                *   Whereas  openat(2)  ignores  unknown  bits  in  its  flags
+                *   argument, openat2() returns an error if unknown or
+                *   conflicting flags are specified in how.flags.
+                *
+                * So we better clear ignored/invalid flags
+                * and only keep the expected ones.
+                */
+               flags &= (O_PATH|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
+       }
+#endif
+
+       if (how->resolve & VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS) {
+               struct open_how linux_how = {
+                       .flags = flags,
+                       .mode = mode,
+                       .resolve = RESOLVE_NO_SYMLINKS,
+               };
+
+               result = openat2(fsp_get_pathref_fd(dirfsp),
+                                smb_fname->base_name,
+                                &linux_how,
+                                sizeof(linux_how));
+               if (result == -1) {
+                       if (errno == ENOSYS) {
+                               /*
+                                * The kernel doesn't support
+                                * openat2(), so indicate to
+                                * the callers that
+                                * VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS
+                                * would just be a waste of time.
+                                */
+                               fsp->conn->open_how_resolve &=
+                                       ~VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS;
+                       }
+                       goto out;
+               }
+
+               goto done;
+       }
+
+       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) {
+               int err = errno;
+               unbecome_root();
+               errno = err;
+       }
+
+done:
+       if (result >= 0) {
+               fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
+       } else {
+               /*
+                * "/proc/self/fd/-1" never exists. Indicate to upper
+                * layers that for this fsp a possible name-based
+                * fallback is the only way to go.
+                */
+               fsp->fsp_flags.have_proc_fds = false;
+       }
 
 out:
        END_PROFILE(syscall_openat);
@@ -710,7 +767,7 @@ out:
 }
 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
                                    struct smb_request *req,
-                                   struct files_struct **dirfsp,
+                                   struct files_struct *dirfsp,
                                    struct smb_filename *smb_fname,
                                    uint32_t access_mask,
                                    uint32_t share_access,
@@ -754,13 +811,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 */
@@ -778,12 +835,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 */
@@ -825,7 +882,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;
@@ -953,7 +1010,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;
@@ -1076,7 +1133,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);
@@ -1174,7 +1231,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
@@ -1197,7 +1254,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;
 }
@@ -1211,7 +1268,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;
 }
@@ -1226,17 +1283,14 @@ static int vfswrap_renameat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_renameat);
 
-       if (is_named_stream(smb_fname_src) || is_named_stream(smb_fname_dst)) {
-               errno = ENOENT;
-               goto out;
-       }
+       SMB_ASSERT(!is_named_stream(smb_fname_src));
+       SMB_ASSERT(!is_named_stream(smb_fname_dst));
 
-       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:
        END_PROFILE(syscall_renameat);
        return result;
 }
@@ -1248,14 +1302,11 @@ static int vfswrap_stat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_stat);
 
-       if (is_named_stream(smb_fname)) {
-               errno = ENOENT;
-               goto out;
-       }
+       SMB_ASSERT(!is_named_stream(smb_fname));
 
        result = sys_stat(smb_fname->base_name, &smb_fname->st,
                          lp_fake_directory_create_times(SNUM(handle->conn)));
- out:
+
        END_PROFILE(syscall_stat);
        return result;
 }
@@ -1265,7 +1316,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;
@@ -1278,18 +1329,39 @@ static int vfswrap_lstat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_lstat);
 
-       if (is_named_stream(smb_fname)) {
-               errno = ENOENT;
-               goto out;
-       }
+       SMB_ASSERT(!is_named_stream(smb_fname));
 
        result = sys_lstat(smb_fname->base_name, &smb_fname->st,
                           lp_fake_directory_create_times(SNUM(handle->conn)));
- out:
+
        END_PROFILE(syscall_lstat);
        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);
+
+       SMB_ASSERT(!is_named_stream(smb_fname));
+
+       result = sys_fstatat(
+               fsp_get_pathref_fd(dirfsp),
+               smb_fname->base_name,
+               sbuf,
+               flags,
+               lp_fake_directory_create_times(SNUM(handle->conn)));
+
+       END_PROFILE(syscall_fstatat);
+       return result;
+}
+
 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
                                       const char *name,
                                       enum vfs_translate_direction direction,
@@ -1299,6 +1371,63 @@ 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)
+{
+       struct smb_filename *parent = NULL;
+       struct smb_filename *name = NULL;
+       char *p = NULL;
+
+       parent = cp_smb_filename_nostream(mem_ctx, smb_fname_in);
+       if (parent == NULL) {
+               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(parent);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               p = smb_fname_in->base_name;
+       } else {
+               *p = '\0';
+               p++;
+       }
+
+       if (atname_out == NULL) {
+               *parent_dir_out = parent;
+               return NT_STATUS_OK;
+       }
+
+       name = synthetic_smb_fname(
+               parent,
+               p,
+               smb_fname_in->stream_name,
+               &smb_fname_in->st,
+               smb_fname_in->twrp,
+               smb_fname_in->flags);
+       if (name == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       *parent_dir_out = parent;
+       *atname_out = name;
+       return NT_STATUS_OK;
+}
+
 /*
  * Implement the default fsctl operation.
  */
@@ -1319,6 +1448,14 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
        char **out_data = (char **)_out_data;
        NTSTATUS status;
 
+       /*
+        * Currently all fsctls operate on the base
+        * file if given an alternate data stream.
+        * Revisit this if we implement fsctls later
+        * that need access to the ADS handle.
+        */
+       fsp = metadata_fsp(fsp);
+
        switch (function) {
        case FSCTL_SET_SPARSE:
        {
@@ -1347,8 +1484,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                 * I think I'll make this be the inode+dev. JRA.
                 */
 
-               DEBUG(10,("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
-                         fsp_fnum_dbg(fsp)));
+               DBG_DEBUG("FSCTL_CREATE_OR_GET_OBJECT_ID: called on %s\n",
+                         fsp_fnum_dbg(fsp));
 
                *out_len = MIN(max_out_len, 64);
 
@@ -1405,8 +1542,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                char *cur_pdata = NULL;
 
                if (max_out_len < 16) {
-                       DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
-                               max_out_len));
+                       DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) < 16 is invalid!\n",
+                               max_out_len);
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
@@ -1416,7 +1553,7 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
 
                shadow_data = talloc_zero(ctx, struct shadow_copy_data);
                if (shadow_data == NULL) {
-                       DEBUG(0,("TALLOC_ZERO() failed!\n"));
+                       DBG_ERR("TALLOC_ZERO() failed!\n");
                        return NT_STATUS_NO_MEMORY;
                }
 
@@ -1424,7 +1561,7 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                 * Call the VFS routine to actually do the work.
                 */
                if (SMB_VFS_GET_SHADOW_COPY_DATA(fsp, shadow_data, labels)!=0) {
-                       int log_lev = 0;
+                       int log_lev = DBGLVL_ERR;
                        if (errno == 0) {
                                /* broken module didn't set errno on error */
                                status = NT_STATUS_UNSUCCESSFUL;
@@ -1432,7 +1569,7 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                                status = map_nt_error_from_unix(errno);
                                if (NT_STATUS_EQUAL(status,
                                                    NT_STATUS_NOT_SUPPORTED)) {
-                                       log_lev = 5;
+                                       log_lev = DBGLVL_INFO;
                                }
                        }
                        DEBUG(log_lev, ("FSCTL_GET_SHADOW_COPY_DATA: "
@@ -1453,8 +1590,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                }
 
                if (max_out_len < *out_len) {
-                       DEBUG(0,("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
-                               max_out_len, *out_len));
+                       DBG_ERR("FSCTL_GET_SHADOW_COPY_DATA: max_data_count(%u) too small (%u) bytes needed!\n",
+                               max_out_len, *out_len);
                        TALLOC_FREE(shadow_data);
                        return NT_STATUS_BUFFER_TOO_SMALL;
                }
@@ -1480,8 +1617,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
 
                cur_pdata += 12;
 
-               DEBUG(10,("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
-                         shadow_data->num_volumes, fsp_str_dbg(fsp)));
+               DBG_DEBUG("FSCTL_GET_SHADOW_COPY_DATA: %u volumes for path[%s].\n",
+                         shadow_data->num_volumes, fsp_str_dbg(fsp));
                if (labels && shadow_data->labels) {
                        for (i=0; i<shadow_data->num_volumes; i++) {
                                size_t len = 0;
@@ -1495,7 +1632,7 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                                        return status;
                                }
                                cur_pdata += 2 * sizeof(SHADOW_COPY_LABEL);
-                               DEBUGADD(10,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
+                               DEBUGADD(DBGLVL_DEBUG,("Label[%u]: '%s'\n",i,shadow_data->labels[i]));
                        }
                }
 
@@ -1518,8 +1655,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                uid_t uid;
                size_t sid_len;
 
-               DEBUG(10, ("FSCTL_FIND_FILES_BY_SID: called on %s\n",
-                          fsp_fnum_dbg(fsp)));
+               DBG_DEBUG("FSCTL_FIND_FILES_BY_SID: called on %s\n",
+                          fsp_fnum_dbg(fsp));
 
                if (in_len < 8) {
                        /* NT_STATUS_BUFFER_TOO_SMALL maybe? */
@@ -1535,13 +1672,13 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                if (ret == -1) {
                        return NT_STATUS_INVALID_PARAMETER;
                }
-               DEBUGADD(10, ("for SID: %s\n",
+               DEBUGADD(DBGLVL_DEBUG, ("for SID: %s\n",
                              dom_sid_str_buf(&sid, &buf)));
 
                if (!sid_to_uid(&sid, &uid)) {
-                       DEBUG(0,("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
+                       DBG_ERR("sid_to_uid: failed, sid[%s] sid_len[%lu]\n",
                                 dom_sid_str_buf(&sid, &buf),
-                                (unsigned long)sid_len));
+                                (unsigned long)sid_len);
                        uid = (-1);
                }
 
@@ -1582,14 +1719,14 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                char *out_data_tmp = NULL;
 
                if (in_len != 16) {
-                       DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
-                               in_len));
+                       DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: data_count(%u) != 16 is invalid!\n",
+                               in_len);
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
                if (max_out_len < 16) {
-                       DEBUG(0,("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
-                               max_out_len));
+                       DBG_ERR("FSCTL_QUERY_ALLOCATED_RANGES: max_out_len (%u) < 16 is invalid!\n",
+                               max_out_len);
                        return NT_STATUS_INVALID_PARAMETER;
                }
 
@@ -1610,7 +1747,7 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                *out_len = 16;
                out_data_tmp = talloc_array(ctx, char, *out_len);
                if (out_data_tmp == NULL) {
-                       DEBUG(10, ("unable to allocate memory for response\n"));
+                       DBG_DEBUG("unable to allocate memory for response\n");
                        return NT_STATUS_NO_MEMORY;
                }
 
@@ -1632,8 +1769,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
 
        case FSCTL_IS_VOLUME_DIRTY:
        {
-               DEBUG(10,("FSCTL_IS_VOLUME_DIRTY: called on %s "
-                         "(but remotely not supported)\n", fsp_fnum_dbg(fsp)));
+               DBG_DEBUG("FSCTL_IS_VOLUME_DIRTY: called on %s "
+                         "(but remotely not supported)\n", fsp_fnum_dbg(fsp));
                /*
                 * http://msdn.microsoft.com/en-us/library/cc232128%28PROT.10%29.aspx
                 * says we have to respond with NT_STATUS_INVALID_PARAMETER
@@ -1648,8 +1785,8 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                 */
                if (!vfswrap_logged_ioctl_message) {
                        vfswrap_logged_ioctl_message = true;
-                       DEBUG(2, ("%s (0x%x): Currently not implemented.\n",
-                       __func__, function));
+                       DBG_NOTICE("%s (0x%x): Currently not implemented.\n",
+                       __func__, function);
                }
        }
 
@@ -1659,20 +1796,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;
@@ -1697,6 +1820,8 @@ static struct tevent_req *vfswrap_get_dos_attributes_send(
        struct tevent_req *subreq = NULL;
        struct vfswrap_get_dos_attributes_state *state = NULL;
 
+       SMB_ASSERT(!is_named_stream(smb_fname));
+
        req = tevent_req_create(mem_ctx, &state,
                                struct vfswrap_get_dos_attributes_state);
        if (req == NULL) {
@@ -1711,6 +1836,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,
@@ -1845,25 +1978,22 @@ static NTSTATUS vfswrap_fget_dos_attributes(struct vfs_handle_struct *handle,
 {
        bool offline;
 
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
        offline = vfswrap_is_offline(handle->conn, fsp->fsp_name);
        if (offline) {
                *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,
                                            struct files_struct *fsp,
                                            uint32_t dosmode)
 {
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
        return set_ea_dos_attribute(handle->conn, fsp->fsp_name, dosmode);
 }
 
@@ -1923,6 +2053,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(
@@ -1934,6 +2066,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);
 
@@ -1954,6 +2088,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;
 };
 
@@ -1973,6 +2108,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(
@@ -2112,6 +2248,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);
@@ -2126,6 +2272,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)
@@ -2147,6 +2424,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,
@@ -2210,6 +2488,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,
@@ -2264,6 +2543,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);
@@ -2300,17 +2580,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;
@@ -2391,44 +2670,42 @@ static int vfswrap_unlinkat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_unlinkat);
 
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
+       SMB_ASSERT(!is_named_stream(smb_fname));
 
-       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);
 
- out:
        END_PROFILE(syscall_unlinkat);
        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);
+               struct sys_proc_fd_path_buf buf;
+
+               result = chmod(sys_proc_fd_path(fd, &buf), mode);
+
+               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;
@@ -2440,7 +2717,26 @@ 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);
+               struct sys_proc_fd_path_buf buf;
+
+               result = chown(sys_proc_fd_path(fd, &buf), uid, gid);
+
+               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
@@ -2506,89 +2802,80 @@ 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);
-       }
-       if (!((result == -1) && (errno == ENOSYS))) {
-               goto out;
+               times = NULL;
        }
-#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);
+               struct sys_proc_fd_path_buf buf;
+
+               result = utimensat(AT_FDCWD,
+                                  sys_proc_fd_path(fd, &buf),
+                                  times,
+                                  0);
+
                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.
@@ -2626,7 +2913,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;
 
@@ -2642,8 +2929,8 @@ static int strict_allocate_ftruncate(vfs_handle_struct *handle, files_struct *fs
        if (ret == 0) {
                return 0;
        }
-       DEBUG(10,("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
-               "error %d. Falling back to slow manual allocation\n", errno));
+       DBG_DEBUG("strict_allocate_ftruncate: SMB_VFS_FALLOCATE failed with "
+               "error %d. Falling back to slow manual allocation\n", errno);
 
        /* available disk space is enough or not? */
        space_avail =
@@ -2685,7 +2972,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
@@ -2746,7 +3033,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()
@@ -2758,7 +3045,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;
@@ -2774,18 +3061,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,
@@ -2820,11 +3107,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);
@@ -2844,7 +3131,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;
 }
@@ -2856,8 +3143,10 @@ static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp,
 
        START_PROFILE(syscall_linux_setlease);
 
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
 #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
@@ -2874,17 +3163,17 @@ static int vfswrap_symlinkat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_symlinkat);
 
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
+       SMB_ASSERT(!is_named_stream(new_smb_fname));
 
        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)
@@ -2893,9 +3182,9 @@ static int vfswrap_readlinkat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_readlinkat);
 
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
+       SMB_ASSERT(!is_named_stream(smb_fname));
 
-       result = readlinkat(dirfsp->fh->fd,
+       result = readlinkat(fsp_get_pathref_fd(dirfsp),
                        smb_fname->base_name,
                        buf,
                        bufsiz);
@@ -2915,12 +3204,12 @@ 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);
+       SMB_ASSERT(!is_named_stream(old_smb_fname));
+       SMB_ASSERT(!is_named_stream(new_smb_fname));
 
-       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);
 
@@ -2938,9 +3227,9 @@ static int vfswrap_mknodat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_mknodat);
 
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
+       SMB_ASSERT(!is_named_stream(smb_fname));
 
-       result = sys_mknodat(dirfsp->fh->fd,
+       result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
                        smb_fname->base_name,
                        mode,
                        dev);
@@ -2971,12 +3260,29 @@ 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);
+
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
+       if (!fsp->fsp_flags.is_pathref) {
+               return fchflags(fd, flags);
+       }
+
+       if (fsp->fsp_flags.have_proc_fds) {
+               struct sys_proc_fd_path_buf buf;
+
+               return chflags(sys_proc_fd_path(fd, &buf), flags);
+       }
+
+       /*
+        * This is no longer a handle based call.
+        */
+       return chflags(fsp->fsp_name->base_name, flags);
 #else
        errno = ENOSYS;
        return -1;
@@ -3004,10 +3310,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;
        }
@@ -3021,85 +3323,75 @@ 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;
+
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
 
-       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_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.
         */
-       errno = EOPNOTSUPP;
-       return -1;
+       return NT_STATUS_NOT_SUPPORTED;
 }
 
 static const char *vfswrap_connectpath(struct vfs_handle_struct *handle,
+                                  const struct files_struct *dirfsp,
                                   const struct smb_filename *smb_fname)
 {
        return handle->conn->connectpath;
@@ -3145,39 +3437,23 @@ static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
        NTSTATUS result;
 
        START_PROFILE(fget_nt_acl);
+
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
        result = posix_fget_nt_acl(fsp, security_info,
                                   mem_ctx, ppdesc);
        END_PROFILE(fget_nt_acl);
        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;
 
        START_PROFILE(fset_nt_acl);
+
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
        result = set_nt_acl(fsp, security_info_sent, psd);
        END_PROFILE(fset_nt_acl);
        return result;
@@ -3192,55 +3468,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);
-}
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
 
-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)
-{
-       return sys_acl_set_file(handle, smb_fname, acltype, theacl);
+       return sys_acl_get_fd(handle, fsp, type, mem_ctx);
 }
 
-static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, 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_fd(handle, fsp, theacl);
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
+       return sys_acl_set_fd(handle, fsp, type, theacl);
 }
 
-static int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname)
+static int vfswrap_sys_acl_delete_def_fd(vfs_handle_struct *handle,
+                                        files_struct *fsp)
 {
-       return sys_acl_delete_def_file(handle, smb_fname);
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
+       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);
+
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
+       if (!fsp->fsp_flags.is_pathref) {
+               return fgetxattr(fd, name, value, size);
+       }
+
+       if (fsp->fsp_flags.have_proc_fds) {
+               struct sys_proc_fd_path_buf buf;
+
+               return getxattr(sys_proc_fd_path(fd, &buf), 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;
 
@@ -3286,6 +3574,8 @@ static struct tevent_req *vfswrap_getxattrat_send(
        bool have_per_thread_creds = false;
        bool do_async = false;
 
+       SMB_ASSERT(!is_named_stream(smb_fname));
+
        req = tevent_req_create(mem_ctx, &state,
                                struct vfswrap_getxattrat_state);
        if (req == NULL) {
@@ -3293,6 +3583,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,
        };
@@ -3314,7 +3605,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);
@@ -3336,7 +3627,7 @@ static struct tevent_req *vfswrap_getxattrat_send(
 
        /*
         * Now allocate all parameters from a memory context that won't go away
-        * no matter what. These paremeters will get used in threads and we
+        * no matter what. These parameters will get used in threads and we
         * can't reliably cancel threads, so all buffers passed to the threads
         * must not be freed before all referencing threads terminate.
         */
@@ -3391,31 +3682,14 @@ 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;
 
-       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,
+                                             state->smb_fname->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;
        }
 
@@ -3452,17 +3726,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,
+                                             state->smb_fname->fsp,
+                                             state->xattr_name,
+                                             state->xattr_value,
+                                             talloc_array_length(state->xattr_value));
        if (state->xattr_size == -1) {
                state->vfs_aio_state.error = errno;
        }
@@ -3556,53 +3824,74 @@ 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);
-}
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
 
-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.is_pathref) {
+               return flistxattr(fd, list, size);
+       }
 
-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);
+       if (fsp->fsp_flags.have_proc_fds) {
+               struct sys_proc_fd_path_buf buf;
+
+               return listxattr(sys_proc_fd_path(fd, &buf), 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);
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
+       if (!fsp->fsp_flags.is_pathref) {
+               return fremovexattr(fd, name);
+       }
+
+       if (fsp->fsp_flags.have_proc_fds) {
+               struct sys_proc_fd_path_buf buf;
+
+               return removexattr(sys_proc_fd_path(fd, &buf), 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);
+
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
+       if (!fsp->fsp_flags.is_pathref) {
+               return fsetxattr(fd, name, value, size, flags);
+       }
+
+       if (fsp->fsp_flags.have_proc_fds) {
+               struct sys_proc_fd_path_buf buf;
+
+               return setxattr(sys_proc_fd_path(fd, &buf),
+                               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)
@@ -3694,9 +3983,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
 
        .fdopendir_fn = vfswrap_fdopendir,
        .readdir_fn = vfswrap_readdir,
-       .readdir_attr_fn = vfswrap_readdir_attr,
-       .seekdir_fn = vfswrap_seekdir,
-       .telldir_fn = vfswrap_telldir,
+       .freaddir_attr_fn = vfswrap_freaddir_attr,
        .rewind_dir_fn = vfswrap_rewinddir,
        .mkdirat_fn = vfswrap_mkdirat,
        .closedir_fn = vfswrap_closedir,
@@ -3721,19 +4008,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,
@@ -3742,20 +4029,19 @@ 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,
-       .get_real_filename_fn = vfswrap_get_real_filename,
+       .fstreaminfo_fn = vfswrap_fstreaminfo,
+       .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,
@@ -3763,36 +4049,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 */