From: Volker Lendecke Date: Thu, 6 Jan 2022 14:59:05 +0000 (+0100) Subject: vfs: Add SMB_VFS_FSTATAT X-Git-Tag: tevent-0.12.0~476 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=812cb602e3be3ffc4400cff1df63295cf2f4cd21;p=thirdparty%2Fsamba.git vfs: Add SMB_VFS_FSTATAT Useful if you want to stat/fstat/lstat relative to a directory without doing chdir first. Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c index cc7bb880d5c..e39668ed2a8 100644 --- a/examples/VFS/skel_opaque.c +++ b/examples/VFS/skel_opaque.c @@ -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, diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c index e145881b704..5508e084abd 100644 --- a/examples/VFS/skel_transparent.c +++ b/examples/VFS/skel_transparent.c @@ -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, diff --git a/source3/include/smbprofile.h b/source3/include/smbprofile.h index 3ddd4eb6f5d..ce7a7405bf4 100644 --- a/source3/include/smbprofile.h +++ b/source3/include/smbprofile.h @@ -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) \ diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 695ba0aebd0..39cb38bcc91 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -362,6 +362,7 @@ * 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); diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index 49654f59ff2..99619320df4 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -228,6 +228,13 @@ #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) \ diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 64760874792..d6c244e5613 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -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, diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 5903849931e..9fd712399c9 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -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, diff --git a/source3/modules/vfs_not_implemented.c b/source3/modules/vfs_not_implemented.c index fcc1ca1abbe..303f0a7c5cf 100644 --- a/source3/modules/vfs_not_implemented.c +++ b/source3/modules/vfs_not_implemented.c @@ -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, diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 1bba9a8e2b0..f08a813dac7 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -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, + ×tamp, + &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, diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c index 8becd160456..858900e4fbc 100644 --- a/source3/modules/vfs_time_audit.c +++ b/source3/modules/vfs_time_audit.c @@ -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, diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 1b3ddc286c0..208beaff807 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -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)