From a674a56a97c78a44bf43f1c175d106fbe70c7485 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 8 Feb 2011 15:07:48 -0800 Subject: Add fdopendir to the VFS. We will use this to reuse a directory fd already open by NtCreateX. Autobuild-User: Jeremy Allison Autobuild-Date: Wed Feb 9 00:55:22 CET 2011 on sn-devel-104 --- source3/include/smbprofile.h | 4 +++ source3/include/vfs.h | 6 +++++ source3/include/vfs_macros.h | 5 ++++ source3/modules/vfs_default.c | 14 +++++++++++ source3/modules/vfs_dirsort.c | 43 +++++++++++++++++++++++++++++++ source3/modules/vfs_full_audit.c | 16 ++++++++++++ source3/modules/vfs_netatalk.c | 26 +++++++++++++++++++ source3/modules/vfs_scannedonly.c | 30 ++++++++++++++++++++++ source3/modules/vfs_shadow_copy.c | 53 +++++++++++++++++++++++++++++++++++++++ source3/modules/vfs_time_audit.c | 21 ++++++++++++++++ source3/smbd/vfs.c | 9 +++++++ source3/utils/status_profile.c | 2 ++ 12 files changed, 229 insertions(+) (limited to 'source3') diff --git a/source3/include/smbprofile.h b/source3/include/smbprofile.h index ff8ab90ce1..3041f6c87e 100644 --- a/source3/include/smbprofile.h +++ b/source3/include/smbprofile.h @@ -43,6 +43,10 @@ enum profile_stats_values #define syscall_opendir_count __profile_stats_value(PR_VALUE_SYSCALL_OPENDIR, count) #define syscall_opendir_time __profile_stats_value(PR_VALUE_SYSCALL_OPENDIR, time) + PR_VALUE_SYSCALL_FDOPENDIR, +#define syscall_fdopendir_count __profile_stats_value(PR_VALUE_SYSCALL_FDOPENDIR, count) +#define syscall_fdopendir_time __profile_stats_value(PR_VALUE_SYSCALL_FDOPENDIR, time) + PR_VALUE_SYSCALL_READDIR, #define syscall_readdir_count __profile_stats_value(PR_VALUE_SYSCALL_READDIR, count) #define syscall_readdir_time __profile_stats_value(PR_VALUE_SYSCALL_READDIR, time) diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 72d61e330f..45193d2b54 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -132,6 +132,7 @@ where it belongs. JRA. */ /* Leave at 28 - not yet released. Rename posix_fallocate to fallocate to split out the two possible uses. JRA. */ +/* Leave at 28 - not yet released. Add fdopendir. JRA. */ #define SMB_VFS_INTERFACE_VERSION 28 @@ -198,6 +199,7 @@ struct vfs_fn_pointers { /* Directory operations */ SMB_STRUCT_DIR *(*opendir)(struct vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attributes); + SMB_STRUCT_DIR *(*fdopendir)(struct vfs_handle_struct *handle, files_struct *fsp, const char *mask, uint32 attributes); SMB_STRUCT_DIRENT *(*readdir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, SMB_STRUCT_STAT *sbuf); @@ -526,6 +528,10 @@ uint32_t smb_vfs_call_fs_capabilities(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attributes); +SMB_STRUCT_DIR *smb_vfs_call_fdopendir(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const char *mask, + uint32 attributes); SMB_STRUCT_DIRENT *smb_vfs_call_readdir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, SMB_STRUCT_STAT *sbuf); diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index bb6428ead5..c0fbe3860d 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -74,6 +74,11 @@ #define SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr) \ smb_vfs_call_opendir((handle)->next, (fname), (mask), (attr)) +#define SMB_VFS_FDOPENDIR(conn, fsp, mask, attr) \ + smb_vfs_call_fdopendir((conn)->vfs_handles, (fsp), (mask), (attr)) +#define SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr) \ + smb_vfs_call_fdopendir((handle)->next, (fsp), (mask), (attr)) + #define SMB_VFS_READDIR(conn, dirp, sbuf) \ smb_vfs_call_readdir((conn)->vfs_handles, (dirp), (sbuf)) #define SMB_VFS_NEXT_READDIR(handle, dirp, sbuf) \ diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 698e745d59..eb5a2a4b0d 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -167,6 +167,20 @@ static SMB_STRUCT_DIR *vfswrap_opendir(vfs_handle_struct *handle, const char *f return result; } +static SMB_STRUCT_DIR *vfswrap_fdopendir(vfs_handle_struct *handle, + files_struct *fsp, + const char *mask, + uint32 attr) +{ + SMB_STRUCT_DIR *result; + + START_PROFILE(syscall_fdopendir); + result = sys_fdopendir(fsp->fh->fd); + END_PROFILE(syscall_fdopendir); + return result; +} + + static SMB_STRUCT_DIRENT *vfswrap_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, SMB_STRUCT_STAT *sbuf) diff --git a/source3/modules/vfs_dirsort.c b/source3/modules/vfs_dirsort.c index 4869bc05a0..82a3a4bb98 100644 --- a/source3/modules/vfs_dirsort.c +++ b/source3/modules/vfs_dirsort.c @@ -122,6 +122,48 @@ static SMB_STRUCT_DIR *dirsort_opendir(vfs_handle_struct *handle, return data->source_directory; } +static SMB_STRUCT_DIR *dirsort_fdopendir(vfs_handle_struct *handle, + files_struct *fsp, + const char *mask, + uint32 attr) +{ + struct dirsort_privates *data = NULL; + + /* set up our private data about this directory */ + data = (struct dirsort_privates *)SMB_MALLOC( + sizeof(struct dirsort_privates)); + + if (!data) { + return NULL; + } + + data->directory_list = NULL; + data->pos = 0; + + /* Open the underlying directory and count the number of entries */ + data->source_directory = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, + attr); + + if (data->source_directory == NULL) { + SAFE_FREE(data); + return NULL; + } + + data->fd = dirfd(data->source_directory); + + SMB_VFS_HANDLE_SET_DATA(handle, data, free_dirsort_privates, + struct dirsort_privates, return NULL); + + if (!open_and_sort_dir(handle)) { + SMB_VFS_NEXT_CLOSEDIR(handle,data->source_directory); + /* fd is now closed. */ + fsp->fh->fd = -1; + return NULL; + } + + return data->source_directory; +} + static SMB_STRUCT_DIRENT *dirsort_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, SMB_STRUCT_STAT *sbuf) @@ -179,6 +221,7 @@ static void dirsort_rewinddir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp) static struct vfs_fn_pointers vfs_dirsort_fns = { .opendir = dirsort_opendir, + .fdopendir = dirsort_fdopendir, .readdir = dirsort_readdir, .seekdir = dirsort_seekdir, .telldir = dirsort_telldir, diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 10422fca79..a81f3b5870 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -87,6 +87,7 @@ typedef enum _vfs_op_type { /* Directory operations */ SMB_VFS_OP_OPENDIR, + SMB_VFS_OP_FDOPENDIR, SMB_VFS_OP_READDIR, SMB_VFS_OP_SEEKDIR, SMB_VFS_OP_TELLDIR, @@ -229,6 +230,7 @@ static struct { { SMB_VFS_OP_STATVFS, "statvfs" }, { SMB_VFS_OP_FS_CAPABILITIES, "fs_capabilities" }, { SMB_VFS_OP_OPENDIR, "opendir" }, + { SMB_VFS_OP_FDOPENDIR, "fdopendir" }, { SMB_VFS_OP_READDIR, "readdir" }, { SMB_VFS_OP_SEEKDIR, "seekdir" }, { SMB_VFS_OP_TELLDIR, "telldir" }, @@ -735,6 +737,19 @@ static SMB_STRUCT_DIR *smb_full_audit_opendir(vfs_handle_struct *handle, return result; } +static SMB_STRUCT_DIR *smb_full_audit_fdopendir(vfs_handle_struct *handle, + files_struct *fsp, const char *mask, uint32 attr) +{ + SMB_STRUCT_DIR *result; + + result = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr); + + do_log(SMB_VFS_OP_FDOPENDIR, (result != NULL), handle, "%s", + fsp_str_do_log(fsp)); + + return result; +} + static SMB_STRUCT_DIRENT *smb_full_audit_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, SMB_STRUCT_STAT *sbuf) { @@ -2201,6 +2216,7 @@ static struct vfs_fn_pointers vfs_full_audit_fns = { .statvfs = smb_full_audit_statvfs, .fs_capabilities = smb_full_audit_fs_capabilities, .opendir = smb_full_audit_opendir, + .fdopendir = smb_full_audit_fdopendir, .readdir = smb_full_audit_readdir, .seekdir = smb_full_audit_seekdir, .telldir = smb_full_audit_telldir, diff --git a/source3/modules/vfs_netatalk.c b/source3/modules/vfs_netatalk.c index d5a85b3390..734c603618 100644 --- a/source3/modules/vfs_netatalk.c +++ b/source3/modules/vfs_netatalk.c @@ -198,6 +198,31 @@ static SMB_STRUCT_DIR *atalk_opendir(struct vfs_handle_struct *handle, const cha return ret; } +static SMB_STRUCT_DIR *atalk_fdopendir(struct vfs_handle_struct *handle, files_struct *fsp, const char *mask, uint32 attr) +{ + SMB_STRUCT_DIR *ret = 0; + + ret = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr); + + if (ret == NULL) { + return ret; + } + + /* + * when we try to perform delete operation upon file which has fork + * in ./.AppleDouble and this directory wasn't hidden by Samba, + * MS Windows explorer causes the error: "Cannot find the specified file" + * There is some workaround to avoid this situation, i.e. if + * connection has not .AppleDouble entry in either veto or hide + * list then it would be nice to add one. + */ + + atalk_add_to_list(&handle->conn->hide_list); + atalk_add_to_list(&handle->conn->veto_list); + + return ret; +} + static int atalk_rmdir(struct vfs_handle_struct *handle, const char *path) { bool add = False; @@ -432,6 +457,7 @@ exit_lchown: static struct vfs_fn_pointers vfs_netatalk_fns = { .opendir = atalk_opendir, + .fdopendir = atalk_fdopendir, .rmdir = atalk_rmdir, .rename = atalk_rename, .unlink = atalk_unlink, diff --git a/source3/modules/vfs_scannedonly.c b/source3/modules/vfs_scannedonly.c index 123bf65fd4..fd6c3e2077 100644 --- a/source3/modules/vfs_scannedonly.c +++ b/source3/modules/vfs_scannedonly.c @@ -526,6 +526,35 @@ static SMB_STRUCT_DIR *scannedonly_opendir(vfs_handle_struct * handle, return (SMB_STRUCT_DIR *) sDIR; } +static SMB_STRUCT_DIR *scannedonly_fdopendir(vfs_handle_struct * handle, + files_struct *fsp, + const char *mask, uint32 attr) +{ + SMB_STRUCT_DIR *DIRp; + struct scannedonly_DIR *sDIR; + const char *fname; + + DIRp = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr); + if (!DIRp) { + return NULL; + } + + fname = (const char *)fsp->fsp_name->base_name; + + sDIR = TALLOC_P(NULL, struct scannedonly_DIR); + if (fname[0] != '/') { + sDIR->base = construct_full_path(sDIR,handle, fname, true); + } else { + sDIR->base = name_w_ending_slash(sDIR, fname); + } + DEBUG(SCANNEDONLY_DEBUG, + ("scannedonly_fdopendir, fname=%s, base=%s\n",fname,sDIR->base)); + sDIR->DIR = DIRp; + sDIR->notify_loop_done = 0; + return (SMB_STRUCT_DIR *) sDIR; +} + + static SMB_STRUCT_DIRENT *scannedonly_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR * dirp, SMB_STRUCT_STAT *sbuf) @@ -986,6 +1015,7 @@ static int scannedonly_connect(struct vfs_handle_struct *handle, /* VFS operations structure */ static struct vfs_fn_pointers vfs_scannedonly_fns = { .opendir = scannedonly_opendir, + .fdopendir = scannedonly_fdopendir, .readdir = scannedonly_readdir, .seekdir = scannedonly_seekdir, .telldir = scannedonly_telldir, diff --git a/source3/modules/vfs_shadow_copy.c b/source3/modules/vfs_shadow_copy.c index 6bad1686d9..b597644869 100644 --- a/source3/modules/vfs_shadow_copy.c +++ b/source3/modules/vfs_shadow_copy.c @@ -118,6 +118,58 @@ static SMB_STRUCT_DIR *shadow_copy_opendir(vfs_handle_struct *handle, const char return((SMB_STRUCT_DIR *)dirp); } +static SMB_STRUCT_DIR *shadow_copy_fdopendir(vfs_handle_struct *handle, files_struct *fsp, const char *mask, uint32 attr) +{ + shadow_copy_Dir *dirp; + SMB_STRUCT_DIR *p = SMB_VFS_NEXT_FDOPENDIR(handle,fsp,mask,attr); + + if (!p) { + DEBUG(10,("shadow_copy_opendir: SMB_VFS_NEXT_FDOPENDIR() failed for [%s]\n", + smb_fname_str_dbg(fsp->fsp_name))); + return NULL; + } + + dirp = SMB_MALLOC_P(shadow_copy_Dir); + if (!dirp) { + DEBUG(0,("shadow_copy_fdopendir: Out of memory\n")); + SMB_VFS_NEXT_CLOSEDIR(handle,p); + /* We have now closed the fd in fsp. */ + fsp->fh->fd = -1; + return NULL; + } + + ZERO_STRUCTP(dirp); + + while (True) { + SMB_STRUCT_DIRENT *d; + + d = SMB_VFS_NEXT_READDIR(handle, p, NULL); + if (d == NULL) { + break; + } + + if (shadow_copy_match_name(d->d_name)) { + DEBUG(8,("shadow_copy_fdopendir: hide [%s]\n",d->d_name)); + continue; + } + + DEBUG(10,("shadow_copy_fdopendir: not hide [%s]\n",d->d_name)); + + dirp->dirs = SMB_REALLOC_ARRAY(dirp->dirs,SMB_STRUCT_DIRENT, dirp->num+1); + if (!dirp->dirs) { + DEBUG(0,("shadow_copy_fdopendir: Out of memory\n")); + break; + } + + dirp->dirs[dirp->num++] = *d; + } + + SMB_VFS_NEXT_CLOSEDIR(handle,p); + /* We have now closed the fd in fsp. */ + fsp->fh->fd = -1; + return((SMB_STRUCT_DIR *)dirp); +} + static SMB_STRUCT_DIRENT *shadow_copy_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *_dirp, SMB_STRUCT_STAT *sbuf) @@ -216,6 +268,7 @@ static int shadow_copy_get_shadow_copy_data(vfs_handle_struct *handle, files_str static struct vfs_fn_pointers vfs_shadow_copy_fns = { .opendir = shadow_copy_opendir, + .fdopendir = shadow_copy_fdopendir, .readdir = shadow_copy_readdir, .seekdir = shadow_copy_seekdir, .telldir = shadow_copy_telldir, diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c index 136807f067..d692529a34 100644 --- a/source3/modules/vfs_time_audit.c +++ b/source3/modules/vfs_time_audit.c @@ -221,6 +221,26 @@ static SMB_STRUCT_DIR *smb_time_audit_opendir(vfs_handle_struct *handle, return result; } +static SMB_STRUCT_DIR *smb_time_audit_fdopendir(vfs_handle_struct *handle, + files_struct *fsp, + const char *mask, uint32 attr) +{ + SMB_STRUCT_DIR *result; + struct timespec ts1,ts2; + double timediff; + + clock_gettime_mono(&ts1); + result = SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr); + clock_gettime_mono(&ts2); + timediff = nsec_time_diff(&ts2,&ts1)*1.0e-9; + + if (timediff > audit_timeout) { + smb_time_audit_log("fdopendir", timediff); + } + + return result; +} + static SMB_STRUCT_DIRENT *smb_time_audit_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, SMB_STRUCT_STAT *sbuf) @@ -2324,6 +2344,7 @@ static struct vfs_fn_pointers vfs_time_audit_fns = { .statvfs = smb_time_audit_statvfs, .fs_capabilities = smb_time_audit_fs_capabilities, .opendir = smb_time_audit_opendir, + .fdopendir = smb_time_audit_fdopendir, .readdir = smb_time_audit_readdir, .seekdir = smb_time_audit_seekdir, .telldir = smb_time_audit_telldir, diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 32be699ef8..40aaf6bb74 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -1200,6 +1200,15 @@ SMB_STRUCT_DIR *smb_vfs_call_opendir(struct vfs_handle_struct *handle, return handle->fns->opendir(handle, fname, mask, attributes); } +SMB_STRUCT_DIR *smb_vfs_call_fdopendir(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const char *mask, + uint32 attributes) +{ + VFS_FIND(fdopendir); + return handle->fns->fdopendir(handle, fsp, mask, attributes); +} + SMB_STRUCT_DIRENT *smb_vfs_call_readdir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, SMB_STRUCT_STAT *sbuf) diff --git a/source3/utils/status_profile.c b/source3/utils/status_profile.c index ec0ea03806..198dac69a1 100644 --- a/source3/utils/status_profile.c +++ b/source3/utils/status_profile.c @@ -57,6 +57,8 @@ bool status_profile_dump(bool verbose) profile_separator("System Calls"); d_printf("opendir_count: %u\n", profile_p->syscall_opendir_count); d_printf("opendir_time: %u\n", profile_p->syscall_opendir_time); + d_printf("fdopendir_count: %u\n", profile_p->syscall_fdopendir_count); + d_printf("fdopendir_time: %u\n", profile_p->syscall_fdopendir_time); d_printf("readdir_count: %u\n", profile_p->syscall_readdir_count); d_printf("readdir_time: %u\n", profile_p->syscall_readdir_time); d_printf("mkdir_count: %u\n", profile_p->syscall_mkdir_count); -- cgit