]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
vfs: Add SMB_VFS_RENAME_STREAM
authorVolker Lendecke <vl@samba.org>
Mon, 22 Sep 2025 13:55:57 +0000 (15:55 +0200)
committerRalph Boehme <slow@samba.org>
Tue, 21 Oct 2025 17:33:29 +0000 (17:33 +0000)
[MS-FSA] 2.1.5.15.12.1 Algorithm for Performing Stream Rename

is simpler and diffent enough from renaming a file or directory that I
believe a separate VFS operation is justified instead of tunneling it
through the renameat call. For example it's only possible to rename
streams within a file, so only one stream open fsp and a newname which
is guaranteed to be a stream name is necessary.

Add stub implementations to our streams modules, to be filled later.

Signed-off-by: Volker Lendecke <vl@samba.org>
vfs_streams_xattr: rename_streams
Reviewed-by: Ralph Boehme <slow@samba.org>
12 files changed:
examples/VFS/skel_opaque.c
examples/VFS/skel_transparent.c
source3/include/smbprofile.h
source3/include/vfs.h
source3/include/vfs_macros.h
source3/modules/vfs_default.c
source3/modules/vfs_full_audit.c
source3/modules/vfs_not_implemented.c
source3/modules/vfs_streams_depot.c
source3/modules/vfs_streams_xattr.c
source3/modules/vfs_time_audit.c
source3/smbd/vfs.c

index a3521982f1697912d461cd30e0af193a66ee29be..abb369c480a0e526343e07c1b7f4ad5dc6d0a96b 100644 (file)
@@ -305,6 +305,15 @@ static int skel_renameat(vfs_handle_struct *handle,
        return -1;
 }
 
+static int skel_rename_stream(struct vfs_handle_struct *handle,
+                             struct files_struct *src_fsp,
+                             const char *dst_name,
+                             bool replace_if_exists)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
 static struct tevent_req *skel_fsync_send(struct vfs_handle_struct *handle,
                                          TALLOC_CTX *mem_ctx,
                                          struct tevent_context *ev,
@@ -1002,6 +1011,7 @@ static struct vfs_fn_pointers skel_opaque_fns = {
        .sendfile_fn = skel_sendfile,
        .recvfile_fn = skel_recvfile,
        .renameat_fn = skel_renameat,
+       .rename_stream_fn = skel_rename_stream,
        .fsync_send_fn = skel_fsync_send,
        .fsync_recv_fn = skel_fsync_recv,
        .stat_fn = skel_stat,
index 4d1312414a063c3a734c5dfeacc212839c6a7df6..9a3546192659f5eb045097cde96c688f0d7c24ac 100644 (file)
@@ -395,6 +395,17 @@ static int skel_renameat(vfs_handle_struct *handle,
                        how);
 }
 
+static int skel_rename_stream(struct vfs_handle_struct *handle,
+                             struct files_struct *src_fsp,
+                             const char *dst_name,
+                             bool replace_if_exists)
+{
+       return SMB_VFS_NEXT_RENAME_STREAM(handle,
+                                         src_fsp,
+                                         dst_name,
+                                         replace_if_exists);
+}
+
 struct skel_fsync_state {
        int ret;
        struct vfs_aio_state vfs_aio_state;
@@ -1313,6 +1324,7 @@ static struct vfs_fn_pointers skel_transparent_fns = {
        .sendfile_fn = skel_sendfile,
        .recvfile_fn = skel_recvfile,
        .renameat_fn = skel_renameat,
+       .rename_stream_fn = skel_rename_stream,
        .fsync_send_fn = skel_fsync_send,
        .fsync_recv_fn = skel_fsync_recv,
        .stat_fn = skel_stat,
index c51e0b226721128327c3e8040042a8ea0ce8defc..f41f6c5c11cbdd29b8132c56947398f041979421 100644 (file)
@@ -75,6 +75,7 @@ struct tevent_context;
        SMBPROFILE_STATS_BYTES(syscall_sendfile) \
        SMBPROFILE_STATS_BYTES(syscall_recvfile) \
        SMBPROFILE_STATS_BASIC(syscall_renameat) \
+       SMBPROFILE_STATS_BASIC(syscall_rename_stream) \
        SMBPROFILE_STATS_BYTES(syscall_asys_fsync) \
        SMBPROFILE_STATS_BASIC(syscall_stat) \
        SMBPROFILE_STATS_BASIC(syscall_fstat) \
index 34bd97fa3de32b7ebc16bf5f5df4caf4d978501c..cf6590a56cdf7c40c40764e8017b383aaf3069fd 100644 (file)
  * Version 50 - Add struct files_struct.fsp_flags.posix_append
  * Change to Version 51 - will ship with 4.23
  * Version 51 - Add ntcreatex_deny_[dos|fcb] and ntcreatex_stream_baseopen
+ * Change to Version 52 - will ship with 4.24
+ * Version 52 - Add rename_stream
  */
 
 #define SMB_VFS_INTERFACE_VERSION 51
@@ -1076,6 +1078,10 @@ struct vfs_fn_pointers {
                         struct files_struct *dstdir_fsp,
                         const struct smb_filename *smb_fname_dst,
                         const struct vfs_rename_how *how);
+       int (*rename_stream_fn)(struct vfs_handle_struct *handle,
+                               struct files_struct *src_fsp,
+                               const char *dst_name,
+                               bool replace_if_exists);
        struct tevent_req *(*fsync_send_fn)(struct vfs_handle_struct *handle,
                                            TALLOC_CTX *mem_ctx,
                                            struct tevent_context *ev,
@@ -1585,6 +1591,10 @@ int smb_vfs_call_renameat(struct vfs_handle_struct *handle,
                        struct files_struct *dstfsp,
                        const struct smb_filename *smb_fname_dst,
                        const struct vfs_rename_how *how);
+int smb_vfs_call_rename_stream(struct vfs_handle_struct *handle,
+                              struct files_struct *src_fsp,
+                              const char *dst_name,
+                              bool replace_if_exists);
 
 struct tevent_req *smb_vfs_call_fsync_send(struct vfs_handle_struct *handle,
                                           TALLOC_CTX *mem_ctx,
@@ -2024,6 +2034,10 @@ int vfs_not_implemented_renameat(vfs_handle_struct *handle,
                               files_struct *dstfsp,
                               const struct smb_filename *smb_fname_dst,
                               const struct vfs_rename_how *how);
+int vfs_not_implemented_rename_stream(struct vfs_handle_struct *handle,
+                                     struct files_struct *src_fsp,
+                                     const char *dst_name,
+                                     bool replace_if_exists);
 struct tevent_req *vfs_not_implemented_fsync_send(struct vfs_handle_struct *handle,
                                                  TALLOC_CTX *mem_ctx,
                                                  struct tevent_context *ev,
index f2d8174369ab4f5ec401e78e0bd63cea45a4fbe0..7f2e1defb46e7c22f5db31e0cb34884d8133f436 100644 (file)
 #define SMB_VFS_NEXT_RENAMEAT(handle, oldfsp, old, newfsp, newname, how) \
        smb_vfs_call_renameat((handle)->next, (oldfsp), (old), (newfsp), (newname), (how))
 
+#define SMB_VFS_RENAME_STREAM(conn, src_fsp, dst_name, replace_if_exists) \
+       smb_vfs_call_rename_stream((conn)->vfs_handles,                   \
+                                  (src_fsp),                             \
+                                  (dst_name),                            \
+                                  (replace_if_exists))
+#define SMB_VFS_NEXT_RENAME_STREAM(handle,            \
+                                  src_fsp,           \
+                                  dst_name,          \
+                                  replace_if_exists) \
+       smb_vfs_call_rename_stream((handle)->next,    \
+                                  (src_fsp),         \
+                                  (dst_name),        \
+                                  (replace_if_exists))
+
 #define SMB_VFS_FSYNC_SEND(mem_ctx, ev, fsp) \
        smb_vfs_call_fsync_send((fsp)->conn->vfs_handles, (mem_ctx), (ev), \
                                (fsp))
index 90c67adcc3b2af57a53cee78960ec807e9887ed9..5501723da9db714002a7b4733ba57d8867fe32c9 100644 (file)
@@ -1304,6 +1304,18 @@ static int vfswrap_renameat(vfs_handle_struct *handle,
        return result;
 }
 
+static int vfswrap_rename_stream(struct vfs_handle_struct *handle,
+                                struct files_struct *src_fsp,
+                                const char *dst_name,
+                                bool replace_if_exists)
+{
+       int result = -1;
+       START_PROFILE_X(SNUM(handle->conn), syscall_rename_stream);
+       errno = ENOSYS;
+       END_PROFILE_X(syscall_rename_stream);
+       return result;
+}
+
 static int vfswrap_stat(vfs_handle_struct *handle,
                        struct smb_filename *smb_fname)
 {
@@ -4061,6 +4073,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .sendfile_fn = vfswrap_sendfile,
        .recvfile_fn = vfswrap_recvfile,
        .renameat_fn = vfswrap_renameat,
+       .rename_stream_fn = vfswrap_rename_stream,
        .fsync_send_fn = vfswrap_fsync_send,
        .fsync_recv_fn = vfswrap_fsync_recv,
        .stat_fn = vfswrap_stat,
index fd7b810d59cd16999f5db6f3b6e951cc2b883f72..febca8fd97ab5c44c97c093098852a54e4ff5af5 100644 (file)
@@ -132,6 +132,7 @@ typedef enum _vfs_op_type {
        SMB_VFS_OP_SENDFILE,
        SMB_VFS_OP_RECVFILE,
        SMB_VFS_OP_RENAMEAT,
+       SMB_VFS_OP_RENAME_STREAM,
        SMB_VFS_OP_FSYNC_SEND,
        SMB_VFS_OP_FSYNC_RECV,
        SMB_VFS_OP_STAT,
@@ -211,7 +212,7 @@ typedef enum _vfs_op_type {
        SMB_VFS_OP_FSETXATTR,
 
        /* aio operations */
-        SMB_VFS_OP_AIO_FORCE,
+       SMB_VFS_OP_AIO_FORCE,
 
        /* offline operations */
        SMB_VFS_OP_IS_OFFLINE,
@@ -267,6 +268,7 @@ static struct {
        { SMB_VFS_OP_SENDFILE,  "sendfile" },
        { SMB_VFS_OP_RECVFILE,  "recvfile" },
        { SMB_VFS_OP_RENAMEAT,  "renameat" },
+       { SMB_VFS_OP_RENAME_STREAM,     "rename_stream" },
        { SMB_VFS_OP_FSYNC_SEND,        "fsync_send" },
        { SMB_VFS_OP_FSYNC_RECV,        "fsync_recv" },
        { SMB_VFS_OP_STAT,      "stat" },
@@ -1449,6 +1451,33 @@ static int smb_full_audit_renameat(vfs_handle_struct *handle,
        return result;
 }
 
+static int smb_full_audit_rename_stream(struct vfs_handle_struct *handle,
+                                       struct files_struct *src_fsp,
+                                       const char *dst_name,
+                                       bool replace_if_exists)
+{
+       int result;
+       int saved_errno;
+
+       result = SMB_VFS_NEXT_RENAME_STREAM(handle,
+                                           src_fsp,
+                                           dst_name,
+                                           replace_if_exists);
+       saved_errno = errno;
+
+       do_log(SMB_VFS_OP_RENAME_STREAM,
+              (result >= 0),
+              handle,
+              "%s|%s",
+              fsp_str_do_log(src_fsp),
+              dst_name);
+
+       if (result == -1) {
+               errno = saved_errno;
+       }
+       return result;
+}
+
 struct smb_full_audit_fsync_state {
        vfs_handle_struct *handle;
        files_struct *fsp;
@@ -2939,6 +2968,7 @@ static struct vfs_fn_pointers vfs_full_audit_fns = {
        .sendfile_fn = smb_full_audit_sendfile,
        .recvfile_fn = smb_full_audit_recvfile,
        .renameat_fn = smb_full_audit_renameat,
+       .rename_stream_fn = smb_full_audit_rename_stream,
        .fsync_send_fn = smb_full_audit_fsync_send,
        .fsync_recv_fn = smb_full_audit_fsync_recv,
        .stat_fn = smb_full_audit_stat,
index 4a28cf486cea6da1521538634da8fdf4b0842a21..0e210496b43d7014f2e6617229d86d9a72313e29 100644 (file)
@@ -328,6 +328,16 @@ int vfs_not_implemented_renameat(vfs_handle_struct *handle,
        return -1;
 }
 
+_PUBLIC_
+int vfs_not_implemented_rename_stream(struct vfs_handle_struct *handle,
+                                     struct files_struct *src_fsp,
+                                     const char *dst_name,
+                                     bool replace_if_exists)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
 _PUBLIC_
 struct tevent_req *vfs_not_implemented_fsync_send(struct vfs_handle_struct *handle,
                                                  TALLOC_CTX *mem_ctx,
@@ -1098,6 +1108,7 @@ static struct vfs_fn_pointers vfs_not_implemented_fns = {
        .sendfile_fn = vfs_not_implemented_sendfile,
        .recvfile_fn = vfs_not_implemented_recvfile,
        .renameat_fn = vfs_not_implemented_renameat,
+       .rename_stream_fn = vfs_not_implemented_rename_stream,
        .fsync_send_fn = vfs_not_implemented_fsync_send,
        .fsync_recv_fn = vfs_not_implemented_fsync_recv,
        .stat_fn = vfs_not_implemented_stat,
index 81a11668864e54669af6c42ecc51a81b3f279bcb..fd44eef76a55ccaad27e527bf4e571a883fd1c33 100644 (file)
@@ -1065,6 +1065,15 @@ done:
        return ret;
 }
 
+static int streams_depot_rename_stream(struct vfs_handle_struct *handle,
+                                      struct files_struct *src_fsp,
+                                      const char *dst_name,
+                                      bool replace_if_exists)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
 static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
                           struct stream_struct **streams,
                           const char *name, off_t size,
@@ -1237,6 +1246,7 @@ static struct vfs_fn_pointers vfs_streams_depot_fns = {
        .fstatat_fn = streams_depot_fstatat,
        .unlinkat_fn = streams_depot_unlinkat,
        .renameat_fn = streams_depot_renameat,
+       .rename_stream_fn = streams_depot_rename_stream,
        .fstreaminfo_fn = streams_depot_fstreaminfo,
 };
 
index e8ce0e419e16dbd04b26e8d8f49f64d1217b01a2..3b870f579bebcbeb9b8647c69e2c36828b326f73 100644 (file)
@@ -1303,6 +1303,15 @@ static int streams_xattr_renameat(vfs_handle_struct *handle,
        return ret;
 }
 
+static int streams_xattr_rename_stream(struct vfs_handle_struct *handle,
+                                      struct files_struct *src_fsp,
+                                      const char *dst_name,
+                                      bool replace_if_exists)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
 static NTSTATUS walk_xattr_streams(vfs_handle_struct *handle,
                                files_struct *fsp,
                                const struct smb_filename *smb_fname,
@@ -2310,6 +2319,7 @@ static struct vfs_fn_pointers vfs_streams_xattr_fns = {
        .pwrite_recv_fn = streams_xattr_pwrite_recv,
        .unlinkat_fn = streams_xattr_unlinkat,
        .renameat_fn = streams_xattr_renameat,
+       .rename_stream_fn = streams_xattr_rename_stream,
        .ftruncate_fn = streams_xattr_ftruncate,
        .fallocate_fn = streams_xattr_fallocate,
        .fstreaminfo_fn = streams_xattr_fstreaminfo,
index 8a9263604c9dbb16aa91d1416b5f7f6508aebbfb..83f87b6e7901fe66931ff0295738a65d39662580 100644 (file)
@@ -949,6 +949,38 @@ static int smb_time_audit_renameat(vfs_handle_struct *handle,
        return result;
 }
 
+static int smb_time_audit_rename_stream(struct vfs_handle_struct *handle,
+                                       struct files_struct *src_fsp,
+                                       const char *dst_name,
+                                       bool replace_if_exists)
+{
+       int result;
+       struct timespec ts1, ts2;
+       double timediff;
+       char *msg = NULL;
+
+       clock_gettime_mono(&ts1);
+       result = SMB_VFS_NEXT_RENAME_STREAM(handle,
+                                           src_fsp,
+                                           dst_name,
+                                           replace_if_exists);
+       clock_gettime_mono(&ts2);
+       timediff = nsec_time_diff(&ts2, &ts1) * 1.0e-9;
+
+       if (timediff > audit_timeout) {
+               msg = talloc_asprintf(talloc_tos(),
+                                     "%s -> %s",
+                                     fsp_str_dbg(src_fsp),
+                                     dst_name);
+               if (msg != NULL) {
+                       smb_time_audit_log_msg("rename_stream", timediff, msg);
+                       TALLOC_FREE(msg);
+               }
+       }
+
+       return result;
+}
+
 struct smb_time_audit_fsync_state {
        struct files_struct *fsp;
        int ret;
@@ -2726,6 +2758,7 @@ static struct vfs_fn_pointers vfs_time_audit_fns = {
        .sendfile_fn = smb_time_audit_sendfile,
        .recvfile_fn = smb_time_audit_recvfile,
        .renameat_fn = smb_time_audit_renameat,
+       .rename_stream_fn = smb_time_audit_rename_stream,
        .fsync_send_fn = smb_time_audit_fsync_send,
        .fsync_recv_fn = smb_time_audit_fsync_recv,
        .stat_fn = smb_time_audit_stat,
@@ -2797,7 +2830,6 @@ static struct vfs_fn_pointers vfs_time_audit_fns = {
        .freaddir_attr_fn = smb_time_audit_freaddir_attr,
 };
 
-
 static_decl_vfs;
 NTSTATUS vfs_time_audit_init(TALLOC_CTX *ctx)
 {
index 82fe586506fc92a06480b81ca1da3aa680312ad6..af54fc8f2f58f2ef4a179562f318b8b50f2bce92 100644 (file)
@@ -1821,6 +1821,18 @@ int smb_vfs_call_renameat(struct vfs_handle_struct *handle,
                                how);
 }
 
+int smb_vfs_call_rename_stream(struct vfs_handle_struct *handle,
+                              struct files_struct *src_fsp,
+                              const char *dst_name,
+                              bool replace_if_exists)
+{
+       VFS_FIND(rename_stream);
+       return handle->fns->rename_stream_fn(handle,
+                                            src_fsp,
+                                            dst_name,
+                                            replace_if_exists);
+}
+
 struct smb_vfs_call_fsync_state {
        int (*recv_fn)(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state);
        int retval;