From 8e8aa27e1b1366c8c4e3cf6d8a681fec80cca858 Mon Sep 17 00:00:00 2001 From: Aravind Srinivasan Date: Wed, 18 Feb 2009 17:36:25 -0800 Subject: [PATCH] s3: Fix streams enumeration bug in OneFS implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, we didn’t call SMB_VFS_OPEN_DIR from the streams module, instead we called fdopendir(). As a result we failed to populate the dir_state list in the readdirplus module. So when we tried to view the stream data, we will always returned NULL. To solve this I separated onefs_opendir() and the initialization of the dir_state list. This is done by introducing a new utility function “onefs_rdp_add_dir_state()”, which initializes the dir_state structure and adds it to the dir_state list. This function is called from the streams module before calling readdir(). --- source3/modules/onefs.h | 3 ++ source3/modules/onefs_dir.c | 70 ++++++++++++++++++++++++--------- source3/modules/onefs_streams.c | 13 ++++++ 3 files changed, 68 insertions(+), 18 deletions(-) diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h index b979cfd7eb5..c002739f1f7 100644 --- a/source3/modules/onefs.h +++ b/source3/modules/onefs.h @@ -224,6 +224,9 @@ NTSTATUS onefs_split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname, bool onefs_get_config(int snum, int config_type, struct onefs_vfs_config *cfg); + +int onefs_rdp_add_dir_state(connection_struct *conn, SMB_STRUCT_DIR *dirp); + /* * System Interfaces */ diff --git a/source3/modules/onefs_dir.c b/source3/modules/onefs_dir.c index 3c1a8364beb..83622b2bcda 100644 --- a/source3/modules/onefs_dir.c +++ b/source3/modules/onefs_dir.c @@ -182,6 +182,54 @@ rdp_fill_cache(struct rdp_dir_state *dsp) return nread; } +/** + * Create a dir_state to track an open directory that we're enumerating. + * + * This utility function is globally accessible for use by other parts of the + * onefs.so module to initialize a dir_state when a directory is opened through + * a path other than the VFS layer. + * + * @return 0 on success and errno on failure + * + * @note: Callers of this function MUST cleanup the dir_state through a proper + * call to VFS_CLOSEDIR(). + */ +int +onefs_rdp_add_dir_state(connection_struct *conn, SMB_STRUCT_DIR *dirp) +{ + int ret = 0; + struct rdp_dir_state *dsp = NULL; + + /* No-op if readdirplus is disabled */ + if (!lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, + PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT)) + { + return 0; + } + + /* 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 ENOMEM; + } + + /* 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 ret; + } + + /* Set the SMB_STRUCT_DIR in the dsp */ + dsp->dirp = dirp; + + DLIST_ADD(dirstatelist, dsp); + + return 0; +} + /** * Open a directory for enumeration. * @@ -201,7 +249,6 @@ onefs_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, { 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, @@ -210,13 +257,6 @@ onefs_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, 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) { @@ -224,21 +264,15 @@ onefs_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, return NULL; } - /* Initialize the dir_state structure and add it to the list */ - ret = rdp_init(dsp); + /* Create the dir_state struct and add it to the list */ + ret = onefs_rdp_add_dir_state(handle->conn, ret_dirp); if (ret) { - DEBUG(0, ("Error initializing readdirplus() buffers: %s\n", - strerror(ret))); + DEBUG(0, ("Error adding dir_state to the list\n")); 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)); + fname, ret_dirp)); return ret_dirp; } diff --git a/source3/modules/onefs_streams.c b/source3/modules/onefs_streams.c index d0dd75f2590..9616ca48d56 100644 --- a/source3/modules/onefs_streams.c +++ b/source3/modules/onefs_streams.c @@ -540,6 +540,19 @@ static NTSTATUS walk_onefs_streams(connection_struct *conn, files_struct *fsp, goto out; } + /* Initialize the dir state struct and add it to the list. + * This is a layer violation, and really should be handled by a + * VFS_FDOPENDIR() call which would properly setup the dir state. + * But since this is all within the onefs.so module, we cheat for + * now and call directly into the readdirplus code. + * NOTE: This state MUST be freed by a proper VFS_CLOSEDIR() call. */ + ret = onefs_rdp_add_dir_state(conn, dirp); + if (ret) { + DEBUG(0, ("Error adding dir_state to the list\n")); + status = map_nt_error_from_unix(errno); + goto out; + } + fake_fs.conn = conn; fake_fs.fh = &fake_fh; fake_fs.fsp_name = SMB_STRDUP(fname);