The branch, master has been updated via 11f60a62a1d7633e9a8ec62da18ed9ababa694df (commit) via 6272f4c2f453c509b8a3893d4c2ac5fc356b348d (commit) via 25d345eb39c69b2b42a966846ae893b068de40a4 (commit) via af0e199b31ea4132e369508d72888757887b3327 (commit) from 9a7491e83177ba32e30f29e1b84b8b8be9888953 (commit)
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 11f60a62a1d7633e9a8ec62da18ed9ababa694df Author: Steven Danneman <steven.danne...@isilon.com> Date: Mon Jan 26 20:14:32 2009 -0800 s3: OneFS bulk directory enumeration support OneFS provides the bulk directory enumeration syscall readdirplus(). This syscall has the same semantics as the NFSv3 READDIRPLUS command, returning a batch of directory entries with prefetched stat information via one syscall. This commit wraps the readdirplus() call in the existing POSIX readdir/seekdir VFS interface. By default a batch of 128 directory entries are optimistically read from the kernel into a global cache, and fed to iterative calls of VFS_OP_READDIR. The global buffers could be avoided in the future by hanging connection specific buffers off the conn struct. Added new parameter "onefs:use readdirplus" which toggles usage of this code on or off. commit 6272f4c2f453c509b8a3893d4c2ac5fc356b348d Author: Steven Danneman <steven.danne...@isilon.com> Date: Mon Feb 2 21:37:51 2009 -0800 s3: Added SMB_VFS_INIT_SEARCH_OP to initialize data at the beginning of SMB search requests. By default this VFS call is a NOOP, but the onefs vfs module takes advantage of it to initialize direntry search caches at the beginning of each TRANS2_FIND_FIRST, TRANS2_FIND_NEXT, SMBffirst, SMBsearch, and SMBunique commit 25d345eb39c69b2b42a966846ae893b068de40a4 Author: Steven Danneman <steven.danne...@isilon.com> Date: Thu Jan 22 20:18:56 2009 -0800 Pass stat buffer down through all levels of VFS_READDIR wrappers * VFS_OP_READDIR can now provide stat information, take advantage of it if it's available * is_visible_file(): optimistically expect the provided stat buffer is already valid * dptr_ReadDirName(): refactor code for easier readability, functionality is the same commit af0e199b31ea4132e369508d72888757887b3327 Author: Steven Danneman <steven.danne...@isilon.com> Date: Thu Jan 22 20:14:38 2009 -0800 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 ----------------------------------------------------------------------- Summary of changes: source3/Makefile.in | 2 +- source3/include/proto.h | 6 +- source3/include/vfs.h | 15 +- source3/include/vfs_macros.h | 11 +- source3/modules/onefs.h | 46 ++- source3/modules/onefs_dir.c | 636 +++++++++++++++++++++++++++++++++++ source3/modules/onefs_streams.c | 2 +- source3/modules/vfs_cap.c | 2 +- source3/modules/vfs_catia.c | 5 +- source3/modules/vfs_default.c | 16 +- source3/modules/vfs_full_audit.c | 21 +- source3/modules/vfs_onefs.c | 24 ++- source3/modules/vfs_shadow_copy.c | 4 +- source3/modules/vfs_shadow_copy2.c | 2 +- source3/modules/vfs_streams_depot.c | 2 +- source3/smbd/dir.c | 180 ++++++----- source3/smbd/filename.c | 2 +- source3/smbd/msdfs.c | 4 +- source3/smbd/reply.c | 24 +- source3/smbd/trans2.c | 12 +- source3/smbd/vfs.c | 4 +- source3/torture/cmd_vfs.c | 35 ++- 22 files changed, 912 insertions(+), 143 deletions(-) create mode 100644 source3/modules/onefs_dir.c Changeset truncated at 500 lines: diff --git a/source3/Makefile.in b/source3/Makefile.in index 2049953..6e453c9 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -664,7 +664,7 @@ VFS_ACL_XATTR_OBJ = modules/vfs_acl_xattr.o VFS_ACL_TDB_OBJ = modules/vfs_acl_tdb.o VFS_SMB_TRAFFIC_ANALYZER_OBJ = modules/vfs_smb_traffic_analyzer.o VFS_ONEFS_OBJ = modules/vfs_onefs.o modules/onefs_acl.o modules/onefs_system.o \ - modules/onefs_open.o modules/onefs_streams.o + modules/onefs_open.o modules/onefs_streams.o modules/onefs_dir.c PERFCOUNT_ONEFS_OBJ = modules/perfcount_onefs.o PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o diff --git a/source3/include/proto.h b/source3/include/proto.h index 1566a01..849bed3 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -6495,6 +6495,7 @@ const char *dptr_ReadDirName(TALLOC_CTX *ctx, SMB_STRUCT_STAT *pst); bool dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst); void dptr_DirCacheAdd(struct dptr_struct *dptr, const char *name, long offset); +void dptr_init_search_op(struct dptr_struct *dptr); bool dptr_fill(char *buf1,unsigned int key); struct dptr_struct *dptr_fetch(char *buf,int *num); struct dptr_struct *dptr_fetch_lanman2(int dptr_num); @@ -6512,7 +6513,8 @@ bool get_dir_entry(TALLOC_CTX *ctx, bool is_visible_file(connection_struct *conn, const char *dir_path, const char *name, SMB_STRUCT_STAT *pst, bool use_veto); struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn, const char *name, const char *mask, uint32 attr); -const char *ReadDirName(struct smb_Dir *dirp, long *poffset); +const char *ReadDirName(struct smb_Dir *dirp, long *poffset, + SMB_STRUCT_STAT *sbuf); void RewindDir(struct smb_Dir *dirp, long *poffset); void SeekDir(struct smb_Dir *dirp, long offset); long TellDir(struct smb_Dir *dirp); @@ -7356,7 +7358,7 @@ int vfs_allocate_file_space(files_struct *fsp, uint64_t len); int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len); int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len); SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n); -char *vfs_readdirname(connection_struct *conn, void *p); +char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf); int vfs_ChDir(connection_struct *conn, const char *path); char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn); NTSTATUS check_reduced_name(connection_struct *conn, const char *fname); diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 228f090..f944c89 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -113,6 +113,8 @@ /* 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 */ +/* Leave at 25 - not yet released. Add init_search_op call. - sdann */ #define SMB_VFS_INTERFACE_VERSION 25 @@ -143,14 +145,14 @@ struct smb_file_time; /* Available VFS operations. These values must be in sync with vfs_ops struct - (struct vfs_fn_pointers and struct vfs_handle_pointers inside of struct vfs_ops). + (struct vfs_fn_pointers and struct vfs_handle_pointers inside of struct vfs_ops). In particular, if new operations are added to vfs_ops, appropriate constants should be added to vfs_op_type so that order of them kept same as in vfs_ops. */ typedef enum _vfs_op_type { SMB_VFS_OP_NOOP = -1, - + /* Disk operations */ SMB_VFS_OP_CONNECT = 0, @@ -172,6 +174,7 @@ typedef enum _vfs_op_type { SMB_VFS_OP_MKDIR, SMB_VFS_OP_RMDIR, SMB_VFS_OP_CLOSEDIR, + SMB_VFS_OP_INIT_SEARCH_OP, /* File operations */ @@ -249,7 +252,7 @@ typedef enum _vfs_op_type { SMB_VFS_OP_SYS_ACL_FREE_TEXT, SMB_VFS_OP_SYS_ACL_FREE_ACL, SMB_VFS_OP_SYS_ACL_FREE_QUALIFIER, - + /* EA operations. */ SMB_VFS_OP_GETXATTR, SMB_VFS_OP_LGETXATTR, @@ -303,13 +306,16 @@ 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); int (*mkdir)(struct vfs_handle_struct *handle, const char *path, mode_t mode); int (*rmdir)(struct vfs_handle_struct *handle, const char *path); int (*closedir)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dir); + void (*init_search_op)(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp); /* File operations */ @@ -481,6 +487,7 @@ struct vfs_ops { struct vfs_handle_struct *mkdir; struct vfs_handle_struct *rmdir; struct vfs_handle_struct *closedir; + struct vfs_handle_struct *init_search_op; /* File operations */ diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index e7a9cfd..e57cbd2 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -38,13 +38,14 @@ /* 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))) #define SMB_VFS_MKDIR(conn, path, mode) ((conn)->vfs.ops.mkdir((conn)->vfs.handles.mkdir,(path), (mode))) #define SMB_VFS_RMDIR(conn, path) ((conn)->vfs.ops.rmdir((conn)->vfs.handles.rmdir, (path))) #define SMB_VFS_CLOSEDIR(conn, dir) ((conn)->vfs.ops.closedir((conn)->vfs.handles.closedir, dir)) +#define SMB_VFS_INIT_SEARCH_OP(conn, dirp) ((conn)->vfs.ops.init_search_op((conn)->vfs.handles.init_search_op, (dirp))) /* File operations */ #define SMB_VFS_OPEN(conn, fname, fsp, flags, mode) (((conn)->vfs.ops.open)((conn)->vfs.handles.open, (fname), (fsp), (flags), (mode))) @@ -166,13 +167,14 @@ /* 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))) #define SMB_VFS_OPAQUE_MKDIR(conn, path, mode) ((conn)->vfs_opaque.ops.mkdir((conn)->vfs_opaque.handles.mkdir,(path), (mode))) #define SMB_VFS_OPAQUE_RMDIR(conn, path) ((conn)->vfs_opaque.ops.rmdir((conn)->vfs_opaque.handles.rmdir, (path))) #define SMB_VFS_OPAQUE_CLOSEDIR(conn, dir) ((conn)->vfs_opaque.ops.closedir((conn)->vfs_opaque.handles.closedir, dir)) +#define SMB_VFS_OPAQUE_INIT_SEARCH_OP(conn, dirp) ((conn)->vfs_opaque.ops.init_search_op((conn)->vfs_opaque.handles.init_search_op, (dirp))) /* File operations */ #define SMB_VFS_OPAQUE_OPEN(conn, fname, fsp, flags, mode) (((conn)->vfs_opaque.ops.open)((conn)->vfs_opaque.handles.open, (fname), (fsp), (flags), (mode))) @@ -294,14 +296,15 @@ /* 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)) +#define SMB_VFS_NEXT_INIT_SEARCH_OP(handle, dirp) ((handle)->vfs_next.ops.init_search_op((handle)->vfs_next.handles.init_search_op, (dirp))) /* File operations */ #define SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode) (((handle)->vfs_next.ops.open)((handle)->vfs_next.handles.open, (fname), (fsp), (flags), (mode))) diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h index c8f19f4..72be682 100644 --- a/source3/modules/onefs.h +++ b/source3/modules/onefs.h @@ -41,26 +41,28 @@ enum onefs_acl_wire_format #define PARM_ONEFS_TYPE "onefs" #define PARM_ACL_WIRE_FORMAT "acl wire format" #define PARM_ACL_WIRE_FORMAT_DEFAULT ACL_FORMAT_WINDOWS_SD -#define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE "simple file sharing compatibility mode" -#define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE_DEFAULT false +#define PARM_ATIME_NOW "atime now files" +#define PARM_ATIME_STATIC "atime static files" +#define PARM_ATIME_SLOP "atime now slop" #define PARM_CREATOR_OWNER_GETS_FULL_CONTROL "creator owner gets full control" #define PARM_CREATOR_OWNER_GETS_FULL_CONTROL_DEFAULT true +#define PARM_CTIME_NOW "ctime now files" +#define PARM_CTIME_SLOP "ctime now slop" +#define PARM_IGNORE_SACL "ignore sacl" +#define PARM_IGNORE_SACL_DEFAULT false +#define PARM_MTIME_NOW "mtime now files" +#define PARM_MTIME_STATIC "mtime static files" +#define PARM_MTIME_SLOP "mtime now slop" +#define PARM_USE_READDIRPLUS "use readdirplus" +#define PARM_USE_READDIRPLUS_DEFAULT true +#define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE "simple file sharing compatibility mode" +#define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE_DEFAULT false #define PARM_UNMAPPABLE_SIDS_DENY_EVERYONE "unmappable sids deny everyone" #define PARM_UNMAPPABLE_SIDS_DENY_EVERYONE_DEFAULT false #define PARM_UNMAPPABLE_SIDS_IGNORE "ignore unmappable sids" #define PARM_UNMAPPABLE_SIDS_IGNORE_DEFAULT false #define PARM_UNMAPPABLE_SIDS_IGNORE_LIST "unmappable sids ignore list" #define PARM_UNMAPPABLE_SIDS_IGNORE_LIST_DEFAULT NULL -#define PARM_IGNORE_SACL "ignore sacl" -#define PARM_IGNORE_SACL_DEFAULT false -#define PARM_ATIME_NOW "atime now files" -#define PARM_ATIME_SLOP "atime now slop" -#define PARM_CTIME_NOW "ctime now files" -#define PARM_CTIME_SLOP "ctime now slop" -#define PARM_MTIME_NOW "mtime now files" -#define PARM_MTIME_SLOP "mtime now slop" -#define PARM_MTIME_STATIC "mtime static files" -#define PARM_ATIME_STATIC "atime static files" #define IS_CTIME_NOW_PATH(conn,cfg,path) ((conn) && is_in_path((path),\ (cfg)->ctime_now_list,(conn)->case_sensitive)) @@ -81,7 +83,6 @@ enum onefs_acl_wire_format #define ONEFS_VFS_CONFIG_FAKETIMESTAMPS 0x00000001 - struct onefs_vfs_config { int32 init_flags; @@ -113,6 +114,25 @@ struct onefs_vfs_config /* * vfs interface handlers */ +SMB_STRUCT_DIR *onefs_opendir(struct vfs_handle_struct *handle, + const char *fname, const char *mask, + uint32 attributes); + +SMB_STRUCT_DIRENT *onefs_readdir(struct vfs_handle_struct *handle, + SMB_STRUCT_DIR *dirp, SMB_STRUCT_STAT *sbuf); + +void onefs_seekdir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp, + long offset); + +long onefs_telldir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp); + +void onefs_rewinddir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp); + +int onefs_closedir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *dir); + +void onefs_init_search_op(struct vfs_handle_struct *handle, + SMB_STRUCT_DIR *dirp); + NTSTATUS onefs_create_file(vfs_handle_struct *handle, struct smb_request *req, uint16_t root_dir_fid, diff --git a/source3/modules/onefs_dir.c b/source3/modules/onefs_dir.c new file mode 100644 index 0000000..3c1a836 --- /dev/null +++ b/source3/modules/onefs_dir.c @@ -0,0 +1,636 @@ +/* + * Unix SMB/CIFS implementation. + * + * Support for OneFS bulk directory enumeration API + * + * Copyright (C) Steven Danneman, 2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "onefs.h" + +#include <ifs/ifs_syscalls.h> + +/* The OneFS filesystem provides a readdirplus() syscall, equivalent to the + * NFSv3 PDU, which retrieves bulk directory listings with stat information + * in a single syscall. + * + * This file hides this bulk interface underneath Samba's very POSIX like + * opendir/readdir/telldir VFS interface. This is done to provide a + * significant performance improvement when listing the contents of large + * directories, which also require file meta information. ie a typical + * Windows Explorer request. + */ + +#define RDP_RESUME_KEY_START 0x1 + +#define RDP_BATCH_SIZE 128 +#define RDP_DIRENTRIES_SIZE ((size_t)(RDP_BATCH_SIZE * sizeof(struct dirent))) + +static char *rdp_direntries = NULL; +static SMB_STRUCT_STAT *rdp_stats = NULL; +static uint64_t *rdp_cookies = NULL; + +struct rdp_dir_state { + struct rdp_dir_state *next, *prev; + SMB_STRUCT_DIR *dirp; + char *direntries_cursor; /* cursor to current direntry in the cache */ + size_t stat_count; /* number of entries stored in the cache */ + size_t stat_cursor; /* cursor to current stat in the cache */ + uint64_t resume_cookie; /* last cookie returned from the cache */ + long location; /* absolute location of direnty in DIR */ +}; + +static struct rdp_dir_state *dirstatelist = NULL; + +SMB_STRUCT_DIR *rdp_last_dirp = NULL; + +/** + * Given a DIR pointer, return our internal state. + * + * This function also tells us whether the given DIR is the same as we saw + * during the last call. Because we use a single globally allocated buffer + * for readdirplus entries we must check every call into this API to see if + * it's for the same directory listing, or a new one. If it's the same we can + * maintain our current cached entries, otherwise we must go to the kernel. + * + * @return 0 on success, 1 on failure + */ +static int +rdp_retrieve_dir_state(SMB_STRUCT_DIR *dirp, struct rdp_dir_state **dir_state, + bool *same_as_last) +{ + struct rdp_dir_state *dsp; + + /* Is this directory the same as the last call */ + *same_as_last = (dirp == rdp_last_dirp); + + for(dsp = dirstatelist; dsp; dsp = dsp->next) + if (dsp->dirp == dirp) { + *dir_state = dsp; + return 0; + } + + /* Couldn't find existing dir_state for the given directory + * pointer. */ + return 1; +} + +/** + * Initialize the global readdirplus buffers. + * + * These same buffers are used for all calls into readdirplus. + * + * @return 0 on success, errno value on failure + */ +static int +rdp_init(struct rdp_dir_state *dsp) +{ + /* Unfortunately, there is no good way to free these buffers. If we + * allocated and freed for every DIR handle performance would be + * adversely affected. For now these buffers will be leaked and only + * freed when the smbd process dies. */ + if (!rdp_direntries) { + rdp_direntries = SMB_MALLOC(RDP_DIRENTRIES_SIZE); + if (!rdp_direntries) + return ENOMEM; + } + + if (!rdp_stats) { + rdp_stats = + SMB_MALLOC(RDP_BATCH_SIZE * sizeof(SMB_STRUCT_STAT)); + if (!rdp_stats) + return ENOMEM; + } + + if (!rdp_cookies) { + rdp_cookies = SMB_MALLOC(RDP_BATCH_SIZE * sizeof(uint64_t)); + if (!rdp_cookies) + return ENOMEM; + } + + dsp->direntries_cursor = rdp_direntries + RDP_DIRENTRIES_SIZE; + dsp->stat_count = RDP_BATCH_SIZE; + dsp->stat_cursor = RDP_BATCH_SIZE; + dsp->resume_cookie = RDP_RESUME_KEY_START; + dsp->location = 0; + + return 0; +} + +/** + * Call into readdirplus() to refill our global dirent cache. + * + * This function also resets all cursors back to the beginning of the cache. + * All stat buffers are retrieved by following symlinks. + * + * @return number of entries retrieved, -1 on error + */ +static int +rdp_fill_cache(struct rdp_dir_state *dsp) +{ + int nread, dirfd; + + dirfd = dirfd(dsp->dirp); + if (dirfd < 0) { + DEBUG(1, ("Could not retrieve fd for DIR\n")); + return -1; + } + + /* Resize the stat_count to grab as many entries as possible */ + dsp->stat_count = RDP_BATCH_SIZE; + + DEBUG(9, ("Calling readdirplus() with DIR %p, dirfd: %d, " + "resume_cookie 0x%llx, location %u, size_to_read: %zu, " + "direntries_size: %zu, stat_count: %u\n", + dsp->dirp, dirfd, dsp->resume_cookie, dsp->location, + RDP_BATCH_SIZE, RDP_DIRENTRIES_SIZE, dsp->stat_count)); + + nread = readdirplus(dirfd, + RDP_FOLLOW, + &dsp->resume_cookie, + RDP_BATCH_SIZE, + rdp_direntries, + RDP_DIRENTRIES_SIZE, + &dsp->stat_count, + rdp_stats, + rdp_cookies); + if (nread < 0) { + DEBUG(1, ("Error calling readdirplus(): %s\n", + strerror(errno))); + return -1; + } + + DEBUG(9, ("readdirplus() returned %u entries from DIR %p\n", + dsp->stat_count, dsp->dirp)); + + dsp->direntries_cursor = rdp_direntries; + dsp->stat_cursor = 0; + + return nread; +} + +/** + * Open a directory for enumeration. + * + * Create a state struct to track the state of this directory for the life + * of this open. + * + * @param[in] handle vfs handle given in most VFS calls + * @param[in] fname filename of the directory to open + * @param[in] mask unused + * @param[in] attr unused + * + * @return DIR pointer, NULL if directory does not exist, NULL on error + */ +SMB_STRUCT_DIR * +onefs_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, + uint32 attr) +{ + int ret = 0; + SMB_STRUCT_DIR *ret_dirp; + struct rdp_dir_state *dsp = NULL; + + /* Fallback to default system routines if readdirplus is disabled */ + if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE, + PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT)) + { + return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr); + } + + /* Create a struct dir_state */ + dsp = SMB_MALLOC_P(struct rdp_dir_state); + if (!dsp) { + DEBUG(0, ("Error allocating struct rdp_dir_state.\n")); + return NULL; + } + + /* Open the directory */ + ret_dirp = SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr); + if (!ret_dirp) { + DEBUG(3, ("Unable to open directory: %s\n", fname)); + return NULL; + } + + /* Initialize the dir_state structure and add it to the list */ + ret = rdp_init(dsp); + if (ret) { + DEBUG(0, ("Error initializing readdirplus() buffers: %s\n", + strerror(ret))); + return NULL; + } + + /* Set the SMB_STRUCT_DIR in the dsp */ + dsp->dirp = ret_dirp; + + DLIST_ADD(dirstatelist, dsp); + + DEBUG(9, ("Opened handle on directory: \"%s\", DIR %p\n", + fname, dsp->dirp)); + + return ret_dirp; +} -- Samba Shared Repository