smbd: Fix a typo in a few places
[samba.git] / source3 / modules / vfs_streams_depot.c
index c51bdac0058aeea23b7cf71e28549ff67c60ec76..1221b2c2be220d2c28c92d5b9aa9c8dd9dee7104 100644 (file)
@@ -20,6 +20,7 @@
 #include "includes.h"
 #include "smbd/smbd.h"
 #include "system/filesys.h"
+#include "source3/smbd/dir.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
@@ -71,15 +72,37 @@ static bool file_is_valid(vfs_handle_struct *handle,
                        const struct smb_filename *smb_fname)
 {
        char buf;
+       NTSTATUS status;
+       struct smb_filename *pathref = NULL;
+       int ret;
 
        DEBUG(10, ("file_is_valid (%s) called\n", smb_fname->base_name));
 
-       if (SMB_VFS_GETXATTR(handle->conn, smb_fname, SAMBA_XATTR_MARKER,
-                                 &buf, sizeof(buf)) != sizeof(buf)) {
-               DEBUG(10, ("GETXATTR failed: %s\n", strerror(errno)));
+       status = synthetic_pathref(talloc_tos(),
+                               handle->conn->cwd_fsp,
+                                smb_fname->base_name,
+                                NULL,
+                                NULL,
+                                smb_fname->twrp,
+                                smb_fname->flags,
+                                &pathref);
+       if (!NT_STATUS_IS_OK(status)) {
+               return false;
+       }
+       ret = SMB_VFS_FGETXATTR(pathref->fsp,
+                               SAMBA_XATTR_MARKER,
+                               &buf,
+                               sizeof(buf));
+       if (ret != sizeof(buf)) {
+               int saved_errno = errno;
+               DBG_DEBUG("FGETXATTR failed: %s\n", strerror(saved_errno));
+               TALLOC_FREE(pathref);
+               errno = saved_errno;
                return false;
        }
 
+       TALLOC_FREE(pathref);
+
        if (buf != '1') {
                DEBUG(10, ("got wrong buffer content: '%c'\n", buf));
                return false;
@@ -88,23 +111,37 @@ static bool file_is_valid(vfs_handle_struct *handle,
        return true;
 }
 
-static bool mark_file_valid(vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname)
-{
-       char buf = '1';
-       int ret;
-
-       DEBUG(10, ("marking file %s as valid\n", smb_fname->base_name));
+/*
+ * Return the root of the stream directory. Can be
+ * external to the share definition but by default
+ * is "handle->conn->connectpath/.streams".
+ *
+ * Note that this is an *absolute* path, starting
+ * with '/', so the dirfsp being used in the
+ * calls below isn't looked at.
+ */
 
-       ret = SMB_VFS_SETXATTR(handle->conn, smb_fname, SAMBA_XATTR_MARKER,
-                                   &buf, sizeof(buf), 0);
+static char *stream_rootdir(vfs_handle_struct *handle,
+                           TALLOC_CTX *ctx)
+{
+       const struct loadparm_substitution *lp_sub =
+               loadparm_s3_global_substitution();
+       char *tmp;
 
-       if (ret == -1) {
-               DEBUG(10, ("SETXATTR failed: %s\n", strerror(errno)));
-               return false;
+       tmp = talloc_asprintf(ctx,
+                             "%s/.streams",
+                             handle->conn->connectpath);
+       if (tmp == NULL) {
+               errno = ENOMEM;
+               return NULL;
        }
 
-       return true;
+       return lp_parm_substituted_string(ctx,
+                                         lp_sub,
+                                         SNUM(handle->conn),
+                                         "streams_depot",
+                                         "directory",
+                                         tmp);
 }
 
 /**
@@ -119,8 +156,8 @@ static char *stream_dir(vfs_handle_struct *handle,
        struct smb_filename *smb_fname_hash = NULL;
        char *result = NULL;
        SMB_STRUCT_STAT base_sbuf_tmp;
+       char *tmp = NULL;
        uint8_t first, second;
-       char *tmp;
        char *id_hex;
        struct file_id id;
        uint8_t id_buf[16];
@@ -133,17 +170,8 @@ static char *stream_dir(vfs_handle_struct *handle,
        check_valid = lp_parm_bool(SNUM(handle->conn),
                      "streams_depot", "check_valid", true);
 
-       tmp = talloc_asprintf(talloc_tos(), "%s/.streams",
-               handle->conn->connectpath);
-
-       if (tmp == NULL) {
-               errno = ENOMEM;
-               goto fail;
-       }
-
-       rootdir = lp_parm_talloc_string(talloc_tos(),
-               SNUM(handle->conn), "streams_depot", "directory",
-               tmp);
+       rootdir = stream_rootdir(handle,
+                                talloc_tos());
        if (rootdir == NULL) {
                errno = ENOMEM;
                goto fail;
@@ -153,6 +181,7 @@ static char *stream_dir(vfs_handle_struct *handle,
                                        rootdir,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (rootdir_fname == NULL) {
                errno = ENOMEM;
@@ -168,6 +197,7 @@ static char *stream_dir(vfs_handle_struct *handle,
                                        smb_fname->base_name,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
                if (smb_fname_base == NULL) {
                        errno = ENOMEM;
@@ -185,7 +215,7 @@ static char *stream_dir(vfs_handle_struct *handle,
 
        id = SMB_VFS_FILE_ID_CREATE(handle->conn, &base_sbuf_tmp);
 
-       push_file_id_16((char *)id_buf, &id);
+       push_file_id_16(id_buf, &id);
 
        hash = hash_fn(data_blob_const(id_buf, sizeof(id_buf)));
 
@@ -213,6 +243,7 @@ static char *stream_dir(vfs_handle_struct *handle,
                                        result,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (smb_fname_hash == NULL) {
                errno = ENOMEM;
@@ -250,7 +281,10 @@ static char *stream_dir(vfs_handle_struct *handle,
                              smb_fname_hash->base_name));
                        recursive_rmdir(talloc_tos(), handle->conn,
                                        smb_fname_hash);
-                       SMB_VFS_NEXT_RMDIR(handle, smb_fname_hash);
+                       SMB_VFS_NEXT_UNLINKAT(handle,
+                                       handle->conn->cwd_fsp,
+                                       smb_fname_hash,
+                                       AT_REMOVEDIR);
                } else {
                        newname = talloc_asprintf(talloc_tos(), "lost-%lu",
                                                  random());
@@ -268,6 +302,7 @@ static char *stream_dir(vfs_handle_struct *handle,
                                                newname,
                                                NULL,
                                                NULL,
+                                               smb_fname->twrp,
                                                smb_fname->flags);
                        TALLOC_FREE(newname);
                        if (smb_fname_new == NULL) {
@@ -314,6 +349,7 @@ static char *stream_dir(vfs_handle_struct *handle,
                                        tmp,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (tmp_fname == NULL) {
                errno = ENOMEM;
@@ -342,6 +378,7 @@ static char *stream_dir(vfs_handle_struct *handle,
                                        tmp,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (tmp_fname == NULL) {
                errno = ENOMEM;
@@ -368,10 +405,6 @@ static char *stream_dir(vfs_handle_struct *handle,
                goto fail;
        }
 
-       if (check_valid && !mark_file_valid(handle, smb_fname)) {
-               goto fail;
-       }
-
        TALLOC_FREE(rootdir_fname);
        TALLOC_FREE(rootdir);
        TALLOC_FREE(tmp_fname);
@@ -391,6 +424,7 @@ static char *stream_dir(vfs_handle_struct *handle,
  * stream.
  */
 static NTSTATUS stream_smb_fname(vfs_handle_struct *handle,
+                                const struct stat_ex *base_sbuf,
                                 const struct smb_filename *smb_fname,
                                 struct smb_filename **smb_fname_out,
                                 bool create_dir)
@@ -409,7 +443,7 @@ static NTSTATUS stream_smb_fname(vfs_handle_struct *handle,
                }
        }
 
-       dirname = stream_dir(handle, smb_fname, NULL, create_dir);
+       dirname = stream_dir(handle, smb_fname, base_sbuf, create_dir);
 
        if (dirname == NULL) {
                status = map_nt_error_from_unix(errno);
@@ -433,7 +467,7 @@ static NTSTATUS stream_smb_fname(vfs_handle_struct *handle,
                        goto fail;
                }
        } else {
-               /* Normalize the stream type to upercase. */
+               /* Normalize the stream type to uppercase. */
                if (!strupper_m(strrchr_m(stream_fname, ':') + 1)) {
                        status = NT_STATUS_INVALID_PARAMETER;
                        goto fail;
@@ -447,6 +481,7 @@ static NTSTATUS stream_smb_fname(vfs_handle_struct *handle,
                                        stream_fname,
                                        NULL,
                                        NULL,
+                                       smb_fname->twrp,
                                        smb_fname->flags);
        if (*smb_fname_out == NULL) {
                return NT_STATUS_NO_MEMORY;
@@ -463,16 +498,19 @@ static NTSTATUS stream_smb_fname(vfs_handle_struct *handle,
 static NTSTATUS walk_streams(vfs_handle_struct *handle,
                             struct smb_filename *smb_fname_base,
                             char **pdirname,
-                            bool (*fn)(const char *dirname,
+                            bool (*fn)(const struct smb_filename *dirname,
                                        const char *dirent,
                                        void *private_data),
                             void *private_data)
 {
        char *dirname;
+       char *rootdir = NULL;
+       char *orig_connectpath = NULL;
        struct smb_filename *dir_smb_fname = NULL;
-       DIR *dirhandle = NULL;
-       const char *dirent = NULL;
+       struct smb_Dir *dir_hnd = NULL;
+       const char *dname = NULL;
        char *talloced = NULL;
+       NTSTATUS status;
 
        dirname = stream_dir(handle, smb_fname_base, &smb_fname_base->st,
                             false);
@@ -493,39 +531,59 @@ static NTSTATUS walk_streams(vfs_handle_struct *handle,
                                        dirname,
                                        NULL,
                                        NULL,
+                                       smb_fname_base->twrp,
                                        smb_fname_base->flags);
        if (dir_smb_fname == NULL) {
                TALLOC_FREE(dirname);
                return NT_STATUS_NO_MEMORY;
        }
 
-       dirhandle = SMB_VFS_NEXT_OPENDIR(handle, dir_smb_fname, NULL, 0);
+       /*
+        * For OpenDir to succeed if the stream rootdir is outside
+        * the share path, we must temporarily swap out the connect
+        * path for this share. We're dealing with absolute paths
+        * here so we don't care about chdir calls.
+        */
+       rootdir = stream_rootdir(handle, talloc_tos());
+       if (rootdir == NULL) {
+               TALLOC_FREE(dir_smb_fname);
+               TALLOC_FREE(dirname);
+               return NT_STATUS_NO_MEMORY;
+       }
 
-       TALLOC_FREE(dir_smb_fname);
+       orig_connectpath = handle->conn->connectpath;
+       handle->conn->connectpath = rootdir;
 
-       if (dirhandle == NULL) {
+       status = OpenDir(
+               talloc_tos(), handle->conn, dir_smb_fname, NULL, 0, &dir_hnd);
+       if (!NT_STATUS_IS_OK(status)) {
+               handle->conn->connectpath = orig_connectpath;
+               TALLOC_FREE(rootdir);
+               TALLOC_FREE(dir_smb_fname);
                TALLOC_FREE(dirname);
-               return map_nt_error_from_unix(errno);
+               return status;
        }
 
-       while ((dirent = vfs_readdirname(handle->conn, dirhandle, NULL,
-                                        &talloced)) != NULL) {
-
-               if (ISDOT(dirent) || ISDOTDOT(dirent)) {
+       while ((dname = ReadDirName(dir_hnd, &talloced)) != NULL) {
+               if (ISDOT(dname) || ISDOTDOT(dname)) {
                        TALLOC_FREE(talloced);
                        continue;
                }
 
-               DEBUG(10, ("walk_streams: dirent=%s\n", dirent));
+               DBG_DEBUG("dirent=%s\n", dname);
 
-               if (!fn(dirname, dirent, private_data)) {
+               if (!fn(dir_smb_fname, dname, private_data)) {
                        TALLOC_FREE(talloced);
                        break;
                }
                TALLOC_FREE(talloced);
        }
 
-       SMB_VFS_NEXT_CLOSEDIR(handle, dirhandle);
+       /* Restore the original connectpath. */
+       handle->conn->connectpath = orig_connectpath;
+       TALLOC_FREE(rootdir);
+       TALLOC_FREE(dir_smb_fname);
+       TALLOC_FREE(dir_hnd);
 
        if (pdirname != NULL) {
                *pdirname = dirname;
@@ -537,28 +595,6 @@ static NTSTATUS walk_streams(vfs_handle_struct *handle,
        return NT_STATUS_OK;
 }
 
-/**
- * Helper to stat/lstat the base file of an smb_fname. This will actually
- * fills in the stat struct in smb_filename.
- */
-static int streams_depot_stat_base(vfs_handle_struct *handle,
-                                  struct smb_filename *smb_fname,
-                                  bool follow_links)
-{
-       char *tmp_stream_name;
-       int result;
-
-       tmp_stream_name = smb_fname->stream_name;
-       smb_fname->stream_name = NULL;
-       if (follow_links) {
-               result = SMB_VFS_NEXT_STAT(handle, smb_fname);
-       } else {
-               result = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
-       }
-       smb_fname->stream_name = tmp_stream_name;
-       return result;
-}
-
 static int streams_depot_stat(vfs_handle_struct *handle,
                              struct smb_filename *smb_fname)
 {
@@ -569,18 +605,13 @@ static int streams_depot_stat(vfs_handle_struct *handle,
        DEBUG(10, ("streams_depot_stat called for [%s]\n",
                   smb_fname_str_dbg(smb_fname)));
 
-       if (!is_ntfs_stream_smb_fname(smb_fname)) {
+       if (!is_named_stream(smb_fname)) {
                return SMB_VFS_NEXT_STAT(handle, smb_fname);
        }
 
-       /* If the default stream is requested, just stat the base file. */
-       if (is_ntfs_default_stream_smb_fname(smb_fname)) {
-               return streams_depot_stat_base(handle, smb_fname, true);
-       }
-
        /* Stat the actual stream now. */
-       status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
-                                 false);
+       status = stream_smb_fname(
+               handle, NULL, smb_fname, &smb_fname_stream, false);
        if (!NT_STATUS_IS_OK(status)) {
                ret = -1;
                errno = map_errno_from_nt_status(status);
@@ -608,18 +639,13 @@ static int streams_depot_lstat(vfs_handle_struct *handle,
        DEBUG(10, ("streams_depot_lstat called for [%s]\n",
                   smb_fname_str_dbg(smb_fname)));
 
-       if (!is_ntfs_stream_smb_fname(smb_fname)) {
+       if (!is_named_stream(smb_fname)) {
                return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
        }
 
-       /* If the default stream is requested, just stat the base file. */
-       if (is_ntfs_default_stream_smb_fname(smb_fname)) {
-               return streams_depot_stat_base(handle, smb_fname, false);
-       }
-
        /* Stat the actual stream now. */
-       status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
-                                 false);
+       status = stream_smb_fname(
+               handle, NULL, smb_fname, &smb_fname_stream, false);
        if (!NT_STATUS_IS_OK(status)) {
                ret = -1;
                errno = map_errno_from_nt_status(status);
@@ -633,61 +659,94 @@ static int streams_depot_lstat(vfs_handle_struct *handle,
        return ret;
 }
 
-static int streams_depot_open(vfs_handle_struct *handle,
-                             struct smb_filename *smb_fname,
-                             files_struct *fsp, int flags, mode_t mode)
+static int streams_depot_openat(struct vfs_handle_struct *handle,
+                               const struct files_struct *dirfsp,
+                               const struct smb_filename *smb_fname,
+                               struct files_struct *fsp,
+                               const struct vfs_open_how *how)
 {
        struct smb_filename *smb_fname_stream = NULL;
-       struct smb_filename *smb_fname_base = NULL;
+       struct files_struct *fspcwd = NULL;
        NTSTATUS status;
+       bool create_it;
        int ret = -1;
 
-       if (!is_ntfs_stream_smb_fname(smb_fname)) {
-               return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
+       if (!is_named_stream(smb_fname)) {
+               return SMB_VFS_NEXT_OPENAT(handle,
+                                          dirfsp,
+                                          smb_fname,
+                                          fsp,
+                                          how);
        }
 
-       /* If the default stream is requested, just open the base file. */
-       if (is_ntfs_default_stream_smb_fname(smb_fname)) {
-               char *tmp_stream_name;
+       if (how->resolve != 0) {
+               errno = ENOSYS;
+               return -1;
+       }
 
-               tmp_stream_name = smb_fname->stream_name;
-               smb_fname->stream_name = NULL;
-               ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
-               smb_fname->stream_name = tmp_stream_name;
+       SMB_ASSERT(fsp_is_alternate_stream(fsp));
+       SMB_ASSERT(dirfsp == NULL);
+       SMB_ASSERT(VALID_STAT(fsp->base_fsp->fsp_name->st));
 
-               return ret;
-       }
+       create_it = (how->flags & O_CREAT);
 
-       /* Ensure the base file still exists. */
-       smb_fname_base = synthetic_smb_fname(talloc_tos(),
-                                       smb_fname->base_name,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
-       if (smb_fname_base == NULL) {
+       /* Determine the stream name, and then open it. */
+       status = stream_smb_fname(
+               handle,
+               &fsp->base_fsp->fsp_name->st,
+               fsp->fsp_name,
+               &smb_fname_stream,
+               create_it);
+       if (!NT_STATUS_IS_OK(status)) {
                ret = -1;
-               errno = ENOMEM;
+               errno = map_errno_from_nt_status(status);
                goto done;
        }
 
-       ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
-       if (ret == -1) {
-               goto done;
+       if (create_it) {
+               bool check_valid = lp_parm_bool(
+                       SNUM(handle->conn),
+                       "streams_depot",
+                       "check_valid",
+                       true);
+
+               if (check_valid) {
+                       char buf = '1';
+
+                       DBG_DEBUG("marking file %s as valid\n",
+                                 fsp->base_fsp->fsp_name->base_name);
+
+                       ret = SMB_VFS_FSETXATTR(
+                               fsp->base_fsp,
+                               SAMBA_XATTR_MARKER,
+                               &buf,
+                               sizeof(buf),
+                               0);
+
+                       if (ret == -1) {
+                               DBG_DEBUG("FSETXATTR failed: %s\n",
+                                         strerror(errno));
+                               goto done;
+                       }
+               }
        }
 
-       /* Determine the stream name, and then open it. */
-       status = stream_smb_fname(handle, smb_fname, &smb_fname_stream, true);
+       status = vfs_at_fspcwd(talloc_tos(), handle->conn, &fspcwd);
        if (!NT_STATUS_IS_OK(status)) {
                ret = -1;
                errno = map_errno_from_nt_status(status);
                goto done;
        }
 
-       ret = SMB_VFS_NEXT_OPEN(handle, smb_fname_stream, fsp, flags, mode);
+       ret = SMB_VFS_NEXT_OPENAT(handle,
+                                 fspcwd,
+                                 smb_fname_stream,
+                                 fsp,
+                                 how);
 
  done:
        TALLOC_FREE(smb_fname_stream);
-       TALLOC_FREE(smb_fname_base);
+       TALLOC_FREE(fspcwd);
        return ret;
 }
 
@@ -696,26 +755,37 @@ static int streams_depot_unlink_internal(vfs_handle_struct *handle,
                                const struct smb_filename *smb_fname,
                                int flags)
 {
-       struct smb_filename *smb_fname_base = NULL;
+       struct smb_filename *full_fname = NULL;
+       char *dirname = NULL;
        int ret = -1;
 
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dirfsp,
+                                                 smb_fname);
+       if (full_fname == NULL) {
+               return -1;
+       }
+
        DEBUG(10, ("streams_depot_unlink called for %s\n",
-                  smb_fname_str_dbg(smb_fname)));
+                  smb_fname_str_dbg(full_fname)));
 
        /* If there is a valid stream, just unlink the stream and return. */
-       if (is_ntfs_stream_smb_fname(smb_fname) &&
-           !is_ntfs_default_stream_smb_fname(smb_fname)) {
+       if (is_named_stream(full_fname)) {
                struct smb_filename *smb_fname_stream = NULL;
                NTSTATUS status;
 
-               status = stream_smb_fname(handle, smb_fname, &smb_fname_stream,
-                                         false);
+               status = stream_smb_fname(
+                       handle, NULL, full_fname, &smb_fname_stream, false);
+               TALLOC_FREE(full_fname);
                if (!NT_STATUS_IS_OK(status)) {
                        errno = map_errno_from_nt_status(status);
                        return -1;
                }
 
-               ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_stream);
+               ret = SMB_VFS_NEXT_UNLINKAT(handle,
+                               dirfsp->conn->cwd_fsp,
+                               smb_fname_stream,
+                               0);
 
                TALLOC_FREE(smb_fname_stream);
                return ret;
@@ -725,24 +795,23 @@ static int streams_depot_unlink_internal(vfs_handle_struct *handle,
         * We potentially need to delete the per-inode streams directory
         */
 
-       smb_fname_base = synthetic_smb_fname(talloc_tos(),
-                                       smb_fname->base_name,
-                                       NULL,
-                                       NULL,
-                                       smb_fname->flags);
-       if (smb_fname_base == NULL) {
-               errno = ENOMEM;
-               return -1;
-       }
-
-       if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
-               ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
+       if (full_fname->flags & SMB_FILENAME_POSIX_PATH) {
+               ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
        } else {
-               ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
+               ret = SMB_VFS_NEXT_STAT(handle, full_fname);
+               if (ret == -1 && (errno == ENOENT || errno == ELOOP)) {
+                       if (VALID_STAT(smb_fname->st) &&
+                                       S_ISLNK(smb_fname->st.st_ex_mode)) {
+                               /*
+                                * Original name was a link - Could be
+                                * trying to remove a dangling symlink.
+                                */
+                               ret = SMB_VFS_NEXT_LSTAT(handle, full_fname);
+                       }
+               }
        }
-
        if (ret == -1) {
-               TALLOC_FREE(smb_fname_base);
+               TALLOC_FREE(full_fname);
                return -1;
        }
 
@@ -751,61 +820,69 @@ static int streams_depot_unlink_internal(vfs_handle_struct *handle,
         * check is already done in the caller. Remove the
         * file *after* the streams.
         */
-       {
-               char *dirname = stream_dir(handle, smb_fname_base,
-                                          &smb_fname_base->st, false);
-
-               if (dirname != NULL) {
-                       struct smb_filename *smb_fname_dir =
-                               synthetic_smb_fname(talloc_tos(),
-                                               dirname,
-                                               NULL,
-                                               NULL,
-                                               smb_fname->flags);
-                       if (smb_fname_dir == NULL) {
-                               TALLOC_FREE(smb_fname_base);
-                               TALLOC_FREE(dirname);
-                               errno = ENOMEM;
-                               return -1;
-                       }
-                       SMB_VFS_NEXT_RMDIR(handle, smb_fname_dir);
-                       TALLOC_FREE(smb_fname_dir);
+       dirname = stream_dir(handle,
+                            full_fname,
+                            &full_fname->st,
+                            false);
+       TALLOC_FREE(full_fname);
+       if (dirname != NULL) {
+               struct smb_filename *smb_fname_dir = NULL;
+
+               smb_fname_dir = synthetic_smb_fname(talloc_tos(),
+                                                   dirname,
+                                                   NULL,
+                                                   NULL,
+                                                   smb_fname->twrp,
+                                                   smb_fname->flags);
+               if (smb_fname_dir == NULL) {
+                       TALLOC_FREE(dirname);
+                       errno = ENOMEM;
+                       return -1;
                }
+
+               SMB_VFS_NEXT_UNLINKAT(handle,
+                                     dirfsp->conn->cwd_fsp,
+                                     smb_fname_dir,
+                                     AT_REMOVEDIR);
+               TALLOC_FREE(smb_fname_dir);
                TALLOC_FREE(dirname);
        }
 
-       ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
-       TALLOC_FREE(smb_fname_base);
-       return ret;
-}
-
-static int streams_depot_unlink(vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname)
-{
-       return streams_depot_unlink_internal(handle,
-                               handle->conn->cwd_fsp,
+       ret = SMB_VFS_NEXT_UNLINKAT(handle,
+                               dirfsp,
                                smb_fname,
-                               0);
+                               flags);
+       return ret;
 }
 
-static int streams_depot_rmdir(vfs_handle_struct *handle,
-                               const struct smb_filename *smb_fname)
+static int streams_depot_rmdir_internal(vfs_handle_struct *handle,
+                       struct files_struct *dirfsp,
+                       const struct smb_filename *smb_fname)
 {
+       struct smb_filename *full_fname = NULL;
        struct smb_filename *smb_fname_base = NULL;
        int ret = -1;
 
-       DEBUG(10, ("streams_depot_rmdir called for %s\n",
-               smb_fname->base_name));
+       full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                 dirfsp,
+                                                 smb_fname);
+       if (full_fname == NULL) {
+               return -1;
+       }
+
+       DBG_DEBUG("called for %s\n", full_fname->base_name);
 
        /*
         * We potentially need to delete the per-inode streams directory
         */
 
        smb_fname_base = synthetic_smb_fname(talloc_tos(),
-                               smb_fname->base_name,
+                               full_fname->base_name,
                                NULL,
                                NULL,
-                               smb_fname->flags);
+                               full_fname->twrp,
+                               full_fname->flags);
+       TALLOC_FREE(full_fname);
        if (smb_fname_base == NULL) {
                errno = ENOMEM;
                return -1;
@@ -837,6 +914,7 @@ static int streams_depot_rmdir(vfs_handle_struct *handle,
                                                dirname,
                                                NULL,
                                                NULL,
+                                               smb_fname->twrp,
                                                smb_fname->flags);
                        if (smb_fname_dir == NULL) {
                                TALLOC_FREE(smb_fname_base);
@@ -844,13 +922,19 @@ static int streams_depot_rmdir(vfs_handle_struct *handle,
                                errno = ENOMEM;
                                return -1;
                        }
-                       SMB_VFS_NEXT_RMDIR(handle, smb_fname_dir);
+                       SMB_VFS_NEXT_UNLINKAT(handle,
+                                       dirfsp->conn->cwd_fsp,
+                                       smb_fname_dir,
+                                       AT_REMOVEDIR);
                        TALLOC_FREE(smb_fname_dir);
                }
                TALLOC_FREE(dirname);
        }
 
-       ret = SMB_VFS_NEXT_RMDIR(handle, smb_fname_base);
+       ret = SMB_VFS_NEXT_UNLINKAT(handle,
+                               dirfsp,
+                               smb_fname,
+                               AT_REMOVEDIR);
        TALLOC_FREE(smb_fname_base);
        return ret;
 }
@@ -861,9 +945,10 @@ static int streams_depot_unlinkat(vfs_handle_struct *handle,
                        int flags)
 {
        int ret;
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
        if (flags & AT_REMOVEDIR) {
-               ret = streams_depot_rmdir(handle, smb_fname);
+               ret = streams_depot_rmdir_internal(handle,
+                               dirfsp,
+                               smb_fname);
        } else {
                ret = streams_depot_unlink_internal(handle,
                                dirfsp,
@@ -881,6 +966,8 @@ static int streams_depot_renameat(vfs_handle_struct *handle,
 {
        struct smb_filename *smb_fname_src_stream = NULL;
        struct smb_filename *smb_fname_dst_stream = NULL;
+       struct smb_filename *full_src = NULL;
+       struct smb_filename *full_dst = NULL;
        bool src_is_stream, dst_is_stream;
        NTSTATUS status;
        int ret = -1;
@@ -907,24 +994,47 @@ static int streams_depot_renameat(vfs_handle_struct *handle,
                goto done;
        }
 
-       status = stream_smb_fname(handle, smb_fname_src, &smb_fname_src_stream,
-                                 false);
+       full_src = full_path_from_dirfsp_atname(talloc_tos(),
+                                               srcfsp,
+                                               smb_fname_src);
+       if (full_src == NULL) {
+               errno = ENOMEM;
+               goto done;
+       }
+
+       full_dst = full_path_from_dirfsp_atname(talloc_tos(),
+                                               dstfsp,
+                                               smb_fname_dst);
+       if (full_dst == NULL) {
+               errno = ENOMEM;
+               goto done;
+       }
+
+       status = stream_smb_fname(
+               handle, NULL, full_src, &smb_fname_src_stream, false);
        if (!NT_STATUS_IS_OK(status)) {
                errno = map_errno_from_nt_status(status);
                goto done;
        }
 
-       status = stream_smb_fname(handle, smb_fname_dst,
-                                 &smb_fname_dst_stream, false);
+       status = stream_smb_fname(
+               handle, NULL, full_dst, &smb_fname_dst_stream, false);
        if (!NT_STATUS_IS_OK(status)) {
                errno = map_errno_from_nt_status(status);
                goto done;
        }
 
+       /*
+        * We must use handle->conn->cwd_fsp as
+        * srcfsp and dstfsp directory handles here
+        * as we used the full pathname from the cwd dir
+        * to calculate the streams directory and filename
+        * within.
+        */
        ret = SMB_VFS_NEXT_RENAMEAT(handle,
-                               srcfsp,
+                               handle->conn->cwd_fsp,
                                smb_fname_src_stream,
-                               dstfsp,
+                               handle->conn->cwd_fsp,
                                smb_fname_dst_stream);
 
 done:
@@ -967,10 +1077,11 @@ struct streaminfo_state {
        NTSTATUS status;
 };
 
-static bool collect_one_stream(const char *dirname,
+static bool collect_one_stream(const struct smb_filename *dirfname,
                               const char *dirent,
                               void *private_data)
 {
+       const char *dirname = dirfname->base_name;
        struct streaminfo_state *state =
                (struct streaminfo_state *)private_data;
        struct smb_filename *smb_fname = NULL;
@@ -984,7 +1095,12 @@ static bool collect_one_stream(const char *dirname,
                goto out;
        }
 
-       smb_fname = synthetic_smb_fname(talloc_tos(), sname, NULL, NULL, 0);
+       smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       sname,
+                                       NULL,
+                                       NULL,
+                                       dirfname->twrp,
+                                       0);
        if (smb_fname == NULL) {
                state->status = NT_STATUS_NO_MEMORY;
                ret = false;
@@ -1015,9 +1131,8 @@ static bool collect_one_stream(const char *dirname,
        return ret;
 }
 
-static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
+static NTSTATUS streams_depot_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)
@@ -1028,25 +1143,16 @@ static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
        struct streaminfo_state state;
 
        smb_fname_base = synthetic_smb_fname(talloc_tos(),
-                                       smb_fname->base_name,
+                                       fsp->fsp_name->base_name,
                                        NULL,
                                        NULL,
-                                       smb_fname->flags);
+                                       fsp->fsp_name->twrp,
+                                       fsp->fsp_name->flags);
        if (smb_fname_base == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       if ((fsp != NULL) && (fsp->fh->fd != -1)) {
-               ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &smb_fname_base->st);
-       }
-       else {
-               if (smb_fname_base->flags & SMB_FILENAME_POSIX_PATH) {
-                       ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname_base);
-               } else {
-                       ret = SMB_VFS_NEXT_STAT(handle, smb_fname_base);
-               }
-       }
-
+       ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &smb_fname_base->st);
        if (ret == -1) {
                status = map_nt_error_from_unix(errno);
                goto out;
@@ -1058,19 +1164,11 @@ static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
        state.handle = handle;
        state.status = NT_STATUS_OK;
 
-       if (S_ISLNK(smb_fname_base->st.st_ex_mode)) {
-               /*
-                * Currently we do't have SMB_VFS_LLISTXATTR
-                * inside the VFS which means there's no way
-                * to cope with a symlink when lp_posix_pathnames().
-                * returns true. For now ignore links.
-                * FIXME - by adding SMB_VFS_LLISTXATTR. JRA.
-                */
-               status = NT_STATUS_OK;
-       } else {
-               status = walk_streams(handle, smb_fname_base, NULL, collect_one_stream,
-                             &state);
-       }
+       status = walk_streams(handle,
+                               smb_fname_base,
+                               NULL,
+                               collect_one_stream,
+                               &state);
 
        if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(state.streams);
@@ -1085,9 +1183,8 @@ static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
 
        *pnum_streams = state.num_streams;
        *pstreams = state.streams;
-       status = SMB_VFS_NEXT_STREAMINFO(handle,
-                               fsp,
-                               smb_fname_base,
+       status = SMB_VFS_NEXT_FSTREAMINFO(handle,
+                               fsp->base_fsp ? fsp->base_fsp : fsp,
                                mem_ctx,
                                pnum_streams,
                                pstreams);
@@ -1105,14 +1202,12 @@ static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle,
 
 static struct vfs_fn_pointers vfs_streams_depot_fns = {
        .fs_capabilities_fn = streams_depot_fs_capabilities,
-       .open_fn = streams_depot_open,
+       .openat_fn = streams_depot_openat,
        .stat_fn = streams_depot_stat,
        .lstat_fn = streams_depot_lstat,
-       .unlink_fn = streams_depot_unlink,
        .unlinkat_fn = streams_depot_unlinkat,
-       .rmdir_fn = streams_depot_rmdir,
        .renameat_fn = streams_depot_renameat,
-       .streaminfo_fn = streams_depot_streaminfo,
+       .fstreaminfo_fn = streams_depot_fstreaminfo,
 };
 
 static_decl_vfs;