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 2012/11/07 17:33:29 UTC

svn commit: r1406709 - in /subversion/branches/tree-read-api/subversion: include/ include/private/ libsvn_ra/ libsvn_subr/ libsvn_wc/

Author: julianfoad
Date: Wed Nov  7 16:33:29 2012
New Revision: 1406709

URL: http://svn.apache.org/viewvc?rev=1406709&view=rev
Log:
On the 'tree-read-api' branch: Add an initial version of the tree API.

* subversion/include/svn_types.h
  (svn_tree_t, svn_tree_node_t): New types.

* subversion/include/svn_tree.h
  New file, with the public functions operating on trees and tree nodes.

* subversion/include/private/svn_tree_impl.h
  New file, with the declarations needed by tree implementors.

* subversion/include/private/svn_ra_private.h
  (svn_ra__open_tree): New functions.

* subversion/include/private/svn_subr_private.h
  (svn_io__open_tree): New functions.

* subversion/include/private/svn_wc_private.h
  (svn_wc__open_base_tree, svn_wc__open_pristine_tree,
   svn_wc__open_actual_tree): New functions.

* subversion/libsvn_ra/ra_trees.c,
  subversion/libsvn_subr/disk_trees.c,
  subversion/libsvn_wc/wc_trees.c
  New files, implementing different types of tree.

* subversion/libsvn_subr/tree.c
  New file, implementing the generic tree functions.

Added:
    subversion/branches/tree-read-api/subversion/include/private/svn_tree_impl.h   (with props)
    subversion/branches/tree-read-api/subversion/include/svn_tree.h   (with props)
    subversion/branches/tree-read-api/subversion/libsvn_ra/ra_trees.c   (with props)
    subversion/branches/tree-read-api/subversion/libsvn_subr/disk_trees.c   (with props)
    subversion/branches/tree-read-api/subversion/libsvn_subr/tree.c   (with props)
    subversion/branches/tree-read-api/subversion/libsvn_wc/wc_trees.c   (with props)
Modified:
    subversion/branches/tree-read-api/subversion/include/private/svn_ra_private.h
    subversion/branches/tree-read-api/subversion/include/private/svn_subr_private.h
    subversion/branches/tree-read-api/subversion/include/private/svn_wc_private.h
    subversion/branches/tree-read-api/subversion/include/svn_types.h

Modified: subversion/branches/tree-read-api/subversion/include/private/svn_ra_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/include/private/svn_ra_private.h?rev=1406709&r1=1406708&r2=1406709&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/include/private/svn_ra_private.h (original)
+++ subversion/branches/tree-read-api/subversion/include/private/svn_ra_private.h Wed Nov  7 16:33:29 2012
@@ -272,6 +272,15 @@ svn_ra__replay_ev2(svn_ra_session_t *ses
                    svn_editor_t *editor,
                    apr_pool_t *scratch_pool);
 
+/* Set *TREE_P to a new tree object representing the subtree rooted at
+ * the repository path of SESSION in revision REVNUM.
+ */
+svn_error_t *
+svn_ra__open_tree(svn_tree_t **tree_p,
+                  svn_ra_session_t *ra_session,
+                  svn_revnum_t revnum,
+                  apr_pool_t *result_pool);
+
 
 #ifdef __cplusplus
 }

Modified: subversion/branches/tree-read-api/subversion/include/private/svn_subr_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/include/private/svn_subr_private.h?rev=1406709&r1=1406708&r2=1406709&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/include/private/svn_subr_private.h (original)
+++ subversion/branches/tree-read-api/subversion/include/private/svn_subr_private.h Wed Nov  7 16:33:29 2012
@@ -325,6 +325,17 @@ svn_version__at_least(svn_version_t *ver
 
 /** @} */
 
+/* Set *TREE_P to a new tree object representing the subtree rooted at
+ * absolute path ABSPATH in the local file system.
+ *
+ * Each node in this tree has an empty set of properties.
+ */
+svn_error_t *
+svn_io__open_tree(svn_tree_t **tree_p,
+                  const char *abspath,
+                  apr_pool_t *result_pool);
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Added: subversion/branches/tree-read-api/subversion/include/private/svn_tree_impl.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/include/private/svn_tree_impl.h?rev=1406709&view=auto
==============================================================================
--- subversion/branches/tree-read-api/subversion/include/private/svn_tree_impl.h (added)
+++ subversion/branches/tree-read-api/subversion/include/private/svn_tree_impl.h Wed Nov  7 16:33:29 2012
@@ -0,0 +1,126 @@
+/*
+ * svn_tree_impl.h: header for implementors of svn_tree_t
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#ifndef SVN_TREE_IMPL_H
+#define SVN_TREE_IMPL_H
+
+#include "svn_tree.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** V-table for #svn_tree_t. */
+typedef struct svn_tree__vtable_t
+{
+  /* See svn_tree_get_node_by_relpath(). */
+  svn_error_t *(*get_node_by_relpath)(svn_tree_node_t **node,
+                                      svn_tree_t *tree,
+                                      const char *relpath,
+                                      apr_pool_t *result_pool,
+                                      apr_pool_t *scratch_pool);
+
+} svn_tree__vtable_t;
+
+/** The implementation of the typedef #svn_tree_t. */
+struct svn_tree_t
+{
+  const svn_tree__vtable_t *vtable;
+
+  /* Private data for the implementation. */
+  void *priv;
+
+  /* Pool used to manage this session.  ### What "session"? */
+  apr_pool_t *pool;
+};
+
+/** Create a new "tree" object with the given VTABLE and BATON.
+ *
+ * This is for use by an implementation of the tree class.
+ */
+svn_tree_t *
+svn_tree__create(const svn_tree__vtable_t *vtable,
+                 void *baton,
+                 apr_pool_t *result_pool);
+
+
+/* ---------------------------------------------------------------------- */
+
+/** V-table for #svn_tree_node_t. */
+typedef struct svn_tree_node__vtable_t
+{
+  /* See svn_tree_node_get_relpath(). */
+  svn_error_t *(*get_relpath)(svn_tree_node_t *node,
+                              const char **relpath,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool);
+
+  /* See svn_tree_node_get_kind(). */
+  svn_error_t *(*get_kind)(svn_tree_node_t *node,
+                           svn_node_kind_t *kind,
+                           apr_pool_t *scratch_pool);
+
+  /* See svn_tree_node_get_file(). */
+  svn_error_t *(*get_file)(svn_tree_node_t *node,
+                           svn_stream_t **stream,
+                           apr_hash_t **props,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool);
+
+  /* See svn_tree_node_get_dir(). */
+  svn_error_t *(*read_dir)(svn_tree_node_t *node,
+                          apr_hash_t **children,
+                          apr_hash_t **props,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool);
+} svn_tree_node__vtable_t;
+
+/** The implementation of the typedef #svn_tree_t. */
+struct svn_tree_node_t
+{
+  const svn_tree_node__vtable_t *vtable;
+
+  /** Private data for the implementation. */
+  void *priv;
+
+  /** Pool for ### what purpose/lifetime? */
+  apr_pool_t *pool;
+};
+
+/** Create a new "tree node" object with the given VTABLE and BATON.
+ *
+ * This is for use by an implementation of the tree class.
+ */
+svn_tree_node_t *
+svn_tree_node_create(const svn_tree_node__vtable_t *vtable,
+                     void *baton,
+                     apr_pool_t *result_pool);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SVN_TREE_IMPL_H */
+

Propchange: subversion/branches/tree-read-api/subversion/include/private/svn_tree_impl.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/tree-read-api/subversion/include/private/svn_wc_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/include/private/svn_wc_private.h?rev=1406709&r1=1406708&r2=1406709&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/include/private/svn_wc_private.h (original)
+++ subversion/branches/tree-read-api/subversion/include/private/svn_wc_private.h Wed Nov  7 16:33:29 2012
@@ -1774,6 +1774,38 @@ svn_wc__move2(svn_wc_context_t *wc_ctx,
               void *notify_baton,
               apr_pool_t *scratch_pool);
 
+/* ---------------------------------------------------------------------- */
+
+/* Set *TREE_P to a new tree object representing the subtree rooted at
+ * absolute path ABSPATH in the 'base' layer of a working copy.
+ */
+svn_error_t *
+svn_wc__open_base_tree(svn_tree_t **tree_p,
+                       const char *abspath,
+                       svn_wc_context_t *wc_ctx,
+                       apr_pool_t *result_pool);
+
+/* Set *TREE_P to a new tree object representing the subtree rooted at
+ * absolute path ABSPATH in the 'pristine'/'working' layer of a working copy.
+*/
+svn_error_t *
+svn_wc__open_pristine_tree(svn_tree_t **tree_p,
+                           const char *abspath,
+                           svn_wc_context_t *wc_ctx,
+                           apr_pool_t *result_pool);
+
+/* Set *TREE_P to a new tree object representing the subtree rooted at
+ * absolute path ABSPATH in the 'actual' layer of a working copy.
+ *
+ * That is, the tree that would get exported by "svn export WC", or shown
+ * as the right-hand side of a diff in "svn diff WCPATH".
+ */
+svn_error_t *
+svn_wc__open_actual_tree(svn_tree_t **tree_p,
+                         const char *abspath,
+                         svn_wc_context_t *wc_ctx,
+                         apr_pool_t *result_pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Added: subversion/branches/tree-read-api/subversion/include/svn_tree.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/include/svn_tree.h?rev=1406709&view=auto
==============================================================================
--- subversion/branches/tree-read-api/subversion/include/svn_tree.h (added)
+++ subversion/branches/tree-read-api/subversion/include/svn_tree.h Wed Nov  7 16:33:29 2012
@@ -0,0 +1,215 @@
+/*
+ * svn_tree.h: reading a generic tree
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#ifndef SVN_TREE_H
+#define SVN_TREE_H
+
+#include <apr_hash.h>
+#include "svn_types.h"
+#include "svn_io.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** Set @a *node_p to the root node of @a tree.
+ *
+ * Every tree has a root node, but it is possible that an error could be
+ * thrown for other reasons.
+ */
+svn_error_t *
+svn_tree_get_root_node(svn_tree_node_t **node_p,
+                       svn_tree_t *tree,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool);
+
+/** Set @a *node_p to the node that has relative path @a relpath within @a tree.
+ *
+ * Return an error if not found.
+ */
+svn_error_t *
+svn_tree_get_node_by_relpath(svn_tree_node_t **node_p,
+                             svn_tree_t *tree,
+                             const char *relpath,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool);
+
+/** A tree-walker callback.
+ *
+ * This callback presents one tree node object being visited, @a node,
+ * and the closure @a walk_baton.
+ *
+ * ### TODO: Consider re-modelling, more like Python's OS tree walker
+ *     that passes a list of subdirs and a list of non-dir children,
+ *     and lets the list of subdirs be modified before it recurses into them.
+ *
+ * @a scratch_pool is available for use within the function until it returns.
+ */
+typedef svn_error_t *(*svn_tree_walk_func_t)(svn_tree_node_t *node,
+                                             void *walk_baton,
+                                             apr_pool_t *scratch_pool);
+
+/** Walk the generic tree @a tree.
+ *
+ * Traverse the tree depth-first, visiting the children in lexically sorted
+ * order within a directory.  Recurse to depth @a depth.  Do not recurse
+ * into any node for which there is no read authorization.
+ *
+ * Call @a walk_func for each visited node, passing @a walk_baton and the
+ * tree node object.
+ *
+ * If @a cancel_func is not null, call it with @a cancel_baton to check for
+ * cancellation.
+ */
+svn_error_t *
+svn_tree_walk(svn_tree_t *tree,
+              svn_depth_t depth,
+              svn_tree_walk_func_t walk_func,
+              void *walk_baton,
+              svn_cancel_func_t cancel_func,
+              void *cancel_baton,
+              apr_pool_t *scratch_pool);
+
+/** A two-tree-walker callback.
+ *
+ * This callback presents two tree node objects being visited, @a node1
+ * and @a node2, and the closure @a walk_baton.
+ *
+ * ### TODO: Consider re-modelling, more like Python's OS tree walker
+ *     that passes a list of subdirs and a list of non-dir children,
+ *     and lets the list of subdirs be modified before it recurses into them.
+ *
+ * @a scratch_pool is available for use within the function until it returns.
+ */
+typedef svn_error_t *(*svn_tree_walk_two_func_t)(svn_tree_node_t *node1,
+                                                 svn_tree_node_t *node2,
+                                                 void *walk_baton,
+                                                 apr_pool_t *scratch_pool);
+
+/** Walk the two generic trees @a tree1 and @a tree2, simultaneously,
+ * recursing to @a depth.
+ *
+ * Call @a walk_func for each node, passing @a walk_baton and the tree
+ * node object.
+ *
+ * If @a cancel_func is not null, call it with @a cancel_baton to check for
+ * cancellation.
+ *
+ * TODO: Visit nodes with the same id at the same time, thus tracking moves.
+ * TODO: Let the callback determine the order of walking sub-nodes,
+ * especially with respect to far-moves (moves into or out of a directory).
+ */
+svn_error_t *
+svn_tree_walk_two(svn_tree_t *tree1,
+                  svn_tree_t *tree2,
+                  svn_depth_t depth,
+                  const svn_tree_walk_two_func_t walk_func,
+                  void *walk_baton,
+                  svn_cancel_func_t cancel_func,
+                  void *cancel_baton,
+                  apr_pool_t *scratch_pool);
+
+/* ---------------------------------------------------------------------- */
+
+/** Set @a *relpath_p to the path of @a tree_node, relative to the root of
+ * the tree.
+ *
+ * If @a tree_node is not readable due to lack of authorization,
+ * return a #SVN_ERR_AUTHZ_UNREADABLE error.
+ */
+svn_error_t *
+svn_tree_node_get_relpath(svn_tree_node_t *node,
+                          const char **relpath_p,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool);
+
+/** Set @a *kind to the node kind of @a tree_node.
+ *
+ * The kind will be 'file', 'dir', 'symlink' or 'none'; not 'unknown'.
+ *
+ * If @a tree_node is not readable due to lack of authorization,
+ * return a #SVN_ERR_AUTHZ_UNREADABLE error.
+ */
+svn_error_t *
+svn_tree_node_get_kind(svn_tree_node_t *node,
+                       svn_node_kind_t *kind,
+                       apr_pool_t *scratch_pool);
+
+/** Fetch the contents and/or properties of the file @a tree_node.
+ *
+ * If @a stream is non-NULL, set @a *stream to a readable stream yielding
+ * the contents of the file.  (### ? The stream
+ * handlers for @a stream may not perform any operations on @a tree_node.)
+ *
+ * ###?  If @a checksum is non-NULL, set @a *checksum to the SHA-1 checksum
+ * of the file content.  The particular tree implementation must define
+ * whether checksum is guaranteed to be filled in by the time this function
+ * call returns or whether it is only guaranteed to happen by the time the
+ * caller has read all of the data from @a stream.
+ *
+ * If @a props is non-NULL, set @a *props to contain the regular
+ * versioned properties of the file (not 'wcprops', 'entryprops', etc.).
+ * The hash maps (const char *) names to (#svn_string_t *) values.
+ *
+ * If @a tree_node is not readable due to lack of authorization,
+ * return a #SVN_ERR_AUTHZ_UNREADABLE error; otherwise, if it is the wrong
+ * kind of node, return a #SVN_ERR_WRONG_KIND error.
+ */
+svn_error_t *
+svn_tree_node_read_file(svn_tree_node_t *node,
+                        svn_stream_t **stream,
+                        /* svn_checksum_t **checksum, */
+                        apr_hash_t **props,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool);
+
+/** Fetch the entries and/or properties of the directory @a tree_node.
+ *
+ * If @a dirents is non-NULL, set @a *dirents to contain all the entries
+ * of the directory @a tree_node.  The hash maps (const char *) entry
+ * basenames to (svn_tree_node_t *) values.
+ *
+ * If @a props is non-NULL, set @a *props to contain the regular
+ * versioned properties of the file (not 'wcprops', 'entryprops', etc.).
+ * The hash maps (const char *) names to (#svn_string_t *) values.
+ *
+ * If @a tree_node is not readable due to lack of authorization,
+ * return a #SVN_ERR_AUTHZ_UNREADABLE error; otherwise, if it is the wrong
+ * kind of node, return a #SVN_ERR_WRONG_KIND error.
+ */
+svn_error_t *
+svn_tree_node_read_dir(svn_tree_node_t *node,
+                       apr_hash_t **dirents,
+                       apr_hash_t **props,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SVN_TREE_H */
+

Propchange: subversion/branches/tree-read-api/subversion/include/svn_tree.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/branches/tree-read-api/subversion/include/svn_types.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/include/svn_types.h?rev=1406709&r1=1406708&r2=1406709&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/include/svn_types.h (original)
+++ subversion/branches/tree-read-api/subversion/include/svn_types.h Wed Nov  7 16:33:29 2012
@@ -1269,6 +1269,37 @@ typedef unsigned long svn_linenum_t;
 
 
 
+/** Abstract representation of a tree of #svn_tree_node_t.
+ *
+ * This object presents an interface for referring to, accessing and
+ * traversing a tree, usually a versioned tree, of the kind of nodes that
+ * Subversion versions.
+ *
+ * A tree always has a root node: a completely empty tree is not allowed.
+ *
+ * An implementation of this interface could represent, among other trees,
+ *   * a tree in some revision of a repository,
+ *   * the base or working version of a Working Copy tree,
+ *   * an unversioned tree on disk (presumably without properties),
+ *   * a temporary tree in memory, constructed on the fly.
+ *
+ * @since New in 1.x.
+ */
+typedef struct svn_tree_t svn_tree_t;
+
+/** Abstract representation of a tree node.
+ *
+ * Each node is a file, a directory or a symbolic link, and has a set of
+ * properties.
+ *
+ * @see #svn_tree_t
+ *
+ * @since New in 1.x.
+ */
+typedef struct svn_tree_node_t svn_tree_node_t;
+
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Added: subversion/branches/tree-read-api/subversion/libsvn_ra/ra_trees.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_ra/ra_trees.c?rev=1406709&view=auto
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_ra/ra_trees.c (added)
+++ subversion/branches/tree-read-api/subversion/libsvn_ra/ra_trees.c Wed Nov  7 16:33:29 2012
@@ -0,0 +1,215 @@
+/*
+ * ra_trees.c: generic tree implementation of an in-repository subtree
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#include "svn_types.h"
+#include "svn_pools.h"
+#include "svn_dirent_uri.h"
+#include "svn_tree.h"
+#include "svn_ra.h"
+
+#include "private/svn_tree_impl.h"
+#include "private/svn_ra_private.h"
+
+#include "svn_private_config.h"
+
+
+/* Wrap any RA-layer 'unauthorized read' error in an
+ * SVN_ERR_AUTHZ_UNREADABLE error. */
+static svn_error_t *
+ra_unauthz_err(svn_error_t *err)
+{
+  if (err && ((err->apr_err == SVN_ERR_RA_NOT_AUTHORIZED) ||
+              (err->apr_err == SVN_ERR_RA_DAV_FORBIDDEN)))
+    {
+      err = svn_error_createf(SVN_ERR_AUTHZ_UNREADABLE, err, NULL);
+    }
+  return err;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* */
+typedef struct ra_tree_baton_t
+{
+  svn_ra_session_t *ra_session;
+  svn_revnum_t revnum;
+} ra_tree_baton_t;
+
+/* */
+typedef struct ra_tree_node_baton_t
+{
+  svn_tree_t *tree;
+  ra_tree_baton_t *tb;
+  const char *relpath;
+} ra_tree_node_baton_t;
+
+/* Forward declaration */
+static svn_tree_node_t *
+ra_tree_node_create(svn_tree_t *tree,
+                    const char *relpath,
+                    apr_pool_t *result_pool);
+
+/* */
+static svn_error_t *
+ra_tree_get_node_by_relpath(svn_tree_node_t **node,
+                            svn_tree_t *tree,
+                            const char *relpath,
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool)
+{
+  *node = ra_tree_node_create(tree, relpath, result_pool);
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+ra_treen_get_relpath(svn_tree_node_t *node,
+                const char **relpath_p,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
+{
+  ra_tree_node_baton_t *nb = node->priv;
+
+  *relpath_p = nb->relpath;
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+ra_treen_get_kind(svn_tree_node_t *node,
+                  svn_node_kind_t *kind,
+                  apr_pool_t *scratch_pool)
+{
+  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)));
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+ra_treen_read_file(svn_tree_node_t *node,
+                   svn_stream_t **stream,
+                   apr_hash_t **props,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
+{
+  ra_tree_node_baton_t *nb = node->priv;
+  svn_stream_t *holding_stream;
+
+  SVN_ERR(svn_stream_open_unique(&holding_stream, NULL, NULL,
+                                 svn_io_file_del_on_close,
+                                 scratch_pool, scratch_pool));
+  SVN_ERR(ra_unauthz_err(svn_ra_get_file(nb->tb->ra_session, nb->relpath,
+                                         nb->tb->revnum, holding_stream,
+                                         NULL, props, result_pool)));
+  SVN_ERR(svn_stream_reset(holding_stream));
+  *stream = holding_stream;
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+ra_treen_read_dir(svn_tree_node_t *node,
+                  apr_hash_t **children_p,
+                  apr_hash_t **props,
+                  apr_pool_t *result_pool,
+                  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)
+    {
+      apr_hash_t *children = apr_hash_make(result_pool);
+      apr_hash_index_t *hi;
+
+      for (hi = apr_hash_first(scratch_pool, dirents); hi;
+           hi = apr_hash_next(hi))
+        {
+          const char *name = svn__apr_hash_index_key(hi);
+          const char *relpath = svn_relpath_join(nb->relpath, name, result_pool);
+          svn_tree_node_t *child;
+
+          child = ra_tree_node_create(nb->tree, relpath, result_pool);
+          apr_hash_set(children, name, APR_HASH_KEY_STRING, child);
+        }
+      *children_p = children;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* */
+static const svn_tree__vtable_t ra_tree_vtable =
+{
+  ra_tree_get_node_by_relpath
+};
+
+/* */
+static const svn_tree_node__vtable_t ra_tree_node_vtable =
+{
+  ra_treen_get_relpath,
+  ra_treen_get_kind,
+  ra_treen_read_file,
+  ra_treen_read_dir
+};
+
+/* */
+static svn_tree_node_t *
+ra_tree_node_create(svn_tree_t *tree,
+                    const char *relpath,
+                    apr_pool_t *result_pool)
+{
+  ra_tree_node_baton_t *nb = apr_palloc(result_pool, sizeof(*nb));
+
+  nb->tree = tree;
+  nb->tb = tree->priv;
+  nb->relpath = relpath;
+  return svn_tree_node_create(&ra_tree_node_vtable, nb, result_pool);
+}
+
+svn_error_t *
+svn_ra__open_tree(svn_tree_t **tree_p,
+                  svn_ra_session_t *ra_session,
+                  svn_revnum_t revnum,
+                  apr_pool_t *result_pool)
+{
+  ra_tree_baton_t *tb = apr_palloc(result_pool, sizeof(*tb));
+
+  tb->ra_session = ra_session;
+  tb->revnum = revnum;
+
+  *tree_p = svn_tree__create(&ra_tree_vtable, tb, result_pool);
+  return SVN_NO_ERROR;
+}

Propchange: subversion/branches/tree-read-api/subversion/libsvn_ra/ra_trees.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: subversion/branches/tree-read-api/subversion/libsvn_subr/disk_trees.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/disk_trees.c?rev=1406709&view=auto
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/disk_trees.c (added)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/disk_trees.c Wed Nov  7 16:33:29 2012
@@ -0,0 +1,202 @@
+/*
+ * disk_trees.c: generic tree implementation of unversioned disk trees
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#include "svn_types.h"
+#include "svn_pools.h"
+#include "svn_dirent_uri.h"
+#include "svn_path.h"
+#include "svn_tree.h"
+
+#include "private/svn_tree_impl.h"
+#include "private/svn_subr_private.h"
+
+#include "svn_private_config.h"
+
+
+/* */
+typedef struct disk_tree_baton_t
+{
+  const char *tree_abspath;
+} disk_tree_baton_t;
+
+/* */
+typedef struct disk_tree_node_baton_t
+{
+  svn_tree_t *tree;
+  disk_tree_baton_t *tb;
+  const char *relpath;
+} disk_tree_node_baton_t;
+
+/* Forward declaration */
+static svn_tree_node_t *
+disk_tree_node_create(svn_tree_t *tree,
+                      const char *relpath,
+                      apr_pool_t *result_pool);
+
+/* */
+static svn_error_t *
+disk_tree_get_node_by_relpath(svn_tree_node_t **node,
+                              svn_tree_t *tree,
+                              const char *relpath,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool)
+{
+  *node = disk_tree_node_create(tree, relpath, result_pool);
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+disk_treen_get_relpath(svn_tree_node_t *node,
+                       const char **relpath_p,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
+{
+  disk_tree_node_baton_t *nb = node->priv;
+
+  *relpath_p = nb->relpath;
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+disk_treen_get_kind(svn_tree_node_t *node,
+                    svn_node_kind_t *kind,
+                    apr_pool_t *scratch_pool)
+{
+  disk_tree_node_baton_t *nb = node->priv;
+  const char *abspath = svn_dirent_join(nb->tb->tree_abspath,
+                                        nb->relpath, scratch_pool);
+
+  SVN_ERR(svn_io_check_path(abspath, kind, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+disk_treen_get_file(svn_tree_node_t *node,
+                    svn_stream_t **stream,
+                    apr_hash_t **props,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
+{
+  disk_tree_node_baton_t *nb = node->priv;
+  const char *abspath = svn_dirent_join(nb->tb->tree_abspath,
+                                        nb->relpath, scratch_pool);
+
+  if (stream)
+    SVN_ERR(svn_stream_open_readonly(stream, abspath,
+                                     result_pool, scratch_pool));
+  if (props)
+    *props = apr_hash_make(result_pool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Read a directory from disk.
+ * It's an unversioned tree on disk, so report no properties.
+ * TODO: Consider adding the ability to report svn:executable,
+ * auto-props, etc. like "svn add" does.
+ */
+static svn_error_t *
+disk_treen_get_dir(svn_tree_node_t *node,
+                   apr_hash_t **children_p,
+                   apr_hash_t **props,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
+{
+  disk_tree_node_baton_t *nb = node->priv;
+  const char *abspath = svn_dirent_join(nb->tb->tree_abspath,
+                                        nb->relpath, scratch_pool);
+
+  if (children_p)
+    {
+      apr_hash_t *dirents;
+      apr_hash_index_t *hi;
+      apr_hash_t *children = apr_hash_make(result_pool);
+
+      SVN_ERR(svn_io_get_dirents3(&dirents, abspath, FALSE,
+                                  result_pool, scratch_pool));
+
+      /* Convert RA dirents to tree children */
+      for (hi = apr_hash_first(scratch_pool, dirents); hi;
+           hi = apr_hash_next(hi))
+        {
+          const char *name = svn__apr_hash_index_key(hi);
+          const char *relpath = svn_relpath_join(nb->relpath, name, result_pool);
+          svn_tree_node_t *child;
+
+          child = disk_tree_node_create(nb->tree, relpath, result_pool);
+          apr_hash_set(children, name, APR_HASH_KEY_STRING, child);
+        }
+      *children_p = children;
+    }
+
+  /* It's an unversioned tree on disk, so report no properties. */
+  if (props)
+    *props = apr_hash_make(result_pool);
+
+  return SVN_NO_ERROR;
+}
+
+/* */
+static const svn_tree__vtable_t disk_tree_vtable =
+{
+  disk_tree_get_node_by_relpath
+};
+
+/* */
+static const svn_tree_node__vtable_t disk_tree_node_vtable =
+{
+  disk_treen_get_relpath,
+  disk_treen_get_kind,
+  disk_treen_get_file,
+  disk_treen_get_dir
+};
+
+/* */
+static svn_tree_node_t *
+disk_tree_node_create(svn_tree_t *tree,
+                      const char *relpath,
+                      apr_pool_t *result_pool)
+{
+  disk_tree_node_baton_t *nb = apr_palloc(result_pool, sizeof(*nb));
+
+  nb->tree = tree;
+  nb->tb = tree->priv;
+  nb->relpath = relpath;
+  return svn_tree_node_create(&disk_tree_node_vtable, nb, result_pool);
+}
+
+svn_error_t *
+svn_io__open_tree(svn_tree_t **tree_p,
+                  const char *abspath,
+                  apr_pool_t *result_pool)
+{
+  disk_tree_baton_t *tb = apr_palloc(result_pool, sizeof(*tb));
+
+  tb->tree_abspath = abspath;
+
+  *tree_p = svn_tree__create(&disk_tree_vtable, tb, result_pool);
+  return SVN_NO_ERROR;
+}

Propchange: subversion/branches/tree-read-api/subversion/libsvn_subr/disk_trees.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: subversion/branches/tree-read-api/subversion/libsvn_subr/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/tree.c?rev=1406709&view=auto
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/tree.c (added)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/tree.c Wed Nov  7 16:33:29 2012
@@ -0,0 +1,344 @@
+/*
+ * tree.c: reading a generic tree
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#include <assert.h>
+
+#include "svn_pools.h"
+#include "svn_sorts.h"
+#include "svn_dirent_uri.h"
+#include "svn_tree.h"
+
+#include "private/svn_tree_impl.h"
+
+#include "svn_private_config.h"
+
+
+svn_tree_t *
+svn_tree__create(const svn_tree__vtable_t *vtable,
+                 void *baton,
+                 apr_pool_t *result_pool)
+{
+  svn_tree_t *tree = apr_palloc(result_pool, sizeof(*tree));
+
+  tree->vtable = vtable;
+  tree->pool = result_pool;
+  tree->priv = baton;
+  return tree;
+}
+
+svn_error_t *
+svn_tree_get_root_node(svn_tree_node_t **node_p,
+                       svn_tree_t *tree,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
+{
+  SVN_ERR(tree->vtable->get_node_by_relpath(node_p, tree, "",
+                                            result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_tree_get_node_by_relpath(svn_tree_node_t **node_p,
+                             svn_tree_t *tree,
+                             const char *relpath,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool)
+{
+  SVN_ERR(tree->vtable->get_node_by_relpath(node_p, tree, relpath,
+                                            result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+tree_node_get_kind_or_unknown(svn_node_kind_t *kind,
+                              svn_tree_node_t *node,
+                              apr_pool_t *scratch_pool)
+{
+  svn_error_t *err = svn_tree_node_get_kind(node, kind, scratch_pool);
+
+  if (err && err->apr_err == SVN_ERR_AUTHZ_UNREADABLE)
+    {
+      /* Can't read this node's kind. That's fine; pass 'unknown'. */
+      svn_error_clear(err);
+      *kind = svn_node_unknown;
+      return SVN_NO_ERROR;
+    }
+  return svn_error_trace(err);
+}
+
+/* The body of svn_tree_walk(), which see.
+ */
+static svn_error_t *
+walk_tree(svn_tree_node_t *node,
+          svn_depth_t depth,
+          svn_tree_walk_func_t walk_func,
+          void *walk_baton,
+          svn_cancel_func_t cancel_func,
+          void *cancel_baton,
+          apr_pool_t *scratch_pool)
+{
+  svn_node_kind_t kind;
+
+  if (cancel_func)
+    SVN_ERR(cancel_func(cancel_baton));
+
+  SVN_ERR(tree_node_get_kind_or_unknown(&kind, node, scratch_pool));
+
+  SVN_ERR(walk_func(node, walk_baton, scratch_pool));
+
+  /* Recurse */
+  if (kind == svn_node_dir && depth >= svn_depth_files)
+    {
+      apr_hash_t *dirents;
+      apr_array_header_t *dirents_sorted;
+      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+      int i;
+
+      SVN_ERR(svn_tree_node_read_dir(node, &dirents, NULL /* props */,
+                                     scratch_pool, scratch_pool));
+      dirents_sorted = svn_sort__hash(dirents,
+                                      svn_sort_compare_items_lexically,
+                                      scratch_pool);
+
+      for (i = 0; i < dirents_sorted->nelts; i++)
+        {
+          const svn_sort__item_t *item
+            = &APR_ARRAY_IDX(dirents_sorted, i, svn_sort__item_t);
+          svn_tree_node_t *child = item->value;
+          svn_node_kind_t child_kind;
+
+          svn_pool_clear(iterpool);
+          SVN_ERR(tree_node_get_kind_or_unknown(&child_kind, child, iterpool));
+          if (depth >= svn_depth_immediates || child_kind == svn_node_file)
+            {
+              SVN_ERR(walk_tree(child,
+                                depth == svn_depth_infinity ? depth
+                                       : svn_depth_empty,
+                                walk_func, walk_baton,
+                                cancel_func, cancel_baton, iterpool));
+            }
+        }
+      svn_pool_destroy(iterpool);
+    }
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_tree_walk(svn_tree_t *tree,
+              svn_depth_t depth,
+              svn_tree_walk_func_t walk_func,
+              void *walk_baton,
+              svn_cancel_func_t cancel_func,
+              void *cancel_baton,
+              apr_pool_t *scratch_pool)
+{
+  svn_tree_node_t *node;
+
+  SVN_ERR(svn_tree_get_root_node(&node, tree, scratch_pool, scratch_pool));
+  SVN_ERR(walk_tree(node, depth,
+                    walk_func, walk_baton,
+                    cancel_func, cancel_baton, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* Walk two trees, rooted at NODE1 and NODE2, simultaneously, driving the
+ * CALLBACKS.
+ *
+ * Currently visits nodes with the same relpath at the same time; see TODO
+ * notes on svn_tree_walk_two().
+ *
+ * TODO: allow recursing into a singleton directory (that is, on one side)?
+ */
+static svn_error_t *
+walk_two_trees(svn_tree_node_t *node1,
+               svn_tree_node_t *node2,
+               svn_depth_t depth,
+               const svn_tree_walk_two_func_t walk_func,
+               void *walk_baton,
+               svn_cancel_func_t cancel_func,
+               void *cancel_baton,
+               apr_pool_t *scratch_pool)
+{
+  const char *relpath1 = NULL, *relpath2 = NULL;
+  svn_node_kind_t kind1 = svn_node_none, kind2 = svn_node_none;
+
+  assert(node1 || node2);
+
+  if (cancel_func)
+    SVN_ERR(cancel_func(cancel_baton));
+
+  if (node1)
+    {
+      SVN_ERR(svn_tree_node_get_relpath(node1, &relpath1,
+                                        scratch_pool, scratch_pool));
+      SVN_ERR(svn_tree_node_get_kind(node1, &kind1, scratch_pool));
+    }
+  if (node2)
+    {
+      SVN_ERR(svn_tree_node_get_relpath(node2, &relpath2,
+                                        scratch_pool, scratch_pool));
+      SVN_ERR(svn_tree_node_get_kind(node2, &kind2, scratch_pool));
+    }
+  if (node1 && node2)
+    {
+      assert(strcmp(relpath1, relpath2) == 0);  /* ### until move/rename support */
+      assert(kind1 == kind2);  /* In Subversion a node can't change kind */
+    }
+
+  SVN_ERR(walk_func(node1, node2, walk_baton, scratch_pool));
+
+  SVN_DBG(("walk_two_trees: kind %d/%d, '%s'\n",
+           kind1, kind2, relpath1 ? relpath1 : relpath2));
+
+  /* Recurse, if it's a directory on BOTH sides */
+  if (node1 && node2
+      && kind1 == svn_node_dir
+      && depth >= svn_depth_files)
+    {
+      apr_hash_t *children1, *children2;
+      apr_hash_t *all_children;
+      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+      apr_hash_index_t *hi;
+
+      SVN_ERR(svn_tree_node_read_dir(node1, &children1, NULL,
+                                     scratch_pool, scratch_pool));
+      SVN_ERR(svn_tree_node_read_dir(node2, &children2, NULL,
+                                     scratch_pool, scratch_pool));
+      all_children = apr_hash_overlay(scratch_pool, children1, children2);
+
+      SVN_DBG(("Recursing (%d||%d=%d children) in '%s'\n",
+               apr_hash_count(children1), apr_hash_count(children2),
+               apr_hash_count(all_children),
+               relpath1));
+
+      for (hi = apr_hash_first(scratch_pool, all_children); hi;
+           hi = apr_hash_next(hi))
+        {
+          const char *relpath = svn__apr_hash_index_key(hi);
+          svn_tree_node_t *child1 = apr_hash_get(children1, relpath,
+                                                 APR_HASH_KEY_STRING);
+          svn_tree_node_t *child2 = apr_hash_get(children2, relpath,
+                                                 APR_HASH_KEY_STRING);
+          svn_node_kind_t child_kind;
+
+          svn_pool_clear(iterpool);
+
+          SVN_ERR(tree_node_get_kind_or_unknown(&child_kind,
+                                                child1 ? child1 : child2,
+                                                iterpool));
+          if (depth >= svn_depth_immediates || child_kind == svn_node_file)
+            {
+              SVN_ERR(walk_two_trees(child1, child2,
+                                     depth == svn_depth_infinity ? depth
+                                       : svn_depth_empty,
+                                     walk_func, walk_baton,
+                                     cancel_func, cancel_baton,
+                                     iterpool));
+            }
+        }
+      svn_pool_destroy(iterpool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_tree_walk_two(svn_tree_t *tree1,
+                  svn_tree_t *tree2,
+                  svn_depth_t depth,
+                  const svn_tree_walk_two_func_t walk_func,
+                  void *walk_baton,
+                  svn_cancel_func_t cancel_func,
+                  void *cancel_baton,
+                  apr_pool_t *scratch_pool)
+{
+  svn_tree_node_t *node1, *node2;
+
+  SVN_ERR(svn_tree_get_root_node(&node1, tree1, scratch_pool, scratch_pool));
+  SVN_ERR(svn_tree_get_root_node(&node2, tree2, scratch_pool, scratch_pool));
+
+  SVN_ERR(walk_two_trees(node1, node2,
+                         depth,
+                         walk_func, walk_baton,
+                         cancel_func, cancel_baton,
+                         scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* ---------------------------------------------------------------------- */
+
+svn_tree_node_t *
+svn_tree_node_create(const svn_tree_node__vtable_t *vtable,
+                     void *baton,
+                     apr_pool_t *result_pool)
+{
+  svn_tree_node_t *node = apr_palloc(result_pool, sizeof(*node));
+
+  node->vtable = vtable;
+  node->pool = result_pool;
+  node->priv = baton;
+  return node;
+}
+
+svn_error_t *
+svn_tree_node_get_relpath(svn_tree_node_t *node,
+                          const char **relpath_p,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
+{
+  SVN_ERR(node->vtable->get_relpath(node, relpath_p,
+                                    result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_tree_node_get_kind(svn_tree_node_t *node,
+                       svn_node_kind_t *kind_p,
+                       apr_pool_t *scratch_pool)
+{
+  return node->vtable->get_kind(node, kind_p, scratch_pool);
+}
+
+svn_error_t *
+svn_tree_node_read_file(svn_tree_node_t *node,
+                        svn_stream_t **stream,
+                        /* svn_checksum_t **checksum, */
+                        apr_hash_t **props,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool)
+{
+  return node->vtable->get_file(node, stream, props,
+                                 result_pool, scratch_pool);
+}
+
+svn_error_t *
+svn_tree_node_read_dir(svn_tree_node_t *node,
+                       apr_hash_t **children,
+                       apr_hash_t **props,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
+{
+  return node->vtable->read_dir(node, children, props,
+                                result_pool, scratch_pool);
+}

Propchange: subversion/branches/tree-read-api/subversion/libsvn_subr/tree.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: subversion/branches/tree-read-api/subversion/libsvn_wc/wc_trees.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/wc_trees.c?rev=1406709&view=auto
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/wc_trees.c (added)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/wc_trees.c Wed Nov  7 16:33:29 2012
@@ -0,0 +1,335 @@
+/*
+ * wc_trees.c: implementation of generic tree access to a WC
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#include "svn_types.h"
+#include "svn_pools.h"
+#include "svn_dirent_uri.h"
+#include "svn_wc.h"
+#include "svn_tree.h"
+
+#include "private/svn_tree_impl.h"
+#include "private/svn_wc_private.h"
+
+#include "svn_private_config.h"
+#include "wc.h"
+
+
+/* */
+typedef struct wc_tree_baton_t
+{
+  const char *tree_abspath;
+  svn_wc_context_t *wc_ctx;
+  svn_boolean_t is_base;  /* true -> base, false -> pristine or "actual" */
+  svn_boolean_t is_pristine;  /* true -> pristine, false -> base or "actual" */
+    /* "Pristine" means the WC "working" version for a mod/copy/move,
+     * but the WC "base" version for a delete/add/replace. */
+    /* "Working" means:
+     *   - the WC "working" version for a mod/copy/move,
+     *   - "nothing" for a delete,
+     *   - ??? for an add;
+     * /replace. */
+} wc_tree_baton_t;
+
+/* */
+typedef struct wc_tree_node_baton_t
+{
+  svn_tree_t *tree;
+  const char *relpath;
+} wc_tree_node_baton_t;
+
+/* Forward declaration */
+static svn_tree_node_t *
+wc_tree_node_create(svn_tree_t *tree,
+                    const char *relpath,
+                    apr_pool_t *result_pool);
+
+/* */
+static svn_error_t *
+wc_tree_get_node_by_relpath(svn_tree_node_t **node,
+                            svn_tree_t *tree,
+                            const char *relpath,
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool)
+{
+  *node = wc_tree_node_create(tree, relpath, result_pool);
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+wc_treen_get_relpath(svn_tree_node_t *node,
+                     const char **relpath_p,
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool)
+{
+  wc_tree_node_baton_t *nb = node->priv;
+
+  *relpath_p = nb->relpath;  /* ### not duped */
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+wc_treen_get_kind(svn_tree_node_t *node,
+                  svn_node_kind_t *kind,
+                  apr_pool_t *scratch_pool)
+{
+  wc_tree_node_baton_t *nb = node->priv;
+  wc_tree_baton_t *tb = nb->tree->priv;
+  const char *abspath = svn_dirent_join(tb->tree_abspath, nb->relpath,
+                                        scratch_pool);
+
+  if (tb->is_base)
+    {
+      SVN_DBG(("oops! BASE tree not fully implemented yet: returning WORKING kind"));
+      SVN_ERR(/* ### svn_wc_read_base_kind */
+              svn_wc_read_kind(kind, tb->wc_ctx, abspath,
+                               FALSE /* show_hidden */, scratch_pool));
+    }
+  else if (tb->is_pristine)
+    {
+      SVN_ERR(svn_wc_read_kind(kind, tb->wc_ctx, abspath,
+                               FALSE /* show_hidden */, scratch_pool));
+    }
+  else
+    {
+      SVN_ERR(svn_io_check_path(abspath, kind, scratch_pool));
+    }
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+wc_read_props(apr_hash_t **props,
+              wc_tree_baton_t *tb,
+              const char *abspath,
+              apr_pool_t *result_pool,
+              apr_pool_t *scratch_pool)
+{
+  if (props)
+    {
+      if (tb->is_base)
+        {
+          SVN_ERR(svn_wc__db_base_get_props(props, tb->wc_ctx->db, abspath,
+                                            result_pool, scratch_pool));
+        }
+      else if (tb->is_pristine)
+        {
+          SVN_ERR(svn_wc_get_pristine_props(props, tb->wc_ctx, abspath,
+                                            result_pool, scratch_pool));
+        }
+      else
+        {
+          SVN_ERR(svn_wc_prop_list2(props, tb->wc_ctx, abspath,
+                                    result_pool, scratch_pool));
+        }
+    }
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+wc_treen_read_file(svn_tree_node_t *node,
+                   svn_stream_t **stream,
+                   apr_hash_t **props,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
+{
+  wc_tree_node_baton_t *nb = node->priv;
+  wc_tree_baton_t *tb = nb->tree->priv;
+  const char *abspath = svn_dirent_join(tb->tree_abspath, nb->relpath,
+                                        scratch_pool);
+
+  if (stream)
+    {
+      if (tb->is_base)
+        {
+          const svn_checksum_t *checksum;
+
+          SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL, NULL, NULL,
+                                           NULL, NULL, NULL, NULL, &checksum,
+                                           NULL, NULL, NULL, NULL,
+                                           tb->wc_ctx->db, abspath,
+                                           scratch_pool, scratch_pool));
+          if (checksum)
+            SVN_ERR(svn_wc__db_pristine_read(stream, NULL /* size */,
+                                             tb->wc_ctx->db, abspath,
+                                             checksum,
+                                             result_pool, scratch_pool));
+          else
+            *stream = NULL;
+        }
+      else if (tb->is_pristine)
+        {
+          SVN_ERR(svn_wc_get_pristine_contents2(stream, tb->wc_ctx, abspath,
+                                                result_pool, scratch_pool));
+        }
+      else
+        {
+          SVN_ERR(svn_stream_open_readonly(stream, abspath,
+                                           result_pool, scratch_pool));
+        }
+    }
+
+  SVN_ERR(wc_read_props(props, tb, abspath, result_pool, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* */
+static svn_error_t *
+wc_treen_read_dir(svn_tree_node_t *node,
+                  apr_hash_t **children_p,
+                  apr_hash_t **props,
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
+{
+  wc_tree_node_baton_t *nb = node->priv;
+  wc_tree_baton_t *tb = nb->tree->priv;
+  const char *abspath = svn_dirent_join(tb->tree_abspath, nb->relpath,
+                                        scratch_pool);
+
+  if (children_p)
+    {
+      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+      const apr_array_header_t *wc_children;
+      int i;
+      apr_hash_t *tree_children = apr_hash_make(result_pool);
+
+      if (tb->is_base)
+        {
+          SVN_ERR(svn_wc__db_base_get_children(
+                    &wc_children, tb->wc_ctx->db, abspath,
+                    result_pool, scratch_pool));
+        }
+      else if (tb->is_pristine)
+        {
+          SVN_ERR(svn_wc__node_get_children_of_working_node(
+                    &wc_children, tb->wc_ctx, abspath, FALSE /* show_hidden */,
+                    result_pool, scratch_pool));
+        }
+      else
+        {
+          SVN_ERR(svn_wc__node_get_children(
+                    &wc_children, tb->wc_ctx, abspath, FALSE /* show_hidden */,
+                    result_pool, scratch_pool));
+        }
+
+      for (i = 0; i < wc_children->nelts; i++)
+        {
+          const char *child_abspath = APR_ARRAY_IDX(wc_children, i, const char *);
+          const char *name, *relpath;
+          svn_tree_node_t *child;
+
+          svn_pool_clear(iterpool);
+          name = svn_dirent_basename(child_abspath, iterpool);
+          relpath = svn_relpath_join(nb->relpath, name, result_pool);
+          child = wc_tree_node_create(nb->tree, relpath, result_pool);
+          apr_hash_set(tree_children, name, APR_HASH_KEY_STRING, child);
+        }
+      svn_pool_destroy(iterpool);
+
+      *children_p = tree_children;
+    }
+
+  SVN_ERR(wc_read_props(props, tb, abspath, result_pool, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* */
+static const svn_tree__vtable_t wc_tree_vtable =
+{
+  wc_tree_get_node_by_relpath
+};
+
+/* */
+static const svn_tree_node__vtable_t wc_tree_node_vtable =
+{
+  wc_treen_get_relpath,
+  wc_treen_get_kind,
+  wc_treen_read_file,
+  wc_treen_read_dir
+};
+
+/* */
+static svn_tree_node_t *
+wc_tree_node_create(svn_tree_t *tree,
+                    const char *relpath,
+                    apr_pool_t *result_pool)
+{
+  wc_tree_node_baton_t *nb = apr_palloc(result_pool, sizeof(*nb));
+
+  nb->tree = tree;
+  nb->relpath = relpath;
+  return svn_tree_node_create(&wc_tree_node_vtable, nb, result_pool);
+}
+
+svn_error_t *
+svn_wc__open_base_tree(svn_tree_t **tree_p,
+                       const char *abspath,
+                       svn_wc_context_t *wc_ctx,
+                       apr_pool_t *result_pool)
+{
+  wc_tree_baton_t *tb = apr_palloc(result_pool, sizeof(*tb));
+
+  tb->tree_abspath = abspath;
+  tb->wc_ctx = wc_ctx;
+  tb->is_base = TRUE;
+  tb->is_pristine = FALSE;
+  *tree_p = svn_tree__create(&wc_tree_vtable, tb, result_pool);
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__open_pristine_tree(svn_tree_t **tree_p,
+                           const char *abspath,
+                           svn_wc_context_t *wc_ctx,
+                           apr_pool_t *result_pool)
+{
+  wc_tree_baton_t *tb = apr_palloc(result_pool, sizeof(*tb));
+
+  tb->tree_abspath = abspath;
+  tb->wc_ctx = wc_ctx;
+  tb->is_base = FALSE;
+  tb->is_pristine = TRUE;
+  *tree_p = svn_tree__create(&wc_tree_vtable, tb, result_pool);
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__open_actual_tree(svn_tree_t **tree_p,
+                         const char *abspath,
+                         svn_wc_context_t *wc_ctx,
+                         apr_pool_t *result_pool)
+{
+  wc_tree_baton_t *tb = apr_palloc(result_pool, sizeof(*tb));
+
+  tb->tree_abspath = abspath;
+  tb->wc_ctx = wc_ctx;
+  tb->is_base = FALSE;
+  tb->is_pristine = FALSE;
+  *tree_p = svn_tree__create(&wc_tree_vtable, tb, result_pool);
+  return SVN_NO_ERROR;
+}
+

Propchange: subversion/branches/tree-read-api/subversion/libsvn_wc/wc_trees.c
------------------------------------------------------------------------------
    svn:eol-style = native