smbd: Fix a typo in a few places
[samba.git] / source3 / modules / vfs_default.c
index 722a3424c3188762d0cdfa4f027bb37a7161991f..48b5dd9e39f46b178ba734651a8cf25242839358 100644 (file)
 
 static int vfswrap_connect(vfs_handle_struct *handle, const char *service, const char *user)
 {
+       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 */
 }
 
@@ -117,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);
 }
@@ -179,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;
@@ -194,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;
@@ -202,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);
        }
 
@@ -237,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 = {
@@ -256,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++) {
@@ -363,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);
        }
 
@@ -437,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;
@@ -459,7 +483,7 @@ static NTSTATUS vfswrap_read_dfs_pathat(struct vfs_handle_struct *handle,
                }
        }
 
-       referral_len = readlinkat(fsp_get_io_fd(dirfsp),
+       referral_len = readlinkat(fsp_get_pathref_fd(dirfsp),
                                smb_fname->base_name,
                                link_target,
                                bufsize - 1);
@@ -474,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;
         }
@@ -492,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;
@@ -567,67 +600,17 @@ static DIR *vfswrap_fdopendir(vfs_handle_struct *handle,
        return result;
 }
 
-
 static struct dirent *vfswrap_readdir(vfs_handle_struct *handle,
                                      struct files_struct *dirfsp,
-                                     DIR *dirp,
-                                     SMB_STRUCT_STAT *sbuf)
+                                     DIR *dirp)
 {
        struct dirent *result;
-       bool do_stat = false;
-       bool fake_ctime = lp_fake_directory_create_times(SNUM(handle->conn));
-       int flags = AT_SYMLINK_NOFOLLOW;
-       struct stat st;
-       int ret;
 
        START_PROFILE(syscall_readdir);
 
-#if defined(HAVE_DIRFD) && defined(HAVE_FSTATAT)
-       do_stat = true;
-#endif
-
        result = readdir(dirp);
        END_PROFILE(syscall_readdir);
 
-       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);
-
-       /* See if we can efficiently return this. */
-       if (!do_stat) {
-               return result;
-       }
-
-       ret = fstatat(dirfd(dirp),
-                     result->d_name,
-                     &st,
-                     flags);
-       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_mode) &&
-           !(dirfsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH))
-       {
-               return result;
-       }
-       init_stat_ex_from_stat(sbuf, &st, fake_ctime);
-
        return result;
 }
 
@@ -639,22 +622,6 @@ static NTSTATUS vfswrap_freaddir_attr(struct vfs_handle_struct *handle,
        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);
@@ -693,28 +660,79 @@ 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;
        }
 
+       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;
@@ -726,10 +744,22 @@ static int vfswrap_openat(vfs_handle_struct *handle,
                        mode);
 
        if (became_root) {
+               int err = errno;
                unbecome_root();
+               errno = err;
        }
 
-       fsp->fsp_flags.have_proc_fds = fsp->conn->have_proc_fds;
+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);
@@ -737,6 +767,7 @@ out:
 }
 static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle,
                                    struct smb_request *req,
+                                   struct files_struct *dirfsp,
                                    struct smb_filename *smb_fname,
                                    uint32_t access_mask,
                                    uint32_t share_access,
@@ -754,7 +785,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, smb_fname,
+       return create_file_default(handle->conn, req, dirfsp, smb_fname,
                                   access_mask, share_access,
                                   create_disposition, create_options,
                                   file_attributes, oplock_request, lease,
@@ -1252,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(fsp_get_pathref_fd(srcfsp),
                        smb_fname_src->base_name,
                        fsp_get_pathref_fd(dstfsp),
                        smb_fname_dst->base_name);
 
- out:
        END_PROFILE(syscall_renameat);
        return result;
 }
@@ -1274,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;
 }
@@ -1304,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,
@@ -1325,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.
  */
@@ -1345,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:
        {
@@ -1367,19 +1478,19 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
        case FSCTL_CREATE_OR_GET_OBJECT_ID:
        {
                unsigned char objid[16];
-               char *return_data = NULL;
+               uint8_t *return_data = NULL;
 
                /* This should return the object-id on this file.
                 * 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);
 
                /* Hmmm, will this cause problems if less data asked for? */
-               return_data = talloc_array(ctx, char, 64);
+               return_data = talloc_array(ctx, uint8_t, 64);
                if (return_data == NULL) {
                        return NT_STATUS_NO_MEMORY;
                }
@@ -1387,16 +1498,17 @@ static NTSTATUS vfswrap_fsctl(struct vfs_handle_struct *handle,
                /* For backwards compatibility only store the dev/inode. */
                push_file_id_16(return_data, &fsp->file_id);
                memcpy(return_data+16,create_volume_objectid(fsp->conn,objid),16);
-               push_file_id_16(return_data+32, &fsp->file_id);
+               push_file_id_16(return_data + 32, &fsp->file_id);
                memset(return_data+48, 0, 16);
-               *out_data = return_data;
+               *_out_data = return_data;
                return NT_STATUS_OK;
        }
 
        case FSCTL_GET_REPARSE_POINT:
        {
+               uint32_t tag;
                status = fsctl_get_reparse_point(
-                       fsp, ctx, out_data, max_out_len, out_len);
+                       fsp, ctx, &tag, _out_data, max_out_len, out_len);
                return status;
        }
 
@@ -1431,8 +1543,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;
                }
 
@@ -1442,7 +1554,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;
                }
 
@@ -1450,7 +1562,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;
@@ -1458,7 +1570,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: "
@@ -1479,8 +1591,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;
                }
@@ -1506,8 +1618,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;
@@ -1521,7 +1633,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]));
                        }
                }
 
@@ -1544,8 +1656,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? */
@@ -1561,13 +1673,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);
                }
 
@@ -1608,14 +1720,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;
                }
 
@@ -1636,7 +1748,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;
                }
 
@@ -1658,8 +1770,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
@@ -1674,8 +1786,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);
                }
        }
 
@@ -1709,6 +1821,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) {
@@ -1723,6 +1837,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,
@@ -1857,6 +1979,8 @@ 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;
@@ -1869,6 +1993,8 @@ 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);
 }
 
@@ -1928,6 +2054,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(
@@ -1939,6 +2067,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);
 
@@ -1959,6 +2089,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;
 };
 
@@ -1978,6 +2109,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(
@@ -2117,6 +2249,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);
@@ -2131,6 +2273,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)
@@ -2152,6 +2425,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,
@@ -2215,6 +2489,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,
@@ -2269,6 +2544,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);
@@ -2305,7 +2581,7 @@ 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);
 
@@ -2395,15 +2671,12 @@ static int vfswrap_unlinkat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_unlinkat);
 
-       if (is_named_stream(smb_fname)) {
-               errno = ENOENT;
-               goto out;
-       }
+       SMB_ASSERT(!is_named_stream(smb_fname));
+
        result = unlinkat(fsp_get_pathref_fd(dirfsp),
                        smb_fname->base_name,
                        flags);
 
- out:
        END_PROFILE(syscall_unlinkat);
        return result;
 }
@@ -2422,15 +2695,10 @@ static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t m
 
        if (fsp->fsp_flags.have_proc_fds) {
                int fd = fsp_get_pathref_fd(fsp);
-               const char *p = NULL;
-               char buf[PATH_MAX];
+               struct sys_proc_fd_path_buf buf;
+
+               result = chmod(sys_proc_fd_path(fd, &buf), mode);
 
-               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;
        }
@@ -2450,7 +2718,26 @@ static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t ui
        int result;
 
        START_PROFILE(syscall_fchown);
-       result = fchown(fsp_get_io_fd(fsp), 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
@@ -2526,7 +2813,7 @@ static int vfswrap_fntimes(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_fntimes);
 
-       if (is_named_stream(fsp->fsp_name)) {
+       if (fsp_is_alternate_stream(fsp)) {
                errno = ENOENT;
                goto out;
        }
@@ -2541,8 +2828,7 @@ static int vfswrap_fntimes(vfs_handle_struct *handle,
                }
 
                if (!is_omit_timespec(&ft->create_time)) {
-                       set_create_timespec_ea(handle->conn,
-                                              fsp->fsp_name,
+                       set_create_timespec_ea(fsp,
                                               ft->create_time);
                }
 
@@ -2568,19 +2854,12 @@ static int vfswrap_fntimes(vfs_handle_struct *handle,
 
        if (fsp->fsp_flags.have_proc_fds) {
                int fd = fsp_get_pathref_fd(fsp);
-               const char *p = NULL;
-               char buf[PATH_MAX];
+               struct sys_proc_fd_path_buf buf;
 
-               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;
-               }
+               result = utimensat(AT_FDCWD,
+                                  sys_proc_fd_path(fd, &buf),
+                                  times,
+                                  0);
 
                goto out;
        }
@@ -2651,8 +2930,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 =
@@ -2788,13 +3067,13 @@ static bool vfswrap_lock(vfs_handle_struct *handle, files_struct *fsp, int op, o
        return result;
 }
 
-static int vfswrap_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
-                               uint32_t share_access, uint32_t access_mask)
+static int vfswrap_filesystem_sharemode(vfs_handle_struct *handle,
+                                       files_struct *fsp,
+                                       uint32_t share_access,
+                                       uint32_t access_mask)
 {
-       START_PROFILE(syscall_kernel_flock);
-       kernel_flock(fsp_get_io_fd(fsp), share_access, access_mask);
-       END_PROFILE(syscall_kernel_flock);
-       return 0;
+       errno = ENOTSUP;
+       return -1;
 }
 
 static int vfswrap_fcntl(vfs_handle_struct *handle, files_struct *fsp, int cmd,
@@ -2865,6 +3144,8 @@ 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_get_io_fd(fsp), leasetype);
 #else
@@ -2883,6 +3164,8 @@ static int vfswrap_symlinkat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_symlinkat);
 
+       SMB_ASSERT(!is_named_stream(new_smb_fname));
+
        result = symlinkat(link_target->base_name,
                        fsp_get_pathref_fd(dirfsp),
                        new_smb_fname->base_name);
@@ -2900,6 +3183,8 @@ static int vfswrap_readlinkat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_readlinkat);
 
+       SMB_ASSERT(!is_named_stream(smb_fname));
+
        result = readlinkat(fsp_get_pathref_fd(dirfsp),
                        smb_fname->base_name,
                        buf,
@@ -2920,6 +3205,9 @@ static int vfswrap_linkat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_linkat);
 
+       SMB_ASSERT(!is_named_stream(old_smb_fname));
+       SMB_ASSERT(!is_named_stream(new_smb_fname));
+
        result = linkat(fsp_get_pathref_fd(srcfsp),
                        old_smb_fname->base_name,
                        fsp_get_pathref_fd(dstfsp),
@@ -2940,6 +3228,8 @@ static int vfswrap_mknodat(vfs_handle_struct *handle,
 
        START_PROFILE(syscall_mknodat);
 
+       SMB_ASSERT(!is_named_stream(smb_fname));
+
        result = sys_mknodat(fsp_get_pathref_fd(dirfsp),
                        smb_fname->base_name,
                        mode,
@@ -2971,12 +3261,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 +3311,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;
        }
@@ -3032,6 +3335,8 @@ static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
        struct stream_struct *streams = *pstreams;
        NTSTATUS status;
 
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
        if (fsp->fsp_flags.is_directory) {
                /*
                 * No default streams on directories
@@ -3072,21 +3377,22 @@ static NTSTATUS vfswrap_fstreaminfo(vfs_handle_struct *handle,
        return NT_STATUS_OK;
 }
 
-static int vfswrap_get_real_filename(struct vfs_handle_struct *handle,
-                                    const struct smb_filename *path,
-                                    const char *name,
-                                    TALLOC_CTX *mem_ctx,
-                                    char **found_name)
+static NTSTATUS vfswrap_get_real_filename_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;
@@ -3132,39 +3438,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;
@@ -3179,19 +3469,14 @@ 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));
+
+       return sys_acl_get_fd(handle, fsp, type, mem_ctx);
 }
 
 static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
@@ -3199,63 +3484,52 @@ static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle,
                                  SMB_ACL_TYPE_T type,
                                  SMB_ACL_T theacl)
 {
-       if (!fsp->fsp_flags.is_pathref &&
-           type == SMB_ACL_TYPE_ACCESS)
-       {
-               return sys_acl_set_fd(handle, fsp, theacl);
-       }
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
 
-       if (fsp->fsp_flags.have_proc_fds) {
-               int fd = fsp_get_pathref_fd(fsp);
-               struct smb_filename smb_fname;
-               const char *p = NULL;
-               char buf[PATH_MAX];
-
-               p = sys_proc_fd_path(fd, buf, sizeof(buf));
-               if (p == NULL) {
-                       return -1;
-               }
-
-               smb_fname = (struct smb_filename) {
-                       .base_name = buf,
-               };
-
-               return sys_acl_set_file(handle,
-                                       &smb_fname,
-                                       type,
-                                       theacl);
-       }
-
-       /*
-        * This is no longer a handle based call.
-        */
-       return sys_acl_set_file(handle,
-                               fsp->fsp_name,
-                               type,
-                               theacl);
+       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;
 
@@ -3301,6 +3575,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) {
@@ -3308,6 +3584,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,
        };
@@ -3351,7 +3628,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.
         */
@@ -3406,31 +3683,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;
        }
 
@@ -3467,17 +3727,11 @@ static void vfswrap_getxattrat_do_async(void *private_data)
                goto end_profile;
        }
 
-       ret = fchdir(fsp_get_pathref_fd(state->dir_fsp));
-       if (ret == -1) {
-               state->xattr_size = -1;
-               state->vfs_aio_state.error = errno;
-               goto end_profile;
-       }
-
-       state->xattr_size = getxattr(state->name,
-                                    state->xattr_name,
-                                    state->xattr_value,
-                                    talloc_array_length(state->xattr_value));
+       state->xattr_size = vfswrap_fgetxattr(state->handle,
+                                             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;
        }
@@ -3571,54 +3825,20 @@ static ssize_t vfswrap_getxattrat_recv(struct tevent_req *req,
        return xattr_size;
 }
 
-static ssize_t vfswrap_fgetxattr(struct vfs_handle_struct *handle,
-                                struct files_struct *fsp,
-                                const char *name,
-                                void *value,
-                                size_t size)
-{
-       int fd = fsp_get_pathref_fd(fsp);
-
-       if (!fsp->fsp_flags.is_pathref) {
-               return fgetxattr(fd, name, value, size);
-       }
-
-       if (fsp->fsp_flags.have_proc_fds) {
-               const char *p = NULL;
-               char buf[PATH_MAX];
-
-               p = sys_proc_fd_path(fd, buf, sizeof(buf));
-               if (p == NULL) {
-                       return -1;
-               }
-
-               return getxattr(p, name, value, size);
-       }
-
-       /*
-        * This is no longer a handle based call.
-        */
-       return getxattr(fsp->fsp_name->base_name, name, value, size);
-}
-
 static ssize_t vfswrap_flistxattr(struct vfs_handle_struct *handle, struct files_struct *fsp, char *list, size_t size)
 {
        int fd = fsp_get_pathref_fd(fsp);
 
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
        if (!fsp->fsp_flags.is_pathref) {
                return flistxattr(fd, list, size);
        }
 
        if (fsp->fsp_flags.have_proc_fds) {
-               const char *p = NULL;
-               char buf[PATH_MAX];
+               struct sys_proc_fd_path_buf buf;
 
-               p = sys_proc_fd_path(fd, buf, sizeof(buf));
-               if (p == NULL) {
-                       return -1;
-               }
-
-               return listxattr(p, list, size);
+               return listxattr(sys_proc_fd_path(fd, &buf), list, size);
        }
 
        /*
@@ -3631,20 +3851,16 @@ static int vfswrap_fremovexattr(struct vfs_handle_struct *handle, struct files_s
 {
        int fd = fsp_get_pathref_fd(fsp);
 
+       SMB_ASSERT(!fsp_is_alternate_stream(fsp));
+
        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];
+               struct sys_proc_fd_path_buf buf;
 
-               p = sys_proc_fd_path(fd, buf, sizeof(buf));
-               if (p == NULL) {
-                       return -1;
-               }
-
-               return removexattr(p, name);
+               return removexattr(sys_proc_fd_path(fd, &buf), name);
        }
 
        /*
@@ -3657,20 +3873,20 @@ static int vfswrap_fsetxattr(struct vfs_handle_struct *handle, struct files_stru
 {
        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) {
-               const char *p = NULL;
-               char buf[PATH_MAX];
-
-               p = sys_proc_fd_path(fd, buf, sizeof(buf));
-               if (p == NULL) {
-                       return -1;
-               }
+               struct sys_proc_fd_path_buf buf;
 
-               return setxattr(p, name, value, size, flags);
+               return setxattr(sys_proc_fd_path(fd, &buf),
+                               name,
+                               value,
+                               size,
+                               flags);
        }
 
        /*
@@ -3769,8 +3985,6 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .fdopendir_fn = vfswrap_fdopendir,
        .readdir_fn = vfswrap_readdir,
        .freaddir_attr_fn = vfswrap_freaddir_attr,
-       .seekdir_fn = vfswrap_seekdir,
-       .telldir_fn = vfswrap_telldir,
        .rewind_dir_fn = vfswrap_rewinddir,
        .mkdirat_fn = vfswrap_mkdirat,
        .closedir_fn = vfswrap_closedir,
@@ -3795,6 +4009,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .stat_fn = vfswrap_stat,
        .fstat_fn = vfswrap_fstat,
        .lstat_fn = vfswrap_lstat,
+       .fstatat_fn = vfswrap_fstatat,
        .get_alloc_size_fn = vfswrap_get_alloc_size,
        .unlinkat_fn = vfswrap_unlinkat,
        .fchmod_fn = vfswrap_fchmod,
@@ -3806,7 +4021,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .ftruncate_fn = vfswrap_ftruncate,
        .fallocate_fn = vfswrap_fallocate,
        .lock_fn = vfswrap_lock,
-       .kernel_flock_fn = vfswrap_kernel_flock,
+       .filesystem_sharemode_fn = vfswrap_filesystem_sharemode,
        .fcntl_fn = vfswrap_fcntl,
        .linux_setlease_fn = vfswrap_linux_setlease,
        .getlock_fn = vfswrap_getlock,
@@ -3815,16 +4030,17 @@ 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,
        .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,
        .fset_dos_attributes_fn = vfswrap_fset_dos_attributes,
        .get_dos_attributes_send_fn = vfswrap_get_dos_attributes_send,
@@ -3840,21 +4056,17 @@ static struct vfs_fn_pointers vfs_default_fns = {
        /* 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_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,