From af0e199b31ea4132e369508d72888757887b3327 Mon Sep 17 00:00:00 2001 From: Steven Danneman Date: Thu, 22 Jan 2009 20:14:38 -0800 Subject: [PATCH] Add an optional SMB_STRUCT_SMB parameter to VFS_OP_READDIR * this allows VFS implementations that prefetch stat information on readdir to return it through one VFS call * backwards compatibility is maintained by passing in NULL * if the system readdir doesn't return stat info, the stat struct is set to invalid --- source3/include/vfs.h | 5 ++++- source3/include/vfs_macros.h | 8 +++---- source3/modules/onefs_streams.c | 2 +- source3/modules/vfs_cap.c | 2 +- source3/modules/vfs_catia.c | 5 +++-- source3/modules/vfs_default.c | 8 ++++++- source3/modules/vfs_full_audit.c | 7 +++--- source3/modules/vfs_shadow_copy.c | 4 ++-- source3/modules/vfs_shadow_copy2.c | 2 +- source3/modules/vfs_streams_depot.c | 2 +- source3/smbd/vfs.c | 4 ++-- source3/torture/cmd_vfs.c | 35 +++++++++++++++++++++++++++-- 12 files changed, 63 insertions(+), 21 deletions(-) diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 228f090600f..6aea0ae6a08 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -113,6 +113,7 @@ /* Leave at 25 - not yet released. Add create_file call. -- tprouty. */ /* Leave at 25 - not yet released. Add create time to ntimes. -- tstecher. */ /* Leave at 25 - not yet released. Add get_alloc_size call. -- tprouty. */ +/* Leave at 25 - not yet released. Add SMB_STRUCT_STAT to readdir. - sdann */ #define SMB_VFS_INTERFACE_VERSION 25 @@ -303,7 +304,9 @@ struct vfs_ops { /* Directory operations */ SMB_STRUCT_DIR *(*opendir)(struct vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attributes); - SMB_STRUCT_DIRENT *(*readdir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp); + SMB_STRUCT_DIRENT *(*readdir)(struct vfs_handle_struct *handle, + SMB_STRUCT_DIR *dirp, + SMB_STRUCT_STAT *sbuf); void (*seekdir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, long offset); long (*telldir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp); void (*rewind_dir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp); diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index e7a9cfdc764..208566f77e0 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -38,7 +38,7 @@ /* Directory operations */ #define SMB_VFS_OPENDIR(conn, fname, mask, attr) ((conn)->vfs.ops.opendir((conn)->vfs.handles.opendir, (fname), (mask), (attr))) -#define SMB_VFS_READDIR(conn, dirp) ((conn)->vfs.ops.readdir((conn)->vfs.handles.readdir, (dirp))) +#define SMB_VFS_READDIR(conn, dirp, sbuf) ((conn)->vfs.ops.readdir((conn)->vfs.handles.readdir, (dirp), (sbuf))) #define SMB_VFS_SEEKDIR(conn, dirp, offset) ((conn)->vfs.ops.seekdir((conn)->vfs.handles.seekdir, (dirp), (offset))) #define SMB_VFS_TELLDIR(conn, dirp) ((conn)->vfs.ops.telldir((conn)->vfs.handles.telldir, (dirp))) #define SMB_VFS_REWINDDIR(conn, dirp) ((conn)->vfs.ops.rewind_dir((conn)->vfs.handles.rewind_dir, (dirp))) @@ -166,7 +166,7 @@ /* Directory operations */ #define SMB_VFS_OPAQUE_OPENDIR(conn, fname, mask, attr) ((conn)->vfs_opaque.ops.opendir((conn)->vfs_opaque.handles.opendir, (fname), (mask), (attr))) -#define SMB_VFS_OPAQUE_READDIR(conn, dirp) ((conn)->vfs_opaque.ops.readdir((conn)->vfs_opaque.handles.readdir, (dirp))) +#define SMB_VFS_OPAQUE_READDIR(conn, dirp, sbuf) ((conn)->vfs_opaque.ops.readdir((conn)->vfs_opaque.handles.readdir, (dirp), (sbuf))) #define SMB_VFS_OPAQUE_SEEKDIR(conn, dirp, offset) ((conn)->vfs_opaque.ops.seekdir((conn)->vfs_opaque.handles.seekdir, (dirp), (offset))) #define SMB_VFS_OPAQUE_TELLDIR(conn, dirp) ((conn)->vfs_opaque.ops.telldir((conn)->vfs_opaque.handles.telldir, (dirp))) #define SMB_VFS_OPAQUE_REWINDDIR(conn, dirp) ((conn)->vfs_opaque.ops.rewind_dir((conn)->vfs_opaque.handles.rewind_dir, (dirp))) @@ -294,11 +294,11 @@ /* Directory operations */ #define SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr) ((handle)->vfs_next.ops.opendir((handle)->vfs_next.handles.opendir, (fname), (mask), (attr))) -#define SMB_VFS_NEXT_READDIR(handle, dirp) ((handle)->vfs_next.ops.readdir((handle)->vfs_next.handles.readdir, (dirp))) +#define SMB_VFS_NEXT_READDIR(handle, dirp, sbuf) ((handle)->vfs_next.ops.readdir((handle)->vfs_next.handles.readdir, (dirp), (sbuf))) #define SMB_VFS_NEXT_SEEKDIR(handle, dirp, offset) ((handle)->vfs_next.ops.seekdir((handle)->vfs_next.handles.seekdir, (dirp), (offset))) #define SMB_VFS_NEXT_TELLDIR(handle, dirp) ((handle)->vfs_next.ops.telldir((handle)->vfs_next.handles.telldir, (dirp))) #define SMB_VFS_NEXT_REWINDDIR(handle, dirp) ((handle)->vfs_next.ops.rewind_dir((handle)->vfs_next.handles.rewind_dir, (dirp))) -#define SMB_VFS_NEXT_DIR(handle, dirp) ((handle)->vfs_next.ops.readdir((handle)->vfs_next.handles.readdir, (dirp))) +#define SMB_VFS_NEXT_DIR(handle, dirp, sbuf) ((handle)->vfs_next.ops.readdir((handle)->vfs_next.handles.readdir, (dirp), (sbuf))) #define SMB_VFS_NEXT_MKDIR(handle, path, mode) ((handle)->vfs_next.ops.mkdir((handle)->vfs_next.handles.mkdir,(path), (mode))) #define SMB_VFS_NEXT_RMDIR(handle, path) ((handle)->vfs_next.ops.rmdir((handle)->vfs_next.handles.rmdir, (path))) #define SMB_VFS_NEXT_CLOSEDIR(handle, dir) ((handle)->vfs_next.ops.closedir((handle)->vfs_next.handles.closedir, dir)) diff --git a/source3/modules/onefs_streams.c b/source3/modules/onefs_streams.c index 615edf379d3..d0dd75f2590 100644 --- a/source3/modules/onefs_streams.c +++ b/source3/modules/onefs_streams.c @@ -545,7 +545,7 @@ static NTSTATUS walk_onefs_streams(connection_struct *conn, files_struct *fsp, fake_fs.fsp_name = SMB_STRDUP(fname); /* Iterate over the streams in the ADS directory. */ - while ((dp = SMB_VFS_READDIR(conn, dirp)) != NULL) { + while ((dp = SMB_VFS_READDIR(conn, dirp, NULL)) != NULL) { /* Skip the "." and ".." entries */ if ((strcmp(dp->d_name, ".") == 0) || (strcmp(dp->d_name, "..") == 0)) diff --git a/source3/modules/vfs_cap.c b/source3/modules/vfs_cap.c index ac85d3a8043..e26d29d6673 100644 --- a/source3/modules/vfs_cap.c +++ b/source3/modules/vfs_cap.c @@ -61,7 +61,7 @@ static SMB_STRUCT_DIRENT *cap_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR size_t newnamelen; DEBUG(3,("cap: cap_readdir\n")); - result = SMB_VFS_NEXT_READDIR(handle, dirp); + result = SMB_VFS_NEXT_READDIR(handle, dirp, NULL); if (!result) { return NULL; } diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c index d0c341fdd38..2870254bfbb 100644 --- a/source3/modules/vfs_catia.c +++ b/source3/modules/vfs_catia.c @@ -105,11 +105,12 @@ static SMB_STRUCT_DIR *catia_opendir(vfs_handle_struct *handle, static SMB_STRUCT_DIRENT *catia_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp) { - SMB_STRUCT_DIRENT *result = SMB_VFS_NEXT_READDIR(handle, dirp); - SMB_STRUCT_DIRENT *newdirent; + SMB_STRUCT_DIRENT *result = NULL; + SMB_STRUCT_DIRENT *newdirent = NULL; char *newname; size_t newnamelen; + result = SMB_VFS_NEXT_READDIR(handle, dirp, NULL); if (result == NULL) { return result; } diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 679be57558f..7d61191a697 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -113,12 +113,18 @@ static SMB_STRUCT_DIR *vfswrap_opendir(vfs_handle_struct *handle, const char *f return result; } -static SMB_STRUCT_DIRENT *vfswrap_readdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp) +static SMB_STRUCT_DIRENT *vfswrap_readdir(vfs_handle_struct *handle, + SMB_STRUCT_DIR *dirp, + SMB_STRUCT_STAT *sbuf) { SMB_STRUCT_DIRENT *result; START_PROFILE(syscall_readdir); result = sys_readdir(dirp); + /* Default Posix readdir() does not give us stat info. + * Set to invalid to indicate we didn't return this info. */ + if (sbuf) + SET_STAT_INVALID(*sbuf); END_PROFILE(syscall_readdir); return result; } diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index c6d62fdd879..e279772494d 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -94,7 +94,8 @@ static int smb_full_audit_statvfs(struct vfs_handle_struct *handle, static SMB_STRUCT_DIR *smb_full_audit_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr); static SMB_STRUCT_DIRENT *smb_full_audit_readdir(vfs_handle_struct *handle, - SMB_STRUCT_DIR *dirp); + SMB_STRUCT_DIR *dirp, + SMB_STRUCT_STAT *sbuf); static void smb_full_audit_seekdir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, long offset); static long smb_full_audit_telldir(vfs_handle_struct *handle, @@ -1029,11 +1030,11 @@ static SMB_STRUCT_DIR *smb_full_audit_opendir(vfs_handle_struct *handle, } static SMB_STRUCT_DIRENT *smb_full_audit_readdir(vfs_handle_struct *handle, - SMB_STRUCT_DIR *dirp) + SMB_STRUCT_DIR *dirp, SMB_STRUCT_STAT *sbuf) { SMB_STRUCT_DIRENT *result; - result = SMB_VFS_NEXT_READDIR(handle, dirp); + result = SMB_VFS_NEXT_READDIR(handle, dirp, sbuf); /* This operation has no reasonable error condition * (End of dir is also failure), so always succeed. diff --git a/source3/modules/vfs_shadow_copy.c b/source3/modules/vfs_shadow_copy.c index fbd2960abae..4f5cedb3d44 100644 --- a/source3/modules/vfs_shadow_copy.c +++ b/source3/modules/vfs_shadow_copy.c @@ -93,7 +93,7 @@ static SMB_STRUCT_DIR *shadow_copy_opendir(vfs_handle_struct *handle, const char while (True) { SMB_STRUCT_DIRENT *d; - d = SMB_VFS_NEXT_READDIR(handle, p); + d = SMB_VFS_NEXT_READDIR(handle, p, NULL); if (d == NULL) { break; } @@ -176,7 +176,7 @@ static int shadow_copy_get_shadow_copy_data(vfs_handle_struct *handle, files_str SHADOW_COPY_LABEL *tlabels; SMB_STRUCT_DIRENT *d; - d = SMB_VFS_NEXT_READDIR(handle, p); + d = SMB_VFS_NEXT_READDIR(handle, p, NULL); if (d == NULL) { break; } diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 56dd6ea8d87..9eaf8ee8512 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -524,7 +524,7 @@ static int shadow_copy2_get_shadow_copy2_data(vfs_handle_struct *handle, shadow_copy2_data->num_volumes = 0; shadow_copy2_data->labels = NULL; - while ((d = SMB_VFS_NEXT_READDIR(handle, p))) { + while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) { SHADOW_COPY_LABEL *tlabels; /* ignore names not of the right form in the snapshot directory */ diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c index 77efb277de0..1c2c0e5f77c 100644 --- a/source3/modules/vfs_streams_depot.c +++ b/source3/modules/vfs_streams_depot.c @@ -352,7 +352,7 @@ static NTSTATUS walk_streams(vfs_handle_struct *handle, return map_nt_error_from_unix(errno); } - while ((dirent = vfs_readdirname(handle->conn, dirhandle)) != NULL) { + while ((dirent = vfs_readdirname(handle->conn, dirhandle, NULL)) != NULL) { if (ISDOT(dirent) || ISDOTDOT(dirent)) { continue; diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 8d82ca550c5..95802473680 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -705,7 +705,7 @@ SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n) A vfs_readdir wrapper which just returns the file name. ********************************************************************/ -char *vfs_readdirname(connection_struct *conn, void *p) +char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf) { SMB_STRUCT_DIRENT *ptr= NULL; char *dname; @@ -713,7 +713,7 @@ char *vfs_readdirname(connection_struct *conn, void *p) if (!p) return(NULL); - ptr = SMB_VFS_READDIR(conn, (DIR *)p); + ptr = SMB_VFS_READDIR(conn, (DIR *)p, sbuf); if (!ptr) return(NULL); diff --git a/source3/torture/cmd_vfs.c b/source3/torture/cmd_vfs.c index 31eb27b7568..f273cedb90c 100644 --- a/source3/torture/cmd_vfs.c +++ b/source3/torture/cmd_vfs.c @@ -141,20 +141,51 @@ static NTSTATUS cmd_opendir(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc static NTSTATUS cmd_readdir(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv) { - SMB_STRUCT_DIRENT *dent; + const char *user; + const char *group; + SMB_STRUCT_STAT st; + SMB_STRUCT_DIRENT *dent = NULL; if (vfs->currentdir == NULL) { printf("readdir: error=-1 (no open directory)\n"); return NT_STATUS_UNSUCCESSFUL; } - dent = SMB_VFS_READDIR(vfs->conn, vfs->currentdir); + dent = SMB_VFS_READDIR(vfs->conn, vfs->currentdir, &st); if (dent == NULL) { printf("readdir: NULL\n"); return NT_STATUS_OK; } printf("readdir: %s\n", dent->d_name); + if (VALID_STAT(st)) { + printf(" stat available"); + if (S_ISREG(st.st_mode)) printf(" Regular File\n"); + else if (S_ISDIR(st.st_mode)) printf(" Directory\n"); + else if (S_ISCHR(st.st_mode)) printf(" Character Device\n"); + else if (S_ISBLK(st.st_mode)) printf(" Block Device\n"); + else if (S_ISFIFO(st.st_mode)) printf(" Fifo\n"); + else if (S_ISLNK(st.st_mode)) printf(" Symbolic Link\n"); + else if (S_ISSOCK(st.st_mode)) printf(" Socket\n"); + printf(" Size: %10u", (unsigned int)st.st_size); +#ifdef HAVE_STAT_ST_BLOCKS + printf(" Blocks: %9u", (unsigned int)st.st_blocks); +#endif +#ifdef HAVE_STAT_ST_BLKSIZE + printf(" IO Block: %u\n", (unsigned int)st.st_blksize); +#endif + printf(" Device: 0x%10x", (unsigned int)st.st_dev); + printf(" Inode: %10u", (unsigned int)st.st_ino); + printf(" Links: %10u\n", (unsigned int)st.st_nlink); + printf(" Access: %05o", (st.st_mode) & 007777); + printf(" Uid: %5lu/%.16s Gid: %5lu/%.16s\n", + (unsigned long)st.st_uid, user, + (unsigned long)st.st_gid, group); + printf(" Access: %s", ctime(&(st.st_atime))); + printf(" Modify: %s", ctime(&(st.st_mtime))); + printf(" Change: %s", ctime(&(st.st_ctime))); + } + return NT_STATUS_OK; }