From: Volker Lendecke Date: Sun, 13 Mar 2022 11:15:59 +0000 (+0100) Subject: vfs: Add SMB_VFS_GET_REAL_FILENAME_AT X-Git-Tag: talloc-2.3.4~332 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=02f6130c907e7e3aef89a9b84c72f1deb649e5ff;p=thirdparty%2Fsamba.git vfs: Add SMB_VFS_GET_REAL_FILENAME_AT In a patchset that I'm working on right now there's the need to call getrealfilename while the code does have a pathref fsp already around. Doing the name-based call including non_widelink_open is not necessary in this case. Start by adding the _at based call to the VFS. For now, fall back to the name-based call. glusterfs-fuse will in a future patch be converted to fgetxattr. Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c index 4719a45e7bb..bc18a07478b 100644 --- a/examples/VFS/skel_opaque.c +++ b/examples/VFS/skel_opaque.c @@ -660,6 +660,15 @@ static NTSTATUS skel_get_real_filename(struct vfs_handle_struct *handle, return NT_STATUS_NOT_IMPLEMENTED; } +static NTSTATUS skel_get_real_filename_at(struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + static const char *skel_connectpath(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname) { @@ -1045,6 +1054,7 @@ static struct vfs_fn_pointers skel_opaque_fns = { .fstreaminfo_fn = skel_fstreaminfo, .get_real_filename_fn = skel_get_real_filename, + .get_real_filename_at_fn = skel_get_real_filename_at, .connectpath_fn = skel_connectpath, .brl_lock_windows_fn = skel_brl_lock_windows, .brl_unlock_windows_fn = skel_brl_unlock_windows, diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c index ecd3c282240..52d95235d1c 100644 --- a/examples/VFS/skel_transparent.c +++ b/examples/VFS/skel_transparent.c @@ -885,6 +885,16 @@ static NTSTATUS skel_get_real_filename(struct vfs_handle_struct *handle, path, name, mem_ctx, found_name); } +static NTSTATUS skel_get_real_filename_at(struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + return SMB_VFS_NEXT_GET_REAL_FILENAME_AT( + handle, dirfsp, name, mem_ctx, found_name); +} + static const char *skel_connectpath(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname) { @@ -1360,6 +1370,7 @@ static struct vfs_fn_pointers skel_transparent_fns = { .fstreaminfo_fn = skel_fstreaminfo, .get_real_filename_fn = skel_get_real_filename, + .get_real_filename_at_fn = skel_get_real_filename_at, .connectpath_fn = skel_connectpath, .brl_lock_windows_fn = skel_brl_lock_windows, .brl_unlock_windows_fn = skel_brl_unlock_windows, diff --git a/source3/include/vfs.h b/source3/include/vfs.h index e3d7fee90ff..716b9f02fce 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -369,6 +369,7 @@ * Version 47 - remove st_ex_itime from struct stat_ex * Version 47 - remove (unused) struct lock_struct last_lock_failure from files_struct. + * Version 47 - Add SMB_VFS_GET_REAL_FILENAME_AT */ #define SMB_VFS_INTERFACE_VERSION 47 @@ -1153,6 +1154,12 @@ struct vfs_fn_pointers { TALLOC_CTX *mem_ctx, char **found_name); + NTSTATUS (*get_real_filename_at_fn)(struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name); + const char *(*connectpath_fn)(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname); @@ -1621,6 +1628,11 @@ NTSTATUS smb_vfs_call_get_real_filename(struct vfs_handle_struct *handle, const char *name, TALLOC_CTX *mem_ctx, char **found_name); +NTSTATUS smb_vfs_call_get_real_filename_at(struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name); const char *smb_vfs_call_connectpath(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname); NTSTATUS smb_vfs_call_brl_lock_windows(struct vfs_handle_struct *handle, @@ -2088,6 +2100,12 @@ NTSTATUS vfs_not_implemented_get_real_filename( const char *name, TALLOC_CTX *mem_ctx, char **found_name); +NTSTATUS vfs_not_implemented_get_real_filename_at( + struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name); const char *vfs_not_implemented_connectpath(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname); NTSTATUS vfs_not_implemented_brl_lock_windows(struct vfs_handle_struct *handle, diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index 99619320df4..29cbaaba5c1 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -372,6 +372,22 @@ #define SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name, mem_ctx, found_name) \ smb_vfs_call_get_real_filename((handle)->next, (path), (name), (mem_ctx), (found_name)) +#define SMB_VFS_GET_REAL_FILENAME_AT(conn, dirfsp, name, mem_ctx, found_name) \ + smb_vfs_call_get_real_filename_at( \ + (conn)->vfs_handles, \ + (dirfsp), \ + (name), \ + (mem_ctx), \ + (found_name)) +#define SMB_VFS_NEXT_GET_REAL_FILENAME_AT( \ + handle, dirfsp, name, mem_ctx, found_name) \ + smb_vfs_call_get_real_filename_at( \ + (handle)->next, \ + (dirfsp), \ + (name), \ + (mem_ctx), \ + (found_name)) + #define SMB_VFS_CONNECTPATH(conn, smb_fname) \ smb_vfs_call_connectpath((conn)->vfs_handles, (smb_fname)) #define SMB_VFS_NEXT_CONNECTPATH(conn, smb_fname) \ diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c index 44c9cf3053a..b2f38c2be3b 100644 --- a/source3/modules/vfs_ceph.c +++ b/source3/modules/vfs_ceph.c @@ -1286,6 +1286,20 @@ static NTSTATUS cephwrap_get_real_filename( return NT_STATUS_NOT_SUPPORTED; } +static NTSTATUS cephwrap_get_real_filename_at( + struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + /* + * Don't fall back to get_real_filename so callers can differentiate + * between a full directory scan and an actual case-insensitive stat. + */ + return NT_STATUS_NOT_SUPPORTED; +} + static const char *cephwrap_connectpath(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname) { @@ -1635,6 +1649,7 @@ static struct vfs_fn_pointers ceph_fns = { .realpath_fn = cephwrap_realpath, .fchflags_fn = cephwrap_fchflags, .get_real_filename_fn = cephwrap_get_real_filename, + .get_real_filename_at_fn = cephwrap_get_real_filename_at, .connectpath_fn = cephwrap_connectpath, /* EA operations. */ diff --git a/source3/modules/vfs_ceph_snapshots.c b/source3/modules/vfs_ceph_snapshots.c index ad4c8f1dd94..2878eb7041e 100644 --- a/source3/modules/vfs_ceph_snapshots.c +++ b/source3/modules/vfs_ceph_snapshots.c @@ -1351,6 +1351,18 @@ static NTSTATUS ceph_snap_gmt_get_real_filename( return status; } +static NTSTATUS ceph_snap_gmt_get_real_filename_at( + struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + NTSTATUS status = ceph_snap_gmt_get_real_filename( + handle, dirfsp->fsp_name, name, mem_ctx, found_name); + return status; +} + static uint64_t ceph_snap_gmt_disk_free(vfs_handle_struct *handle, const struct smb_filename *csmb_fname, uint64_t *bsize, @@ -1462,6 +1474,7 @@ static struct vfs_fn_pointers ceph_snap_fns = { .fsetxattr_fn = ceph_snap_gmt_fsetxattr, .fchflags_fn = ceph_snap_gmt_fchflags, .get_real_filename_fn = ceph_snap_gmt_get_real_filename, + .get_real_filename_at_fn = ceph_snap_gmt_get_real_filename_at, }; static_decl_vfs; diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 7108402a407..ca928ded260 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -3371,6 +3371,20 @@ static NTSTATUS vfswrap_get_real_filename(struct vfs_handle_struct *handle, return NT_STATUS_NOT_SUPPORTED; } +static NTSTATUS vfswrap_get_real_filename_at( + struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + /* + * Don't fall back to get_real_filename so callers can differentiate + * between a full directory scan and an actual case-insensitive stat. + */ + return NT_STATUS_NOT_SUPPORTED; +} + static const char *vfswrap_connectpath(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname) { @@ -4016,6 +4030,7 @@ static struct vfs_fn_pointers vfs_default_fns = { .fs_file_id_fn = vfswrap_fs_file_id, .fstreaminfo_fn = vfswrap_fstreaminfo, .get_real_filename_fn = vfswrap_get_real_filename, + .get_real_filename_at_fn = vfswrap_get_real_filename_at, .connectpath_fn = vfswrap_connectpath, .brl_lock_windows_fn = vfswrap_brl_lock_windows, .brl_unlock_windows_fn = vfswrap_brl_unlock_windows, diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index a905971c1b9..c57366a533e 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -167,6 +167,7 @@ typedef enum _vfs_op_type { SMB_VFS_OP_FS_FILE_ID, SMB_VFS_OP_FSTREAMINFO, SMB_VFS_OP_GET_REAL_FILENAME, + SMB_VFS_OP_GET_REAL_FILENAME_AT, SMB_VFS_OP_CONNECTPATH, SMB_VFS_OP_BRL_LOCK_WINDOWS, SMB_VFS_OP_BRL_UNLOCK_WINDOWS, @@ -304,6 +305,7 @@ static struct { { SMB_VFS_OP_FS_FILE_ID, "fs_file_id" }, { SMB_VFS_OP_FSTREAMINFO, "fstreaminfo" }, { SMB_VFS_OP_GET_REAL_FILENAME, "get_real_filename" }, + { SMB_VFS_OP_GET_REAL_FILENAME_AT, "get_real_filename_at" }, { SMB_VFS_OP_CONNECTPATH, "connectpath" }, { SMB_VFS_OP_BRL_LOCK_WINDOWS, "brl_lock_windows" }, { SMB_VFS_OP_BRL_UNLOCK_WINDOWS, "brl_unlock_windows" }, @@ -2103,6 +2105,29 @@ static NTSTATUS smb_full_audit_get_real_filename( return result; } +static NTSTATUS smb_full_audit_get_real_filename_at( + struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + NTSTATUS result; + + result = SMB_VFS_NEXT_GET_REAL_FILENAME_AT( + handle, dirfsp, name, mem_ctx, found_name); + + do_log(SMB_VFS_OP_GET_REAL_FILENAME_AT, + NT_STATUS_IS_OK(result), + handle, + "%s/%s->%s", + fsp_str_dbg(dirfsp), + name, + NT_STATUS_IS_OK(result) ? *found_name : ""); + + return result; +} + static const char *smb_full_audit_connectpath(vfs_handle_struct *handle, const struct smb_filename *smb_fname) { @@ -2992,6 +3017,7 @@ static struct vfs_fn_pointers vfs_full_audit_fns = { .snap_delete_fn = smb_full_audit_snap_delete, .fstreaminfo_fn = smb_full_audit_fstreaminfo, .get_real_filename_fn = smb_full_audit_get_real_filename, + .get_real_filename_at_fn = smb_full_audit_get_real_filename_at, .connectpath_fn = smb_full_audit_connectpath, .brl_lock_windows_fn = smb_full_audit_brl_lock_windows, .brl_unlock_windows_fn = smb_full_audit_brl_unlock_windows, diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c index 56a403b5547..70a638a076a 100644 --- a/source3/modules/vfs_glusterfs.c +++ b/source3/modules/vfs_glusterfs.c @@ -2033,6 +2033,18 @@ static NTSTATUS vfs_gluster_get_real_filename( return NT_STATUS_OK; } +static NTSTATUS vfs_gluster_get_real_filename_at( + struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + NTSTATUS status = vfs_gluster_get_real_filename( + handle, dirfsp->fsp_name, name, mem_ctx, found_name); + return status; +} + static const char *vfs_gluster_connectpath(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname) { @@ -2371,6 +2383,7 @@ static struct vfs_fn_pointers glusterfs_fns = { .file_id_create_fn = NULL, .fstreaminfo_fn = NULL, .get_real_filename_fn = vfs_gluster_get_real_filename, + .get_real_filename_at_fn = vfs_gluster_get_real_filename_at, .connectpath_fn = vfs_gluster_connectpath, .create_dfs_pathat_fn = vfs_gluster_create_dfs_pathat, .read_dfs_pathat_fn = vfs_gluster_read_dfs_pathat, diff --git a/source3/modules/vfs_glusterfs_fuse.c b/source3/modules/vfs_glusterfs_fuse.c index d4bef3fe834..35ee1742bb0 100644 --- a/source3/modules/vfs_glusterfs_fuse.c +++ b/source3/modules/vfs_glusterfs_fuse.c @@ -58,6 +58,18 @@ static NTSTATUS vfs_gluster_fuse_get_real_filename( return NT_STATUS_OK; } +static NTSTATUS vfs_gluster_fuse_get_real_filename_at( + struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **_found_name) +{ + NTSTATUS status = vfs_gluster_fuse_get_real_filename( + handle, dirfsp->fsp_name, name, mem_ctx, _found_name); + return status; +} + struct device_mapping_entry { SMB_DEV_T device; /* the local device, for reference */ uint64_t mapped_device; /* the mapped device */ @@ -252,6 +264,7 @@ struct vfs_fn_pointers glusterfs_fuse_fns = { .connect_fn = vfs_glusterfs_fuse_connect, .get_real_filename_fn = vfs_gluster_fuse_get_real_filename, + .get_real_filename_at_fn = vfs_gluster_fuse_get_real_filename_at, .file_id_create_fn = vfs_glusterfs_fuse_file_id_create, }; diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 0f31896b724..23e7d8edac8 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -370,6 +370,17 @@ static NTSTATUS vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle, return NT_STATUS_OK; } +static NTSTATUS vfs_gpfs_get_real_filename_at(struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + NTSTATUS status = vfs_gpfs_get_real_filename( + handle, dirfsp->fsp_name, name, mem_ctx, found_name); + return status; +} + static void sd2gpfs_control(uint16_t control, struct gpfs_acl *gacl) { unsigned int gpfs_aclflags = 0; @@ -2551,6 +2562,7 @@ static struct vfs_fn_pointers vfs_gpfs_fns = { .filesystem_sharemode_fn = vfs_gpfs_filesystem_sharemode, .linux_setlease_fn = vfs_gpfs_setlease, .get_real_filename_fn = vfs_gpfs_get_real_filename, + .get_real_filename_at_fn = vfs_gpfs_get_real_filename_at, .get_dos_attributes_send_fn = vfs_not_implemented_get_dos_attributes_send, .get_dos_attributes_recv_fn = vfs_not_implemented_get_dos_attributes_recv, .fget_dos_attributes_fn = vfs_gpfs_fget_dos_attributes, diff --git a/source3/modules/vfs_not_implemented.c b/source3/modules/vfs_not_implemented.c index 3b6b84cffd0..0a69f94c665 100644 --- a/source3/modules/vfs_not_implemented.c +++ b/source3/modules/vfs_not_implemented.c @@ -734,6 +734,17 @@ NTSTATUS vfs_not_implemented_get_real_filename( return NT_STATUS_NOT_IMPLEMENTED; } +_PUBLIC_ +NTSTATUS vfs_not_implemented_get_real_filename_at( + struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + _PUBLIC_ const char *vfs_not_implemented_connectpath(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname) @@ -1149,6 +1160,7 @@ static struct vfs_fn_pointers vfs_not_implemented_fns = { .fstreaminfo_fn = vfs_not_implemented_fstreaminfo, .get_real_filename_fn = vfs_not_implemented_get_real_filename, + .get_real_filename_at_fn = vfs_not_implemented_get_real_filename_at, .connectpath_fn = vfs_not_implemented_connectpath, .brl_lock_windows_fn = vfs_not_implemented_brl_lock_windows, .brl_unlock_windows_fn = vfs_not_implemented_brl_unlock_windows, diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index dfdc6735dfb..cde46a9023b 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -2602,6 +2602,18 @@ static NTSTATUS shadow_copy2_get_real_filename( return NT_STATUS_OK; } +static NTSTATUS shadow_copy2_get_real_filename_at( + struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + NTSTATUS status = shadow_copy2_get_real_filename( + handle, dirfsp->fsp_name, name, mem_ctx, found_name); + return status; +} + static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname_in) { @@ -3447,6 +3459,7 @@ static struct vfs_fn_pointers vfs_shadow_copy2_fns = { .fsetxattr_fn = shadow_copy2_fsetxattr, .fchflags_fn = shadow_copy2_fchflags, .get_real_filename_fn = shadow_copy2_get_real_filename, + .get_real_filename_at_fn = shadow_copy2_get_real_filename_at, .pwrite_fn = shadow_copy2_pwrite, .pwrite_send_fn = shadow_copy2_pwrite_send, .pwrite_recv_fn = shadow_copy2_pwrite_recv, diff --git a/source3/modules/vfs_snapper.c b/source3/modules/vfs_snapper.c index a0e3852681d..e8f05cba1fb 100644 --- a/source3/modules/vfs_snapper.c +++ b/source3/modules/vfs_snapper.c @@ -2477,6 +2477,18 @@ static NTSTATUS snapper_gmt_get_real_filename( return status; } +static NTSTATUS snapper_gmt_get_real_filename_at( + struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + NTSTATUS status = snapper_gmt_get_real_filename( + handle, dirfsp->fsp_name, name, mem_ctx, found_name); + return status; +} + static uint64_t snapper_gmt_disk_free(vfs_handle_struct *handle, const struct smb_filename *smb_fname, uint64_t *bsize, @@ -2631,6 +2643,7 @@ static struct vfs_fn_pointers snapper_fns = { .fsetxattr_fn = snapper_gmt_fsetxattr, .fchflags_fn = snapper_gmt_fchflags, .get_real_filename_fn = snapper_gmt_get_real_filename, + .get_real_filename_at_fn = snapper_gmt_get_real_filename_at, }; static_decl_vfs; diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c index 6f133d29b54..b40f9ff00ef 100644 --- a/source3/modules/vfs_time_audit.c +++ b/source3/modules/vfs_time_audit.c @@ -1742,6 +1742,32 @@ static NTSTATUS smb_time_audit_get_real_filename( return result; } +static NTSTATUS smb_time_audit_get_real_filename_at( + struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + NTSTATUS result; + struct timespec ts1,ts2; + double timediff; + + clock_gettime_mono(&ts1); + result = SMB_VFS_NEXT_GET_REAL_FILENAME_AT( + handle, dirfsp, name, mem_ctx, found_name); + clock_gettime_mono(&ts2); + timediff = nsec_time_diff(&ts2,&ts1)*1.0e-9; + + if (timediff > audit_timeout) { + smb_time_audit_log_fname("get_real_filename_at", + timediff, + fsp_str_dbg(dirfsp)); + } + + return result; +} + static const char *smb_time_audit_connectpath(vfs_handle_struct *handle, const struct smb_filename *smb_fname) { @@ -2804,6 +2830,7 @@ static struct vfs_fn_pointers vfs_time_audit_fns = { .snap_delete_fn = smb_time_audit_snap_delete, .fstreaminfo_fn = smb_time_audit_fstreaminfo, .get_real_filename_fn = smb_time_audit_get_real_filename, + .get_real_filename_at_fn = smb_time_audit_get_real_filename_at, .connectpath_fn = smb_time_audit_connectpath, .brl_lock_windows_fn = smb_time_audit_brl_lock_windows, .brl_unlock_windows_fn = smb_time_audit_brl_unlock_windows, diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 5e8c5505905..68a97ace038 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -2272,6 +2272,17 @@ NTSTATUS smb_vfs_call_get_real_filename(struct vfs_handle_struct *handle, found_name); } +NTSTATUS smb_vfs_call_get_real_filename_at(struct vfs_handle_struct *handle, + struct files_struct *dirfsp, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + VFS_FIND(get_real_filename_at); + return handle->fns->get_real_filename_at_fn( + handle, dirfsp, name, mem_ctx, found_name); +} + const char *smb_vfs_call_connectpath(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname) {