vfs: Add SMB_VFS_FSTATAT
authorVolker Lendecke <vl@samba.org>
Thu, 6 Jan 2022 14:59:05 +0000 (15:59 +0100)
committerJeremy Allison <jra@samba.org>
Thu, 10 Mar 2022 18:23:35 +0000 (18:23 +0000)
Useful if you want to stat/fstat/lstat relative to a directory without
doing chdir first.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
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_shadow_copy2.c
source3/modules/vfs_time_audit.c
source3/smbd/vfs.c

index cc7bb880d5c27069d71329632450a5a4069b00bd..e39668ed2a8aa73227bb5d8ab79095106930216d 100644 (file)
@@ -345,6 +345,17 @@ static int skel_lstat(vfs_handle_struct *handle,
        return -1;
 }
 
+static int skel_fstatat(
+       struct vfs_handle_struct *handle,
+       const struct files_struct *dirfsp,
+       const struct smb_filename *smb_fname,
+       SMB_STRUCT_STAT *sbuf,
+       int flags)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
 static uint64_t skel_get_alloc_size(struct vfs_handle_struct *handle,
                                    struct files_struct *fsp,
                                    const SMB_STRUCT_STAT *sbuf)
@@ -1001,6 +1012,7 @@ static struct vfs_fn_pointers skel_opaque_fns = {
        .stat_fn = skel_stat,
        .fstat_fn = skel_fstat,
        .lstat_fn = skel_lstat,
+       .fstatat_fn = skel_fstatat,
        .get_alloc_size_fn = skel_get_alloc_size,
        .unlinkat_fn = skel_unlinkat,
        .fchmod_fn = skel_fchmod,
index e145881b704381e54649fd1610a51e5e9340a76e..5508e084abd53c3fe740dde4bead750802a15acf 100644 (file)
@@ -473,6 +473,16 @@ static int skel_lstat(vfs_handle_struct *handle,
        return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
 }
 
+static int skel_fstatat(
+       struct vfs_handle_struct *handle,
+       const struct files_struct *dirfsp,
+       const struct smb_filename *smb_fname,
+       SMB_STRUCT_STAT *sbuf,
+       int flags)
+{
+       return SMB_VFS_NEXT_FSTATAT(handle, dirfsp, smb_fname, sbuf, flags);
+}
+
 static uint64_t skel_get_alloc_size(struct vfs_handle_struct *handle,
                                    struct files_struct *fsp,
                                    const SMB_STRUCT_STAT *sbuf)
@@ -1316,6 +1326,7 @@ static struct vfs_fn_pointers skel_transparent_fns = {
        .stat_fn = skel_stat,
        .fstat_fn = skel_fstat,
        .lstat_fn = skel_lstat,
+       .fstatat_fn = skel_fstatat,
        .get_alloc_size_fn = skel_get_alloc_size,
        .unlinkat_fn = skel_unlinkat,
        .fchmod_fn = skel_fchmod,
index 3ddd4eb6f5d70417ef736e9d3b200add41f40e07..ce7a7405bf47e6470a2f0c0f58d4ed744146721d 100644 (file)
@@ -66,6 +66,7 @@ struct tevent_context;
        SMBPROFILE_STATS_BASIC(syscall_stat) \
        SMBPROFILE_STATS_BASIC(syscall_fstat) \
        SMBPROFILE_STATS_BASIC(syscall_lstat) \
+       SMBPROFILE_STATS_BASIC(syscall_fstatat) \
        SMBPROFILE_STATS_BASIC(syscall_get_alloc_size) \
        SMBPROFILE_STATS_BASIC(syscall_unlinkat) \
        SMBPROFILE_STATS_BASIC(syscall_chmod) \
index 695ba0aebd09112a29617f4405cd50eb9477577b..39cb38bcc91c709e2e61c9f3453e1f394f2fcf0d 100644 (file)
  * Version 45 - Remove SMB_VFS_GETXATTR
  * Version 46 - Rename SMB_VFS_KERNEL_FLOCK to SMB_VFS_FILESYSTEM_SHAREMODE
  * Version 46 - Add flags and xferlen args to SMB_VFS_OFFLOAD_READ_RECV
+ * Version 46 - Add SMB_VFS_FSTATAT
  */
 
 #define SMB_VFS_INTERFACE_VERSION 46
@@ -1016,6 +1017,12 @@ struct vfs_fn_pointers {
        int (*stat_fn)(struct vfs_handle_struct *handle, struct smb_filename *smb_fname);
        int (*fstat_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_STAT *sbuf);
        int (*lstat_fn)(struct vfs_handle_struct *handle, struct smb_filename *smb_filename);
+       int (*fstatat_fn)(
+               struct vfs_handle_struct *handle,
+               const struct files_struct *dirfsp,
+               const struct smb_filename *smb_fname,
+               SMB_STRUCT_STAT *sbuf,
+               int flags);
        uint64_t (*get_alloc_size_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, const SMB_STRUCT_STAT *sbuf);
        int (*unlinkat_fn)(struct vfs_handle_struct *handle,
                        struct files_struct *srcdir_fsp,
@@ -1514,6 +1521,12 @@ int smb_vfs_call_fstat(struct vfs_handle_struct *handle,
                       struct files_struct *fsp, SMB_STRUCT_STAT *sbuf);
 int smb_vfs_call_lstat(struct vfs_handle_struct *handle,
                       struct smb_filename *smb_filename);
+int smb_vfs_call_fstatat(
+       struct vfs_handle_struct *handle,
+       const struct files_struct *dirfsp,
+       const struct smb_filename *smb_fname,
+       SMB_STRUCT_STAT *sbuf,
+       int flags);
 uint64_t smb_vfs_call_get_alloc_size(struct vfs_handle_struct *handle,
                                     struct files_struct *fsp,
                                     const SMB_STRUCT_STAT *sbuf);
@@ -1942,6 +1955,12 @@ int vfs_not_implemented_fstat(vfs_handle_struct *handle, files_struct *fsp,
                        SMB_STRUCT_STAT *sbuf);
 int vfs_not_implemented_lstat(vfs_handle_struct *handle,
                              struct smb_filename *smb_fname);
+int vfs_not_implemented_fstatat(
+       struct vfs_handle_struct *handle,
+       const struct files_struct *dirfsp,
+       const struct smb_filename *smb_fname,
+       SMB_STRUCT_STAT *sbuf,
+       int flags);
 uint64_t vfs_not_implemented_get_alloc_size(struct vfs_handle_struct *handle,
                                            struct files_struct *fsp,
                                            const SMB_STRUCT_STAT *sbuf);
index 49654f59ff245b43e01b9e78c8b30d99099c867b..99619320df421536dcc5a88262a1f73bb24231ca 100644 (file)
 #define SMB_VFS_NEXT_LSTAT(handle, smb_fname) \
        smb_vfs_call_lstat((handle)->next, (smb_fname))
 
+#define SMB_VFS_FSTATAT(conn, dirfsp, smb_fname, sbuf, flags) \
+       smb_vfs_call_fstatat((conn)->vfs_handles, (dirfsp), (smb_fname), \
+                            (sbuf), (flags))
+#define SMB_VFS_NEXT_FSTATAT(conn, dirfsp, smb_fname, sbuf, flags) \
+       smb_vfs_call_fstatat((handle)->next, (dirfsp), (smb_fname), \
+                            (sbuf), (flags))
+
 #define SMB_VFS_GET_ALLOC_SIZE(conn, fsp, sbuf) \
        smb_vfs_call_get_alloc_size((conn)->vfs_handles, (fsp), (sbuf))
 #define SMB_VFS_NEXT_GET_ALLOC_SIZE(conn, fsp, sbuf) \
index 647608747921a8d57c04a64554fe28958956cc91..d6c244e561323fac2b77ae682325211b2700067f 100644 (file)
@@ -1314,6 +1314,33 @@ static int vfswrap_lstat(vfs_handle_struct *handle,
        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);
+
+       if (is_named_stream(smb_fname)) {
+               errno = ENOENT;
+               goto out;
+       }
+
+       result = sys_fstatat(
+               fsp_get_pathref_fd(dirfsp),
+               smb_fname->base_name,
+               sbuf,
+               flags,
+               lp_fake_directory_create_times(SNUM(handle->conn)));
+ out:
+       END_PROFILE(syscall_fstatat);
+       return result;
+}
+
 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
                                       const char *name,
                                       enum vfs_translate_direction direction,
@@ -3968,6 +3995,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,
index 5903849931ee2c64541826d842b7d7adb1da1d60..9fd712399c981a1b3a00b1b97001b739c77ee9b6 100644 (file)
@@ -140,6 +140,7 @@ typedef enum _vfs_op_type {
        SMB_VFS_OP_STAT,
        SMB_VFS_OP_FSTAT,
        SMB_VFS_OP_LSTAT,
+       SMB_VFS_OP_FSTATAT,
        SMB_VFS_OP_GET_ALLOC_SIZE,
        SMB_VFS_OP_UNLINKAT,
        SMB_VFS_OP_FCHMOD,
@@ -276,6 +277,7 @@ static struct {
        { SMB_VFS_OP_STAT,      "stat" },
        { SMB_VFS_OP_FSTAT,     "fstat" },
        { SMB_VFS_OP_LSTAT,     "lstat" },
+       { SMB_VFS_OP_FSTATAT,   "fstatat" },
        { SMB_VFS_OP_GET_ALLOC_SIZE,    "get_alloc_size" },
        { SMB_VFS_OP_UNLINKAT,  "unlinkat" },
        { SMB_VFS_OP_FCHMOD,    "fchmod" },
@@ -1568,6 +1570,26 @@ static int smb_full_audit_lstat(vfs_handle_struct *handle,
        return result;    
 }
 
+static int smb_full_audit_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;
+
+       result = SMB_VFS_NEXT_FSTATAT(handle, dirfsp, smb_fname, sbuf, flags);
+
+       do_log(SMB_VFS_OP_FSTATAT,
+              (result >= 0),
+              handle,
+              "%s/%s",
+              fsp_str_do_log(dirfsp),
+              smb_fname_str_do_log(handle->conn, smb_fname));
+
+       return result;
+}
 static uint64_t smb_full_audit_get_alloc_size(vfs_handle_struct *handle,
                       files_struct *fsp, const SMB_STRUCT_STAT *sbuf)
 {
@@ -2930,6 +2952,7 @@ static struct vfs_fn_pointers vfs_full_audit_fns = {
        .stat_fn = smb_full_audit_stat,
        .fstat_fn = smb_full_audit_fstat,
        .lstat_fn = smb_full_audit_lstat,
+       .fstatat_fn = smb_full_audit_fstatat,
        .get_alloc_size_fn = smb_full_audit_get_alloc_size,
        .unlinkat_fn = smb_full_audit_unlinkat,
        .fchmod_fn = smb_full_audit_fchmod,
index fcc1ca1abbe0263dc2de25954ed742384545a6b3..303f0a7c5cf6919fec46859232642ee1dc07ec1c 100644 (file)
@@ -381,6 +381,18 @@ int vfs_not_implemented_lstat(vfs_handle_struct *handle,
        return -1;
 }
 
+_PUBLIC_
+int vfs_not_implemented_fstatat(
+       struct vfs_handle_struct *handle,
+       const struct files_struct *dirfsp,
+       const struct smb_filename *smb_fname,
+       SMB_STRUCT_STAT *sbuf,
+       int flags)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
 _PUBLIC_
 uint64_t vfs_not_implemented_get_alloc_size(struct vfs_handle_struct *handle,
                                            struct files_struct *fsp,
@@ -1104,6 +1116,7 @@ static struct vfs_fn_pointers vfs_not_implemented_fns = {
        .stat_fn = vfs_not_implemented_stat,
        .fstat_fn = vfs_not_implemented_fstat,
        .lstat_fn = vfs_not_implemented_lstat,
+       .fstatat_fn = vfs_not_implemented_fstatat,
        .get_alloc_size_fn = vfs_not_implemented_get_alloc_size,
        .unlinkat_fn = vfs_not_implemented_unlinkat,
        .fchmod_fn = vfs_not_implemented_fchmod,
index 1bba9a8e2b04424f116edd70a2a48e1a36aafe24..f08a813dac7c7ce1a2e0506877f8c652ca85656a 100644 (file)
@@ -1414,6 +1414,102 @@ out:
        return ret;
 }
 
+static int shadow_copy2_fstatat(
+       struct vfs_handle_struct *handle,
+       const struct files_struct *dirfsp,
+       const struct smb_filename *smb_fname_in,
+       SMB_STRUCT_STAT *sbuf,
+       int flags)
+{
+       struct shadow_copy2_private *priv = NULL;
+       struct smb_filename *smb_fname = NULL;
+       time_t timestamp = 0;
+       char *stripped = NULL;
+       char *abspath = NULL;
+       bool converted = false;
+       int ret;
+       bool ok;
+
+       SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+                               return -1);
+
+       smb_fname = full_path_from_dirfsp_atname(talloc_tos(),
+                                                dirfsp,
+                                                smb_fname_in);
+       if (smb_fname == NULL) {
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ok = shadow_copy2_strip_snapshot_converted(talloc_tos(),
+                                                  handle,
+                                                  smb_fname,
+                                                  &timestamp,
+                                                  &stripped,
+                                                  &converted);
+       if (!ok) {
+               return -1;
+       }
+       if (timestamp == 0) {
+               TALLOC_FREE(stripped);
+               ret = SMB_VFS_NEXT_FSTATAT(
+                       handle, dirfsp, smb_fname_in, sbuf, flags);
+               if (ret != 0) {
+                       return ret;
+               }
+               if (!converted) {
+                       return 0;
+               }
+
+               abspath = make_path_absolute(
+                       talloc_tos(), priv, smb_fname->base_name);
+               if (abspath == NULL) {
+                       errno = ENOMEM;
+                       return -1;
+               }
+
+               convert_sbuf(handle, abspath, sbuf);
+               TALLOC_FREE(abspath);
+               return 0;
+       }
+
+       smb_fname->base_name = shadow_copy2_convert(
+               smb_fname, handle, stripped, timestamp);
+       TALLOC_FREE(stripped);
+       if (smb_fname->base_name == NULL) {
+               TALLOC_FREE(smb_fname);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       ret = SMB_VFS_NEXT_FSTATAT(handle,
+                                  dirfsp,
+                                  smb_fname,
+                                  sbuf,
+                                  flags);
+       if (ret != 0) {
+               int saved_errno = errno;
+               TALLOC_FREE(smb_fname);
+               errno = saved_errno;
+               return -1;
+       }
+
+       abspath = make_path_absolute(
+               talloc_tos(), priv, smb_fname->base_name);
+       if (abspath == NULL) {
+               TALLOC_FREE(smb_fname);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       convert_sbuf(handle, abspath, sbuf);
+       TALLOC_FREE(abspath);
+
+       TALLOC_FREE(smb_fname);
+
+       return 0;
+}
+
 static int shadow_copy2_openat(vfs_handle_struct *handle,
                               const struct files_struct *dirfsp,
                               const struct smb_filename *smb_fname_in,
@@ -3248,6 +3344,7 @@ static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
        .stat_fn = shadow_copy2_stat,
        .lstat_fn = shadow_copy2_lstat,
        .fstat_fn = shadow_copy2_fstat,
+       .fstatat_fn = shadow_copy2_fstatat,
        .openat_fn = shadow_copy2_openat,
        .unlinkat_fn = shadow_copy2_unlinkat,
        .fchmod_fn = shadow_copy2_fchmod,
index 8becd160456ae06ccb0e59d557fec7cc99369f94..858900e4fbcd8b32e45ddf06f1c5120bddab1f94 100644 (file)
@@ -1107,6 +1107,29 @@ static int smb_time_audit_lstat(vfs_handle_struct *handle,
        return result;
 }
 
+static int smb_time_audit_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;
+       struct timespec ts1,ts2;
+       double timediff;
+
+       clock_gettime_mono(&ts1);
+       result = SMB_VFS_NEXT_FSTATAT(handle, dirfsp, smb_fname, sbuf, flags);
+       clock_gettime_mono(&ts2);
+       timediff = nsec_time_diff(&ts2,&ts1)*1.0e-9;
+
+       if (timediff > audit_timeout) {
+               smb_time_audit_log_smb_fname("fstatat", timediff, smb_fname);
+       }
+
+       return result;
+}
+
 static uint64_t smb_time_audit_get_alloc_size(vfs_handle_struct *handle,
                                              files_struct *fsp,
                                              const SMB_STRUCT_STAT *sbuf)
@@ -2745,6 +2768,7 @@ static struct vfs_fn_pointers vfs_time_audit_fns = {
        .stat_fn = smb_time_audit_stat,
        .fstat_fn = smb_time_audit_fstat,
        .lstat_fn = smb_time_audit_lstat,
+       .fstatat_fn = smb_time_audit_fstatat,
        .get_alloc_size_fn = smb_time_audit_get_alloc_size,
        .unlinkat_fn = smb_time_audit_unlinkat,
        .fchmod_fn = smb_time_audit_fchmod,
index 1b3ddc286c089fad3d855345ef392e7877902e41..208beaff80730d9c337755139f36c7e705eb780d 100644 (file)
@@ -2037,6 +2037,17 @@ int smb_vfs_call_lstat(struct vfs_handle_struct *handle,
        return handle->fns->lstat_fn(handle, smb_filename);
 }
 
+int smb_vfs_call_fstatat(
+       struct vfs_handle_struct *handle,
+       const struct files_struct *dirfsp,
+       const struct smb_filename *smb_fname,
+       SMB_STRUCT_STAT *sbuf,
+       int flags)
+{
+       VFS_FIND(fstatat);
+       return handle->fns->fstatat_fn(handle, dirfsp, smb_fname, sbuf, flags);
+}
+
 uint64_t smb_vfs_call_get_alloc_size(struct vfs_handle_struct *handle,
                                     struct files_struct *fsp,
                                     const SMB_STRUCT_STAT *sbuf)