]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
vfs: Add SMB_VFS_FSTATVFS
authorVolker Lendecke <vl@samba.org>
Wed, 19 Nov 2025 13:05:49 +0000 (14:05 +0100)
committerAnoop C S <anoopcs@samba.org>
Sun, 15 Feb 2026 10:42:34 +0000 (10:42 +0000)
To replace SMB_VFS_STATVFS next

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Anoop C S <anoopcs@samba.org>
14 files changed:
examples/VFS/skel_opaque.c
examples/VFS/skel_transparent.c
source3/include/vfs.h
source3/include/vfs_macros.h
source3/modules/vfs_ceph.c
source3/modules/vfs_ceph_new.c
source3/modules/vfs_default.c
source3/modules/vfs_full_audit.c
source3/modules/vfs_glusterfs.c
source3/modules/vfs_media_harmony.c
source3/modules/vfs_not_implemented.c
source3/modules/vfs_time_audit.c
source3/modules/vfs_unityed_media.c
source3/smbd/vfs.c

index 31aff0c1273b454e1ee4b223825ef80c6c9406d1..c265cc852c268a1e9a2dae0ade0cf372baba94d6 100644 (file)
@@ -91,6 +91,14 @@ static int skel_statvfs(struct vfs_handle_struct *handle,
        return -1;
 }
 
+static int skel_fstatvfs(struct vfs_handle_struct *handle,
+                        struct files_struct *fsp,
+                        struct vfs_statvfs_struct *statbuf)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
 static uint32_t skel_fs_capabilities(struct vfs_handle_struct *handle,
                                     enum timestamp_set_resolution *p_ts_res)
 {
@@ -962,6 +970,7 @@ static struct vfs_fn_pointers skel_opaque_fns = {
        .set_quota_fn = skel_set_quota,
        .get_shadow_copy_data_fn = skel_get_shadow_copy_data,
        .statvfs_fn = skel_statvfs,
+       .fstatvfs_fn = skel_fstatvfs,
        .fs_capabilities_fn = skel_fs_capabilities,
        .get_dfs_referrals_fn = skel_get_dfs_referrals,
        .create_dfs_pathat_fn = skel_create_dfs_pathat,
index 50cbb5c90a5479e4937e21c21d60f56260335d80..b1bc6cdd4068335a689f25b5a434a05fac71ed5a 100644 (file)
@@ -88,6 +88,13 @@ static int skel_statvfs(struct vfs_handle_struct *handle,
        return SMB_VFS_NEXT_STATVFS(handle, smb_fname, statbuf);
 }
 
+static int skel_fstatvfs(struct vfs_handle_struct *handle,
+                        struct files_struct *fsp,
+                        struct vfs_statvfs_struct *statbuf)
+{
+       return SMB_VFS_NEXT_FSTATVFS(handle, fsp, statbuf);
+}
+
 static uint32_t skel_fs_capabilities(struct vfs_handle_struct *handle,
                                     enum timestamp_set_resolution *p_ts_res)
 {
@@ -1272,6 +1279,7 @@ static struct vfs_fn_pointers skel_transparent_fns = {
        .set_quota_fn = skel_set_quota,
        .get_shadow_copy_data_fn = skel_get_shadow_copy_data,
        .statvfs_fn = skel_statvfs,
+       .fstatvfs_fn = skel_fstatvfs,
        .fs_capabilities_fn = skel_fs_capabilities,
        .get_dfs_referrals_fn = skel_get_dfs_referrals,
        .create_dfs_pathat_fn = skel_create_dfs_pathat,
index ef2dc8b6d59ac2c1f3b46d5445ae96eed831bd1b..6a779e151fe65ced5e37b17cbfcd8ce9ba69b24d 100644 (file)
  * Version 52 - Add VFS_OPEN_HOW_RESOLVE_NO_XDEV for SMB_VFS_OPENAT()
  * Change to Version 53 - will ship with 4.25
  * Version 53 - Change DISK_FREE to take a fsp instead of a name
+ * Version 53 - Add fstatvfs
  */
 
 #define SMB_VFS_INTERFACE_VERSION 53
@@ -999,6 +1000,9 @@ struct vfs_fn_pointers {
        int (*statvfs_fn)(struct vfs_handle_struct *handle,
                                const struct smb_filename *smb_fname,
                                struct vfs_statvfs_struct *statbuf);
+       int (*fstatvfs_fn)(struct vfs_handle_struct *handle,
+                          struct files_struct *fsp,
+                          struct vfs_statvfs_struct *statbuf);
        uint32_t (*fs_capabilities_fn)(struct vfs_handle_struct *handle, enum timestamp_set_resolution *p_ts_res);
 
        /*
@@ -1459,6 +1463,9 @@ int smb_vfs_call_get_shadow_copy_data(struct vfs_handle_struct *handle,
 int smb_vfs_call_statvfs(struct vfs_handle_struct *handle,
                        const struct smb_filename *smb_fname,
                        struct vfs_statvfs_struct *statbuf);
+int smb_vfs_call_fstatvfs(struct vfs_handle_struct *handle,
+                         struct files_struct *fsp,
+                         struct vfs_statvfs_struct *statbuf);
 uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle,
                                      enum timestamp_set_resolution *p_ts_res);
 /*
@@ -1892,6 +1899,9 @@ int vfs_not_implemented_get_shadow_copy_data(vfs_handle_struct *handle,
 int vfs_not_implemented_statvfs(struct vfs_handle_struct *handle,
                                const struct smb_filename *smb_fname,
                                struct vfs_statvfs_struct *statbuf);
+int vfs_not_implemented_fstatvfs(struct vfs_handle_struct *handle,
+                                struct files_struct *fsp,
+                                struct vfs_statvfs_struct *statbuf);
 uint32_t vfs_not_implemented_fs_capabilities(struct vfs_handle_struct *handle,
                                enum timestamp_set_resolution *p_ts_res);
 NTSTATUS vfs_not_implemented_get_dfs_referrals(struct vfs_handle_struct *handle,
index 7f583586b129210fe48f0f10179052bc12c874cb..cb5a4fe9fa05e92e5f68e3f1d84a4a199ee9fcce 100644 (file)
 #define SMB_VFS_NEXT_STATVFS(handle, smb_fname, statbuf) \
        smb_vfs_call_statvfs((handle)->next, (smb_fname), (statbuf))
 
+#define SMB_VFS_FSTATVFS(conn, fsp, statbuf) \
+       smb_vfs_call_fstatvfs((conn)->vfs_handles, (fsp), (statbuf))
+#define SMB_VFS_NEXT_FSTATVFS(handle, fsp, statbuf) \
+       smb_vfs_call_fstatvfs((handle)->next, (fsp), (statbuf))
+
 #define SMB_VFS_FS_CAPABILITIES(conn, p_ts_res) \
        smb_vfs_call_fs_capabilities((conn)->vfs_handles, (p_ts_res))
 #define SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) \
index b35af684599743842b56c1076aeacad8934e9d56..a3080e4cd0274c2e1691f55c92064abc7b47d7d4 100644 (file)
@@ -378,6 +378,13 @@ static int cephwrap_statvfs(struct vfs_handle_struct *handle,
        return ret;
 }
 
+static int cephwrap_fstatvfs(struct vfs_handle_struct *handle,
+                            struct files_struct *fsp,
+                            struct vfs_statvfs_struct *statbuf)
+{
+       return cephwrap_statvfs(handle, fsp->fsp_name, statbuf);
+}
+
 static uint32_t cephwrap_fs_capabilities(
        struct vfs_handle_struct *handle,
        enum timestamp_set_resolution *p_ts_res)
@@ -1779,6 +1786,7 @@ static struct vfs_fn_pointers ceph_fns = {
        .get_quota_fn = vfs_not_implemented_get_quota,
        .set_quota_fn = vfs_not_implemented_set_quota,
        .statvfs_fn = cephwrap_statvfs,
+       .fstatvfs_fn = cephwrap_fstatvfs,
        .fs_capabilities_fn = cephwrap_fs_capabilities,
 
        /* Directory operations */
index 935ed2c605d5b03f92ba35d6342821b8c61fea5c..7d4be60e40a70dfc1d0408add6fd75882cb1537d 100644 (file)
@@ -2539,6 +2539,13 @@ out:
        return status_code(ret);
 }
 
+static int vfs_ceph_fstatvfs(struct vfs_handle_struct *handle,
+                            struct files_struct *fsp,
+                            struct vfs_statvfs_struct *statbuf)
+{
+       return vfs_ceph_statvfs(handle, fsp->fsp_name, statbuf);
+}
+
 static uint32_t vfs_ceph_fs_capabilities(
        struct vfs_handle_struct *handle,
        enum timestamp_set_resolution *p_ts_res)
@@ -4616,6 +4623,7 @@ static struct vfs_fn_pointers ceph_new_fns = {
        .get_quota_fn = vfs_not_implemented_get_quota,
        .set_quota_fn = vfs_not_implemented_set_quota,
        .statvfs_fn = vfs_ceph_statvfs,
+       .fstatvfs_fn = vfs_ceph_fstatvfs,
        .fs_capabilities_fn = vfs_ceph_fs_capabilities,
 
        /* Directory operations */
index 332c872c02f4f2408b72d0d1ee972fb8e497ebf7..9c260fc3743deb6b4443e60f72ae8997ab9df748 100644 (file)
@@ -169,6 +169,18 @@ static int vfswrap_statvfs(struct vfs_handle_struct *handle,
        return sys_statvfs(smb_fname->base_name, statbuf);
 }
 
+static int vfswrap_fstatvfs(struct vfs_handle_struct *handle,
+                           struct files_struct *fsp,
+                           struct vfs_statvfs_struct *statbuf)
+{
+       int ret, fd;
+
+       fd = fsp_get_pathref_fd(fsp);
+
+       ret = sys_fstatvfs(fd, statbuf);
+       return ret;
+}
+
 static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle,
                enum timestamp_set_resolution *p_ts_res)
 {
@@ -4045,6 +4057,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
        .set_quota_fn = vfswrap_set_quota,
        .get_shadow_copy_data_fn = vfswrap_get_shadow_copy_data,
        .statvfs_fn = vfswrap_statvfs,
+       .fstatvfs_fn = vfswrap_fstatvfs,
        .fs_capabilities_fn = vfswrap_fs_capabilities,
        .get_dfs_referrals_fn = vfswrap_get_dfs_referrals,
        .create_dfs_pathat_fn = vfswrap_create_dfs_pathat,
index e0cdf2718f46ec8fdc83c4091d7da934da135be5..382eab197d598b665062851bd8b79d4a025af63e 100644 (file)
@@ -101,6 +101,7 @@ typedef enum _vfs_op_type {
        SMB_VFS_OP_SET_QUOTA,
        SMB_VFS_OP_GET_SHADOW_COPY_DATA,
        SMB_VFS_OP_STATVFS,
+       SMB_VFS_OP_FSTATVFS,
        SMB_VFS_OP_FS_CAPABILITIES,
        SMB_VFS_OP_GET_DFS_REFERRALS,
        SMB_VFS_OP_CREATE_DFS_PATHAT,
@@ -241,6 +242,7 @@ static struct {
        { SMB_VFS_OP_SET_QUOTA, "set_quota" },
        { SMB_VFS_OP_GET_SHADOW_COPY_DATA,      "get_shadow_copy_data" },
        { SMB_VFS_OP_STATVFS,   "statvfs" },
+       { SMB_VFS_OP_FSTATVFS,  "fstatvfs" },
        { SMB_VFS_OP_FS_CAPABILITIES,   "fs_capabilities" },
        { SMB_VFS_OP_GET_DFS_REFERRALS, "get_dfs_referrals" },
        { SMB_VFS_OP_CREATE_DFS_PATHAT, "create_dfs_pathat" },
@@ -893,6 +895,19 @@ static int smb_full_audit_statvfs(struct vfs_handle_struct *handle,
        return result;
 }
 
+static int smb_full_audit_fstatvfs(struct vfs_handle_struct *handle,
+                                  struct files_struct *fsp,
+                                  struct vfs_statvfs_struct *statbuf)
+{
+       int result;
+
+       result = SMB_VFS_NEXT_FSTATVFS(handle, fsp, statbuf);
+
+       do_log(SMB_VFS_OP_FSTATVFS, errmsg_unix(result), handle, "");
+
+       return result;
+}
+
 static uint32_t smb_full_audit_fs_capabilities(struct vfs_handle_struct *handle, enum timestamp_set_resolution *p_ts_res)
 {
        int result;
@@ -3147,6 +3162,7 @@ static struct vfs_fn_pointers vfs_full_audit_fns = {
        .set_quota_fn = smb_full_audit_set_quota,
        .get_shadow_copy_data_fn = smb_full_audit_get_shadow_copy_data,
        .statvfs_fn = smb_full_audit_statvfs,
+       .fstatvfs_fn = smb_full_audit_fstatvfs,
        .fs_capabilities_fn = smb_full_audit_fs_capabilities,
        .get_dfs_referrals_fn = smb_full_audit_get_dfs_referrals,
        .create_dfs_pathat_fn = smb_full_audit_create_dfs_pathat,
index 8ee36bc8e64b1e559ba26c4d43f96a34b42119da..c7f786c926ea3f3cc18f68dbb4b0479039b7b305 100644 (file)
@@ -593,6 +593,13 @@ static int vfs_gluster_statvfs(struct vfs_handle_struct *handle,
        return ret;
 }
 
+static int vfs_gluster_fstatvfs(struct vfs_handle_struct *handle,
+                               struct files_struct *fsp,
+                               struct vfs_statvfs_struct *vfs_statvfs)
+{
+       return vfs_gluster_statvfs(handle, fsp->fsp_name, vfs_statvfs);
+}
+
 static uint32_t vfs_gluster_fs_capabilities(struct vfs_handle_struct *handle,
                                            enum timestamp_set_resolution *p_ts_res)
 {
@@ -2563,6 +2570,7 @@ static struct vfs_fn_pointers glusterfs_fns = {
        .get_quota_fn = vfs_gluster_get_quota,
        .set_quota_fn = vfs_gluster_set_quota,
        .statvfs_fn = vfs_gluster_statvfs,
+       .fstatvfs_fn = vfs_gluster_fstatvfs,
        .fs_capabilities_fn = vfs_gluster_fs_capabilities,
 
        .get_dfs_referrals_fn = NULL,
index d939219149f7e4811a51494bd7a11b455e8741f4..7fbc5bad2b43745a0dcb4c95f30414e02e2e27dd 100644 (file)
@@ -664,6 +664,66 @@ out:
        return status;
 }
 
+/*
+ * Success: return 0
+ * Failure: set errno, return -1
+ */
+static int mh_fstatvfs(struct vfs_handle_struct *handle,
+                      struct files_struct *fsp,
+                      struct vfs_statvfs_struct *statbuf)
+{
+       struct smb_filename *smb_fname = fsp->fsp_name;
+       char *clientPath = NULL;
+       struct smb_filename *clientFname = NULL;
+       NTSTATUS status;
+       int ret;
+
+       DEBUG(MH_INFO_DEBUG, ("Entering with path '%s'\n",
+                             fsp_str_dbg(fsp)));
+
+       if (!is_in_media_files(smb_fname->base_name)) {
+               ret = SMB_VFS_NEXT_FSTATVFS(handle, fsp, statbuf);
+               return ret;
+       }
+
+       ret = alloc_get_client_path(handle,
+                                   talloc_tos(),
+                                   smb_fname->base_name,
+                                   &clientPath);
+       if (ret != 0) {
+               goto err;
+       }
+
+       status = synthetic_pathref(talloc_tos(),
+                                  handle->conn->cwd_fsp,
+                                  clientPath,
+                                  smb_fname->stream_name,
+                                  NULL,
+                                  smb_fname->twrp,
+                                  smb_fname->flags,
+                                  &clientFname);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               ret = -1;
+               goto err;
+       }
+
+       ret = SMB_VFS_NEXT_FSTATVFS(handle, clientFname->fsp, statbuf);
+
+err:
+       {
+               int err = errno;
+               TALLOC_FREE(clientFname);
+
+               DEBUG(MH_INFO_DEBUG, ("Leaving with path '%s'\n",
+                                     fsp_str_dbg(fsp)));
+
+               errno = err;
+       }
+
+       return ret;
+}
+
 static int alloc_set_client_dirinfo(vfs_handle_struct *handle,
                const char *fname,
                struct mh_dirinfo_struct **dirInfo)
@@ -1816,6 +1876,7 @@ static struct vfs_fn_pointers vfs_mh_fns = {
        /* Disk operations */
 
        .statvfs_fn = mh_statvfs,
+       .fstatvfs_fn = mh_fstatvfs,
 
        /* Directory operations */
 
index 964edad47d405124db2e9968cc3154688b16b730..7f97ba9ab1850752bc419e2435b671ce5ee9d19b 100644 (file)
@@ -92,6 +92,15 @@ int vfs_not_implemented_statvfs(struct vfs_handle_struct *handle,
        return -1;
 }
 
+_PUBLIC_
+int vfs_not_implemented_fstatvfs(struct vfs_handle_struct *handle,
+                                struct files_struct *fsp,
+                                struct vfs_statvfs_struct *statbuf)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
 _PUBLIC_
 uint32_t vfs_not_implemented_fs_capabilities(struct vfs_handle_struct *handle,
                                enum timestamp_set_resolution *p_ts_res)
@@ -1057,6 +1066,7 @@ static struct vfs_fn_pointers vfs_not_implemented_fns = {
        .set_quota_fn = vfs_not_implemented_set_quota,
        .get_shadow_copy_data_fn = vfs_not_implemented_get_shadow_copy_data,
        .statvfs_fn = vfs_not_implemented_statvfs,
+       .fstatvfs_fn = vfs_not_implemented_fstatvfs,
        .fs_capabilities_fn = vfs_not_implemented_fs_capabilities,
        .get_dfs_referrals_fn = vfs_not_implemented_get_dfs_referrals,
        .create_dfs_pathat_fn = vfs_not_implemented_create_dfs_pathat,
index cdb08ee169c8f158959ac983c5fb3e7d106e14cf..c68c5e02f5b1d604ad70a9e45ed999cad46fb8c8 100644 (file)
@@ -284,6 +284,28 @@ static int smb_time_audit_statvfs(struct vfs_handle_struct *handle,
        return result;
 }
 
+static int smb_time_audit_fstatvfs(struct vfs_handle_struct *handle,
+                                  struct files_struct *fsp,
+                                  struct vfs_statvfs_struct *statbuf)
+{
+       int result;
+       struct timespec ts1, ts2;
+       double timediff;
+
+       clock_gettime_mono(&ts1);
+       result = SMB_VFS_NEXT_FSTATVFS(handle, fsp, statbuf);
+       clock_gettime_mono(&ts2);
+       timediff = nsec_time_diff(&ts2, &ts1) * 1.0e-9;
+
+       if (timediff > audit_timeout) {
+               smb_time_audit_log_fname("fstatvfs",
+                                        timediff,
+                                        fsp_str_dbg(fsp));
+       }
+
+       return result;
+}
+
 static uint32_t smb_time_audit_fs_capabilities(struct vfs_handle_struct *handle,
                                               enum timestamp_set_resolution *p_ts_res)
 {
@@ -2686,6 +2708,7 @@ static struct vfs_fn_pointers vfs_time_audit_fns = {
        .set_quota_fn = smb_time_audit_set_quota,
        .get_shadow_copy_data_fn = smb_time_audit_get_shadow_copy_data,
        .statvfs_fn = smb_time_audit_statvfs,
+       .fstatvfs_fn = smb_time_audit_fstatvfs,
        .fs_capabilities_fn = smb_time_audit_fs_capabilities,
        .get_dfs_referrals_fn = smb_time_audit_get_dfs_referrals,
        .create_dfs_pathat_fn = smb_time_audit_create_dfs_pathat,
index b2ee2e1e32372c6da406e1f997e0342a8befc45b..edebcf24a885fab997dea8ce28c61c70748beedf 100644 (file)
@@ -558,6 +558,63 @@ err:
        return status;
 }
 
+/*
+ * Success: return 0
+ * Failure: set errno, return -1
+ */
+static int um_fstatvfs(struct vfs_handle_struct *handle,
+                      struct files_struct *fsp,
+                      struct vfs_statvfs_struct *statbuf)
+{
+       struct smb_filename *smb_fname = fsp->fsp_name;
+       char *clientPath = NULL;
+       struct smb_filename *clientFname = NULL;
+       NTSTATUS status;
+       int ret;
+
+       DBG_DEBUG("Entering with path '%s'\n", fsp_str_dbg(fsp));
+
+       if (!is_in_media_files(smb_fname->base_name)) {
+               ret = SMB_VFS_NEXT_FSTATVFS(handle, fsp, statbuf);
+               return ret;
+       }
+
+       ret = alloc_get_client_path(handle,
+                                   talloc_tos(),
+                                   smb_fname->base_name,
+                                   &clientPath);
+       if (ret != 0) {
+               goto err;
+       }
+
+       status = synthetic_pathref(talloc_tos(),
+                                  handle->conn->cwd_fsp,
+                                  clientPath,
+                                  smb_fname->stream_name,
+                                  NULL,
+                                  smb_fname->twrp,
+                                  smb_fname->flags,
+                                  &clientFname);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
+               ret = -1;
+               goto err;
+       }
+
+       ret = SMB_VFS_NEXT_FSTATVFS(handle, clientFname->fsp, statbuf);
+
+err:
+       {
+               int err = errno;
+               TALLOC_FREE(clientFname);
+
+               DBG_DEBUG("Leaving with path '%s'\n", fsp_str_dbg(fsp));
+               errno = err;
+       }
+
+       return ret;
+}
+
 static DIR *um_fdopendir(vfs_handle_struct *handle,
                         files_struct *fsp,
                         const char *mask,
@@ -1492,6 +1549,7 @@ static struct vfs_fn_pointers vfs_um_fns = {
        /* Disk operations */
 
        .statvfs_fn = um_statvfs,
+       .fstatvfs_fn = um_fstatvfs,
 
        /* Directory operations */
 
index 5f0a8d6fe4905b0229d13697389e0ff5a6529ccd..4778edfef59b0f999cea026aec7683bbf7f392b8 100644 (file)
@@ -1477,6 +1477,14 @@ int smb_vfs_call_statvfs(struct vfs_handle_struct *handle,
        return handle->fns->statvfs_fn(handle, smb_fname, statbuf);
 }
 
+int smb_vfs_call_fstatvfs(struct vfs_handle_struct *handle,
+                         struct files_struct *fsp,
+                         struct vfs_statvfs_struct *statbuf)
+{
+       VFS_FIND(fstatvfs);
+       return handle->fns->fstatvfs_fn(handle, fsp, statbuf);
+}
+
 uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle,
                        enum timestamp_set_resolution *p_ts_res)
 {