You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2018/04/30 18:26:10 UTC

svn commit: r1830615 - in /subversion/branches/tree-api/subversion: include/private/svn_tree_impl.h include/svn_tree.h libsvn_client/list.c libsvn_ra/ra_trees.c libsvn_subr/tree.c

Author: julianfoad
Date: Mon Apr 30 18:26:10 2018
New Revision: 1830615

URL: http://svn.apache.org/viewvc?rev=1830615&view=rev
Log:
On the 'tree-api' branch: implement 'svn ls' using the tree API.

This changes only the client-side implementation of 'list'.

* subversion/include/private/svn_tree_impl.h,
  subversion/include/svn_tree.h,
  subversion/libsvn_subr/tree.c
  Add a 'get dirent' method. Fix a bug in the walker.

* subversion/libsvn_client/list.c
  (list_internal,
   get_dir_contents): Delete.
  (list_baton_t,
   list_callback): New.
  (list_internal): Use tree walker.

* subversion/libsvn_ra/ra_trees.c
  Cache the results.

Modified:
    subversion/branches/tree-api/subversion/include/private/svn_tree_impl.h
    subversion/branches/tree-api/subversion/include/svn_tree.h
    subversion/branches/tree-api/subversion/libsvn_client/list.c
    subversion/branches/tree-api/subversion/libsvn_ra/ra_trees.c
    subversion/branches/tree-api/subversion/libsvn_subr/tree.c

Modified: subversion/branches/tree-api/subversion/include/private/svn_tree_impl.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-api/subversion/include/private/svn_tree_impl.h?rev=1830615&r1=1830614&r2=1830615&view=diff
==============================================================================
--- subversion/branches/tree-api/subversion/include/private/svn_tree_impl.h (original)
+++ subversion/branches/tree-api/subversion/include/private/svn_tree_impl.h Mon Apr 30 18:26:10 2018
@@ -94,6 +94,12 @@ typedef struct svn_tree_node__vtable_t
                            apr_hash_t **props,
                            apr_pool_t *result_pool,
                            apr_pool_t *scratch_pool);
+
+  /* See svn_tree_node_get_dirent(). */
+  svn_error_t *(*get_dirent)(svn_tree_node_t *node,
+                             svn_dirent_t **dirent,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool);
 } svn_tree_node__vtable_t;
 
 /** The implementation of the typedef #svn_tree_t. */

Modified: subversion/branches/tree-api/subversion/include/svn_tree.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-api/subversion/include/svn_tree.h?rev=1830615&r1=1830614&r2=1830615&view=diff
==============================================================================
--- subversion/branches/tree-api/subversion/include/svn_tree.h (original)
+++ subversion/branches/tree-api/subversion/include/svn_tree.h Mon Apr 30 18:26:10 2018
@@ -60,15 +60,16 @@ svn_tree_get_node_by_relpath(svn_tree_no
  *
  * The callback receives one directory node being visited, @a dir_node, and
  * the closure @a dir_visit_baton.  It also receives two lists of nodes
- * which together contain all the children to be visited.  The
+ * which together contain all the child nodes to be visited: the
  * subdirectories are in @a subdirs, and the non-directory children in @a
- * files.
+ * files.  Each of these lists is in lexicographical order of child names.
  *
  * This is modeled on Python's 'os.walk' function.
  *
  * ### TODO? "The callback may modify the list of subdirs (in place) in
  * order to influence the order and scope of traversal: the walker will
  * recurse into the subdirs that are in the list when the callback returns."
+ * Altering @a files has no effect.
  *
  * @a scratch_pool is available for use within the function until it returns.
  */
@@ -258,6 +259,14 @@ svn_tree_node_read_dir(svn_tree_node_t *
                        apr_pool_t *result_pool,
                        apr_pool_t *scratch_pool);
 
+/** Fetch the 'dirent' information ...
+ */
+svn_error_t *
+svn_tree_node_get_dirent(svn_tree_node_t *node,
+                         svn_dirent_t **dirent_p,
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool);
+
 
 #ifdef __cplusplus
 }

Modified: subversion/branches/tree-api/subversion/libsvn_client/list.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-api/subversion/libsvn_client/list.c?rev=1830615&r1=1830614&r2=1830615&view=diff
==============================================================================
--- subversion/branches/tree-api/subversion/libsvn_client/list.c (original)
+++ subversion/branches/tree-api/subversion/libsvn_client/list.c Mon Apr 30 18:26:10 2018
@@ -31,6 +31,7 @@
 #include "svn_time.h"
 #include "svn_sorts.h"
 #include "svn_props.h"
+#include "svn_tree.h"
 
 #include "client.h"
 
@@ -53,22 +54,6 @@ list_externals(apr_hash_t *externals,
                svn_client_ctx_t *ctx,
                apr_pool_t *scratch_pool);
 
-static svn_error_t *
-list_internal(const char *path_or_url,
-              const svn_opt_revision_t *peg_revision,
-              const svn_opt_revision_t *revision,
-              const apr_array_header_t *patterns,
-              svn_depth_t depth,
-              apr_uint32_t dirent_fields,
-              svn_boolean_t fetch_locks,
-              svn_boolean_t include_externals,
-              const char *external_parent_url,
-              const char *external_target,
-              svn_client_list_func2_t list_func,
-              void *baton,
-              svn_client_ctx_t *ctx,
-              apr_pool_t *pool);
-
 /* Return TRUE if S matches any of the const char * in PATTERNS.
  * Note that any S will match if PATTERNS is empty.
  * Use SCRATCH_BUFFER for temporary string contents. */
@@ -82,142 +67,6 @@ match_patterns(const char *s,
        : TRUE;
 }
 
-/* Get the directory entries of DIR at REV (relative to the root of
-   RA_SESSION), getting at least the fields specified by DIRENT_FIELDS.
-   Use the cancellation function/baton of CTX to check for cancellation.
-
-   If DEPTH is svn_depth_empty, return immediately.  If DEPTH is
-   svn_depth_files, invoke LIST_FUNC on the file entries with BATON;
-   if svn_depth_immediates, invoke it on file and directory entries;
-   if svn_depth_infinity, invoke it on file and directory entries and
-   recurse into the directory entries with the same depth.
-
-   If PATTERNS is not empty, the last path segments must match at least
-   one of const char * patterns in it or the respective dirent will not
-   be reported.
-
-   LOCKS, if non-NULL, is a hash mapping const char * paths to svn_lock_t
-   objects and FS_PATH is the absolute filesystem path of the RA session.
-   Use SCRATCH_POOL for temporary allocations.
-
-   If the caller passes EXTERNALS as non-NULL, populate the EXTERNALS
-   hash table whose keys are URLs of the directory which has externals
-   definitions, and whose values are the externals description text.
-   Allocate the hash's keys and values in RESULT_POOL.
-
-   EXTERNAL_PARENT_URL and EXTERNAL_TARGET are set when external items
-   are listed, otherwise both are set to NULL by the caller.
-
-   Use SCRATCH_BUFFER for temporary string contents.
-*/
-static svn_error_t *
-get_dir_contents(apr_uint32_t dirent_fields,
-                 const char *dir,
-                 svn_revnum_t rev,
-                 svn_ra_session_t *ra_session,
-                 apr_hash_t *locks,
-                 const char *fs_path,
-                 const apr_array_header_t *patterns,
-                 svn_depth_t depth,
-                 svn_client_ctx_t *ctx,
-                 apr_hash_t *externals,
-                 const char *external_parent_url,
-                 const char *external_target,
-                 svn_client_list_func2_t list_func,
-                 void *baton,
-                 svn_membuf_t *scratch_buffer,
-                 apr_pool_t *result_pool,
-                 apr_pool_t *scratch_pool)
-{
-  apr_hash_t *tmpdirents;
-  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-  apr_array_header_t *array;
-  svn_error_t *err;
-  apr_hash_t *prop_hash = NULL;
-  const svn_string_t *prop_val = NULL;
-  int i;
-
-  if (depth == svn_depth_empty)
-    return SVN_NO_ERROR;
-
-  /* Get the directory's entries. If externals hash is non-NULL, get its
-     properties also. Ignore any not-authorized errors.  */
-  err = svn_ra_get_dir2(ra_session, &tmpdirents, NULL,
-                        externals ? &prop_hash : NULL,
-                        dir, rev, dirent_fields, scratch_pool);
-
-  if (err && ((err->apr_err == SVN_ERR_RA_NOT_AUTHORIZED) ||
-              (err->apr_err == SVN_ERR_RA_DAV_FORBIDDEN)))
-    {
-      svn_error_clear(err);
-      return SVN_NO_ERROR;
-    }
-  SVN_ERR(err);
-
- /* Locks will often be empty.  Prevent pointless lookups in that case. */
- if (locks && apr_hash_count(locks) == 0)
-   locks = NULL;
-
- /* Filter out svn:externals from all properties hash. */
-  if (prop_hash)
-    prop_val = svn_hash_gets(prop_hash, SVN_PROP_EXTERNALS);
-  if (prop_val)
-    {
-      const char *url;
-
-      SVN_ERR(svn_ra_get_session_url(ra_session, &url, scratch_pool));
-
-      svn_hash_sets(externals,
-                    svn_path_url_add_component2(url, dir, result_pool),
-                    svn_string_dup(prop_val, result_pool));
-    }
-
-  if (ctx->cancel_func)
-    SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
-
-  /* Sort the hash, so we can call the callback in a "deterministic" order. */
-  array = svn_sort__hash(tmpdirents, svn_sort_compare_items_lexically,
-                         scratch_pool);
-  for (i = 0; i < array->nelts; ++i)
-    {
-      svn_sort__item_t *item = &APR_ARRAY_IDX(array, i, svn_sort__item_t);
-      const char *path;
-      svn_dirent_t *the_ent = item->value;
-      svn_lock_t *lock;
-
-      svn_pool_clear(iterpool);
-
-      path = svn_relpath_join(dir, item->key, iterpool);
-
-      if (locks)
-        {
-          const char *abs_path = svn_fspath__join(fs_path, path, iterpool);
-          lock = svn_hash_gets(locks, abs_path);
-        }
-      else
-        lock = NULL;
-
-      if (the_ent->kind == svn_node_file
-          || depth == svn_depth_immediates
-          || depth == svn_depth_infinity)
-        if (match_patterns(item->key, patterns, scratch_buffer))
-          SVN_ERR(list_func(baton, path, the_ent, lock, fs_path,
-                            external_parent_url, external_target, iterpool));
-
-      /* If externals is non-NULL, populate the externals hash table
-         recursively for all directory entries. */
-      if (depth == svn_depth_infinity && the_ent->kind == svn_node_dir)
-        SVN_ERR(get_dir_contents(dirent_fields, path, rev, ra_session,
-                                 locks, fs_path, patterns, depth, ctx,
-                                 externals, external_parent_url,
-                                 external_target, list_func, baton,
-                                 scratch_buffer, result_pool, iterpool));
-    }
-
-  svn_pool_destroy(iterpool);
-  return SVN_NO_ERROR;
-}
-
 /* Baton type to be used with list_receiver. */
 typedef struct receiver_baton_t
 {
@@ -266,6 +115,85 @@ list_receiver(const char *rel_path,
   return SVN_NO_ERROR;
 }
 
+/* Info for list_callback(). */
+struct list_baton_t
+{
+  /* The absolute filesystem path of the RA session. */
+  const char *fs_path;
+  apr_uint32_t dirent_fields;
+  /* If non-NULL, maps (const char *) paths to svn_lock_t objects. */
+  apr_hash_t *locks;
+  svn_client_list_func2_t list_func;
+  void *list_baton;
+  const apr_array_header_t *patterns;
+  svn_membuf_t *scratch_buffer;
+
+  const char *session_root_url;
+  apr_hash_t *externals;
+  const char *external_parent_url;
+  const char *external_target;
+
+  svn_boolean_t any_node_found;
+};
+
+/* List the entries in DIR_NODE.
+ * An svn_tree_walk_dir_callback function.
+ */
+static svn_error_t *list_callback(svn_tree_node_t *node,
+                                  void *baton,
+                                  apr_pool_t *scratch_pool)
+{
+  struct list_baton_t *lb = baton;
+  const char *relpath;
+  const char *basename;
+  svn_dirent_t *dirent;
+
+  lb->any_node_found = TRUE;
+
+  SVN_ERR(svn_tree_node_get_relpath(node, &relpath, scratch_pool, scratch_pool));
+  basename = svn_relpath_basename(relpath, scratch_pool);
+  SVN_ERR(svn_tree_node_get_dirent(node, &dirent, scratch_pool, scratch_pool));
+
+  if (match_patterns(basename, lb->patterns, lb->scratch_buffer))
+    {
+      svn_lock_t *lock = NULL;
+
+      if (lb->locks)
+        {
+          const char *abs_fspath = svn_fspath__join(lb->fs_path, relpath,
+                                                    scratch_pool);
+          lock = apr_hash_get(lb->locks, abs_fspath, APR_HASH_KEY_STRING);
+        }
+
+      SVN_ERR(lb->list_func(lb->list_baton, relpath, dirent, lock,
+                            lb->fs_path,
+                            lb->external_parent_url, lb->external_target,
+                            scratch_pool));
+    }
+
+  /* Collect any 'externals' definitions if this is a directory */
+  if (lb->externals && dirent->kind == svn_node_dir)
+    {
+      apr_hash_t *prop_hash = NULL;
+      const svn_string_t *prop_val = NULL;
+
+      SVN_ERR(svn_tree_node_read_dir(node, NULL /*children*/, &prop_hash,
+                                     scratch_pool, scratch_pool));
+      prop_val = svn_hash_gets(prop_hash, SVN_PROP_EXTERNALS);
+      if (prop_val)
+        {
+          apr_pool_t *pool = apr_hash_pool_get(lb->externals);
+
+          svn_hash_sets(lb->externals,
+                        svn_path_url_add_component2(lb->session_root_url,
+                                                    relpath, pool),
+                        svn_string_dup(prop_val, pool));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* List the file/directory entries for PATH_OR_URL at REVISION.
    The actual node revision selected is determined by the path as
    it exists in PEG_REVISION.
@@ -321,7 +249,6 @@ list_internal(const char *path_or_url,
 {
   svn_ra_session_t *ra_session;
   svn_client__pathrev_t *loc;
-  svn_dirent_t *dirent;
   const char *fs_path;
   svn_error_t *err;
   apr_hash_t *locks;
@@ -333,10 +260,6 @@ list_internal(const char *path_or_url,
   else
     externals = NULL;
 
-  /* We use the kind field to determine if we should recurse, so we
-     always need it. */
-  dirent_fields |= SVN_DIRENT_KIND;
-
   /* Get an RA plugin for this filesystem object. */
   SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
                                             path_or_url, NULL,
@@ -382,33 +305,37 @@ list_internal(const char *path_or_url,
         return svn_error_trace(err);
     }
 
-  /* Stat for the file / directory node itself. */
-  SVN_ERR(svn_ra_stat(ra_session, "", loc->rev, &dirent, pool));
-  if (! dirent)
-    return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
-                             _("URL '%s' non-existent in revision %ld"),
-                             loc->url, loc->rev);
-
   /* We need a scratch buffer for temporary string data.
    * Create one with a reasonable initial size. */
   svn_membuf__create(&scratch_buffer, 256, pool);
 
-  /* Report the dirent for the target. */
-  if (match_patterns(svn_dirent_dirname(fs_path, pool), patterns,
-                     &scratch_buffer))
-    SVN_ERR(list_func(baton, "", dirent, locks
-                      ? (svn_hash_gets(locks, fs_path))
-                      : NULL, fs_path, external_parent_url,
-                      external_target, pool));
-
-  if (dirent->kind == svn_node_dir
-      && (depth == svn_depth_files
-          || depth == svn_depth_immediates
-          || depth == svn_depth_infinity))
-    SVN_ERR(get_dir_contents(dirent_fields, "", loc->rev, ra_session, locks,
-                             fs_path, patterns, depth, ctx, externals,
-                             external_parent_url, external_target, list_func,
-                             baton, &scratch_buffer, pool, pool));
+  /* Walk the tree */
+  {
+    struct list_baton_t lb;
+    svn_tree_t *tree;
+
+    lb.fs_path = fs_path;
+    lb.dirent_fields = dirent_fields;
+    lb.locks = locks;
+    lb.list_func = list_func;
+    lb.list_baton = baton;
+    lb.patterns = patterns;
+    lb.scratch_buffer = &scratch_buffer;
+    lb.session_root_url = loc->url;
+    lb.externals = externals;
+    lb.external_parent_url = external_parent_url;
+    lb.external_target = external_target;
+    lb.any_node_found = FALSE;
+
+    SVN_ERR(svn_ra__open_tree(&tree, ra_session, loc->rev, pool));
+
+    SVN_ERR(svn_tree_walk(tree, depth, list_callback, &lb,
+                          ctx->cancel_func, ctx->cancel_baton, pool));
+    if (!lb.any_node_found)
+      return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
+                               _("URL '%s' non-existent in revision %ld"),
+                               loc->url, loc->rev);
+  }
 
   /* We handle externals after listing entries under path_or_url, so that
      handling external items (and any errors therefrom) doesn't delay

Modified: subversion/branches/tree-api/subversion/libsvn_ra/ra_trees.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-api/subversion/libsvn_ra/ra_trees.c?rev=1830615&r1=1830614&r2=1830615&view=diff
==============================================================================
--- subversion/branches/tree-api/subversion/libsvn_ra/ra_trees.c (original)
+++ subversion/branches/tree-api/subversion/libsvn_ra/ra_trees.c Mon Apr 30 18:26:10 2018
@@ -61,6 +61,10 @@ typedef struct ra_tree_node_baton_t
   svn_tree_t *tree;
   ra_tree_baton_t *tb;
   const char *relpath;
+  svn_dirent_t *dirent;  /* null until fetched/known */
+  apr_hash_t *children;  /* null until fetched/known */
+  apr_hash_t *props;  /* null until fetched/known */
+  apr_pool_t *pool;
 } ra_tree_node_baton_t;
 
 /* Forward declaration */
@@ -77,7 +81,25 @@ ra_tree_get_node_by_relpath(svn_tree_nod
                             apr_pool_t *result_pool,
                             apr_pool_t *scratch_pool)
 {
-  *node = ra_tree_node_create(tree, relpath, result_pool);
+  *node = ra_tree_node_create(tree, apr_pstrdup(result_pool, relpath),
+                              result_pool);
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+fetch_dirent(svn_tree_node_t *node,
+             apr_pool_t *scratch_pool)
+{
+  ra_tree_node_baton_t *nb = node->priv;
+
+  if (nb->dirent == NULL)
+    {
+      SVN_ERR(ra_unauthz_err(svn_ra_stat(nb->tb->ra_session, nb->relpath,
+                                         nb->tb->revnum, &nb->dirent,
+                                         nb->pool)));
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -102,9 +124,11 @@ ra_treen_get_kind(svn_tree_node_t *node,
 {
   ra_tree_node_baton_t *nb = node->priv;
 
-  SVN_ERR(ra_unauthz_err(svn_ra_check_path(nb->tb->ra_session, nb->relpath,
-                                           nb->tb->revnum, kind,
-                                           scratch_pool)));
+  if (kind)
+    {
+      SVN_ERR(fetch_dirent(node, scratch_pool));
+      *kind = nb->dirent->kind;
+    }
   return SVN_NO_ERROR;
 }
 
@@ -127,16 +151,23 @@ ra_treen_read_file(svn_tree_node_t *node
                                      result_pool, scratch_pool));
       SVN_ERR(ra_unauthz_err(svn_ra_get_file(nb->tb->ra_session, nb->relpath,
                                              nb->tb->revnum, *stream,
-                                             NULL, props, result_pool)));
+                                             NULL,
+                                             nb->props ? NULL : &nb->props,
+                                             nb->pool)));
       SVN_ERR(svn_stream_reset(*stream));
     }
-  else
+  else if (props)
     {
       /* Just get the properties. */
-      SVN_ERR(ra_unauthz_err(svn_ra_get_file(nb->tb->ra_session, nb->relpath,
-                                             nb->tb->revnum, NULL,
-                                             NULL, props, result_pool)));
+      if (! nb->props)
+        {
+          SVN_ERR(ra_unauthz_err(svn_ra_get_file(nb->tb->ra_session, nb->relpath,
+                                                 nb->tb->revnum, NULL,
+                                                 NULL, &nb->props, nb->pool)));
+        }
     }
+  if (props)
+    *props = nb->props;
   return SVN_NO_ERROR;
 }
 
@@ -149,38 +180,67 @@ ra_treen_read_dir(svn_tree_node_t *node,
                   apr_pool_t *scratch_pool)
 {
   ra_tree_node_baton_t *nb = node->priv;
-  apr_hash_t *dirents;
 
-  SVN_ERR(ra_unauthz_err(svn_ra_get_dir2(nb->tb->ra_session,
-                                         children_p ? &dirents : NULL,
-                                         NULL, props,
-                                         nb->relpath, nb->tb->revnum,
-                                         0 /* dirent_fields */,
-                                         result_pool)));
-
-  /* Convert RA dirents to tree children */
-  if (children_p)
+  if ((children_p && ! nb->children)
+      || (props && ! nb->props))
     {
-      apr_hash_t *children = apr_hash_make(result_pool);
-      apr_hash_index_t *hi;
+      apr_hash_t *dirents = NULL;
 
-      for (hi = apr_hash_first(scratch_pool, dirents); hi;
-           hi = apr_hash_next(hi))
+      SVN_ERR(ra_unauthz_err(svn_ra_get_dir2(nb->tb->ra_session,
+                                             nb->children ? NULL : &dirents,
+                                             NULL, &nb->props,
+                                             nb->relpath, nb->tb->revnum,
+                                             SVN_DIRENT_ALL,
+                                             nb->pool)));
+
+      /* Convert RA dirents to tree children */
+      if (! nb->children)
         {
-          const char *name = apr_hash_this_key(hi);
-          const char *relpath = svn_relpath_join(nb->relpath, name, result_pool);
-          svn_tree_node_t *child;
+          apr_hash_index_t *hi;
 
-          child = ra_tree_node_create(nb->tree, relpath, result_pool);
-          apr_hash_set(children, name, APR_HASH_KEY_STRING, child);
+          nb->children = apr_hash_make(nb->pool);
+          for (hi = apr_hash_first(scratch_pool, dirents); hi;
+               hi = apr_hash_next(hi))
+            {
+              const char *name = apr_hash_this_key(hi);
+              svn_dirent_t *dirent = apr_hash_this_val(hi);
+              const char *relpath = svn_relpath_join(nb->relpath, name, nb->pool);
+              svn_tree_node_t *child;
+              ra_tree_node_baton_t *cb;
+
+              child = ra_tree_node_create(nb->tree, relpath, nb->pool);
+              cb = child->priv;
+              cb->dirent = dirent;
+              apr_hash_set(nb->children, name, APR_HASH_KEY_STRING, child);
+            }
         }
-      *children_p = children;
     }
+  if (children_p)
+    *children_p = nb->children;
+  if (props)
+    *props = nb->props;
 
   return SVN_NO_ERROR;
 }
 
 /* */
+static svn_error_t *
+ra_treen_get_dirent(svn_tree_node_t *node,
+                    svn_dirent_t **dirent,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
+{
+  ra_tree_node_baton_t *nb = node->priv;
+
+  if (dirent)
+    {
+      SVN_ERR(fetch_dirent(node, scratch_pool));
+      *dirent = nb->dirent;
+    }
+  return SVN_NO_ERROR;
+}
+
+/* */
 static const svn_tree__vtable_t ra_tree_vtable =
 {
   ra_tree_get_node_by_relpath
@@ -192,10 +252,13 @@ static const svn_tree_node__vtable_t ra_
   ra_treen_get_relpath,
   ra_treen_get_kind,
   ra_treen_read_file,
-  ra_treen_read_dir
+  ra_treen_read_dir,
+  ra_treen_get_dirent
 };
 
-/* */
+/* Return a new node in RESULT_POOL.
+ * RELPATH must be already allocated in RESULT_POOL.
+ */
 static svn_tree_node_t *
 ra_tree_node_create(svn_tree_t *tree,
                     const char *relpath,
@@ -206,6 +269,10 @@ ra_tree_node_create(svn_tree_t *tree,
   nb->tree = tree;
   nb->tb = tree->priv;
   nb->relpath = relpath;
+  nb->dirent = NULL;
+  nb->children = NULL;
+  nb->props = NULL;
+  nb->pool = result_pool;
   return svn_tree_node_create(&ra_tree_node_vtable, nb, result_pool);
 }
 

Modified: subversion/branches/tree-api/subversion/libsvn_subr/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-api/subversion/libsvn_subr/tree.c?rev=1830615&r1=1830614&r2=1830615&view=diff
==============================================================================
--- subversion/branches/tree-api/subversion/libsvn_subr/tree.c (original)
+++ subversion/branches/tree-api/subversion/libsvn_subr/tree.c Mon Apr 30 18:26:10 2018
@@ -157,9 +157,8 @@ walk_dirs(svn_tree_node_t *dir_node,
   /* Recurse */
   for (i = 0; i < dirs->nelts; i++)
     {
-      const svn_sort__item_t *item
-        = &APR_ARRAY_IDX(dirs, i, svn_sort__item_t);
-      svn_tree_node_t *child = item->value;
+      svn_tree_node_t *child
+        = APR_ARRAY_IDX(dirs, i, svn_tree_node_t *);
 
       svn_pool_clear(iterpool);
       SVN_ERR(walk_dirs(child,
@@ -247,7 +246,7 @@ svn_tree_walk(svn_tree_t *tree,
       SVN_ERR(walk_dirs(node, depth, per_dir_to_per_node_cb, &b,
                         cancel_func, cancel_baton, scratch_pool));
     }
-  else
+  else if (kind == svn_node_file)
     {
       SVN_ERR(walk_func(node, walk_baton, scratch_pool));
     }
@@ -472,3 +471,14 @@ svn_tree_node_read_dir(svn_tree_node_t *
   return node->vtable->read_dir(node, children, props,
                                 result_pool, scratch_pool);
 }
+
+svn_error_t *
+svn_tree_node_get_dirent(svn_tree_node_t *node,
+                         svn_dirent_t **dirent_p,
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool)
+{
+  SVN_ERR(node->vtable->get_dirent(node, dirent_p,
+                                   result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}