s3: Fix streams enumeration bug in OneFS implementation
authorAravind Srinivasan <aravind.srinivasan@isilon.com>
Thu, 19 Feb 2009 01:36:25 +0000 (17:36 -0800)
committerSteven Danneman <steven.danneman@isilon.com>
Thu, 19 Feb 2009 04:49:31 +0000 (20:49 -0800)
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
source3/modules/onefs_dir.c
source3/modules/onefs_streams.c

index b979cfd7eb54781d9081a68f98783f95bca626aa..c002739f1f762a0f3b9f421a7fd5cb905f7dbeb8 100644 (file)
@@ -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
  */
index 3c1a8364beb82b6420e029f2b71935fde7f1a0aa..83622b2bcdabb848e32f452152edfefbabfe139d 100644 (file)
@@ -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;
 }
index d0dd75f259091a27d2e5766949860b7b2ac87d0c..9616ca48d568395855612015b5c074840335d45e 100644 (file)
@@ -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);