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 2011/10/24 11:40:35 UTC

svn commit: r1188060 - in /subversion/branches/tree-read-api/subversion/libsvn_client: tree.c tree.h

Author: julianfoad
Date: Mon Oct 24 09:40:35 2011
New Revision: 1188060

URL: http://svn.apache.org/viewvc?rev=1188060&view=rev
Log:
On the 'tree-read-api' branch: Add a tree walker and specify authorization
failure errors.

Modified:
    subversion/branches/tree-read-api/subversion/libsvn_client/tree.c
    subversion/branches/tree-read-api/subversion/libsvn_client/tree.h

Modified: subversion/branches/tree-read-api/subversion/libsvn_client/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_client/tree.c?rev=1188060&r1=1188059&r2=1188060&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_client/tree.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_client/tree.c Mon Oct 24 09:40:35 2011
@@ -21,11 +21,14 @@
  * ====================================================================
  */
 
+#include "svn_pools.h"
+#include "svn_sorts.h"
 #include "svn_dirent_uri.h"
 #include "svn_path.h"
 #include "client.h"
 #include "tree.h"
 #include "private/svn_wc_private.h"
+#include "svn_private_config.h"
 
 
 /*-----------------------------------------------------------------*/
@@ -123,6 +126,121 @@ svn_tree_get_symlink(svn_tree_t *tree,
                                    result_pool, scratch_pool);
 }
 
+/* */
+static svn_error_t *
+tree_get_kind_or_unknown(svn_tree_t *tree,
+                         svn_kind_t *kind,
+                         const char *relpath,
+                         apr_pool_t *scratch_pool)
+{
+  svn_error_t *err = svn_tree_get_kind(tree, kind, relpath, 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_kind_unknown;
+      return SVN_NO_ERROR;
+    }
+  return svn_error_trace(err);
+}
+
+/* The body of svn_tree_walk(), which see.
+ *
+ * ### The handling of unauthorized-read errors is a bit under-defined.
+ * For example, if the get_kind call returns 'dir' but then the 'get_dir'
+ * returns unauthorized, the callback only gets an empty dir with no
+ * indication that reading the children was unauthorized.
+ */
+static svn_error_t *
+tree_walk(svn_tree_t *tree,
+          const char *relpath,
+          svn_depth_t depth,
+          svn_tree_walk_func_t callback_func,
+          void *callback_baton,
+          svn_cancel_func_t cancel_func,
+          void *cancel_baton,
+          apr_pool_t *scratch_pool)
+{
+  svn_kind_t kind;
+  apr_hash_t *dirents;
+
+  if (cancel_func)
+    SVN_ERR(cancel_func(cancel_baton));
+
+  SVN_ERR(tree_get_kind_or_unknown(tree, &kind, relpath, scratch_pool));
+
+  /* Fetch the dir's children, if needed, before calling the callback, so
+   * that we can pass kind=unknown if fetching the children fails. */
+  if (kind == svn_kind_dir && depth > svn_depth_empty)
+    {
+      svn_error_t *err
+        = svn_tree_get_dir(tree, &dirents, NULL /* props */,
+                           relpath, scratch_pool, scratch_pool);
+
+      if (err && err->apr_err == SVN_ERR_AUTHZ_UNREADABLE)
+        {
+          /* Can't read this directory. That's fine; skip it. */
+          svn_error_clear(err);
+          return SVN_NO_ERROR;
+        }
+      else
+        SVN_ERR(err);
+    }
+
+  SVN_ERR(callback_func(tree, relpath, kind, callback_baton, scratch_pool));
+
+  /* Recurse (visiting the children in sorted order). */
+  if (kind == svn_kind_dir && depth > svn_depth_empty)
+    {
+      apr_array_header_t *dirents_sorted
+        = svn_sort__hash(dirents, svn_sort_compare_items_lexically,
+                         scratch_pool);
+      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+      int i;
+
+      for (i = 0; i < dirents_sorted->nelts; i++)
+        {
+          const svn_sort__item_t *item
+            = &APR_ARRAY_IDX(dirents_sorted, i, svn_sort__item_t);
+          const char *name = item->key;
+          const char *child_relpath;
+          svn_kind_t child_kind;
+
+          svn_pool_clear(iterpool);
+          child_relpath = svn_relpath_join(relpath, name, iterpool);
+          SVN_ERR(tree_get_kind_or_unknown(tree, &child_kind, child_relpath,
+                                           scratch_pool));
+          if (depth > svn_depth_files || child_kind == svn_kind_file)
+            {
+              SVN_ERR(svn_tree_walk(tree, child_relpath,
+                                    depth == svn_depth_infinity ? depth
+                                           : svn_depth_empty,
+                                    callback_func, callback_baton,
+                                    cancel_func, cancel_baton, iterpool));
+            }
+        }
+      svn_pool_destroy(iterpool);
+    }
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_tree_walk(svn_tree_t *tree,
+              const char *relpath,
+              svn_depth_t depth,
+              svn_tree_walk_func_t callback_func,
+              void *callback_baton,
+              svn_cancel_func_t cancel_func,
+              void *cancel_baton,
+              apr_pool_t *scratch_pool)
+{
+  SVN_ERR(tree_walk(tree, relpath, depth,
+                    callback_func, callback_baton,
+                    cancel_func, cancel_baton, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
 
 /*-----------------------------------------------------------------*/
 
@@ -461,6 +579,19 @@ typedef struct ra_tree_baton_t
   svn_revnum_t revnum;
 } ra_tree_baton_t;
 
+/* 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;
+}
+
 /* */
 static svn_error_t *
 ra_tree_get_kind(svn_tree_t *tree,
@@ -470,8 +601,9 @@ ra_tree_get_kind(svn_tree_t *tree,
 {
   ra_tree_baton_t *baton = tree->priv;
 
-  SVN_ERR(svn_ra_check_path2(baton->ra_session, relpath, baton->revnum,
-                             kind, scratch_pool));
+  SVN_ERR(ra_unauthz_err(svn_ra_check_path2(baton->ra_session, relpath,
+                                            baton->revnum, kind,
+                                            scratch_pool)));
   return SVN_NO_ERROR;
 }
 
@@ -490,8 +622,9 @@ ra_tree_get_file(svn_tree_t *tree,
   SVN_ERR(svn_stream_open_unique(&holding_stream, NULL, NULL,
                                  svn_io_file_del_on_close,
                                  scratch_pool, scratch_pool));
-  SVN_ERR(svn_ra_get_file(baton->ra_session, relpath, baton->revnum,
-                          holding_stream, NULL, props, result_pool));
+  SVN_ERR(ra_unauthz_err(svn_ra_get_file(baton->ra_session, relpath,
+                                         baton->revnum, holding_stream,
+                                         NULL, props, result_pool)));
   SVN_ERR(svn_stream_reset(holding_stream));
   *stream = holding_stream;
   return SVN_NO_ERROR;
@@ -508,11 +641,11 @@ ra_tree_get_dir(svn_tree_t *tree,
 {
   ra_tree_baton_t *baton = tree->priv;
 
-  SVN_ERR(svn_ra_get_dir2(baton->ra_session,
-                          dirents, NULL, props,
-                          relpath, baton->revnum,
-                          0 /* dirent_fields */,
-                          result_pool));
+  SVN_ERR(ra_unauthz_err(svn_ra_get_dir2(baton->ra_session,
+                                         dirents, NULL, props,
+                                         relpath, baton->revnum,
+                                         0 /* dirent_fields */,
+                                         result_pool)));
   return SVN_NO_ERROR;
 }
 
@@ -527,8 +660,9 @@ ra_tree_get_symlink(svn_tree_t *tree,
 {
   ra_tree_baton_t *baton = tree->priv;
 
-  SVN_ERR(svn_ra_get_symlink(baton->ra_session, relpath, baton->revnum,
-                             link_target, NULL, props, result_pool));
+  SVN_ERR(ra_unauthz_err(svn_ra_get_symlink(baton->ra_session, relpath,
+                                            baton->revnum, link_target,
+                                            NULL, props, result_pool)));
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/tree-read-api/subversion/libsvn_client/tree.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_client/tree.h?rev=1188060&r1=1188059&r2=1188060&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_client/tree.h (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_client/tree.h Mon Oct 24 09:40:35 2011
@@ -51,13 +51,12 @@ extern "C" {
  */
 typedef struct svn_tree_t svn_tree_t;
 
-
-/** Fetch the node kind of the node at @a relpath.
- * (### and other metadata? revnum? props?)
+/** Set @a *kind to the node kind of the node at @a relpath in @a tree.
  *
  * The kind will be 'file', 'dir', 'symlink' or 'none'; not 'unknown'.
  *
- * Set @a *kind to the node kind.
+ * If the node at @a relpath is not readable due to lack of authorization,
+ * return a #SVN_ERR_AUTHZ_UNREADABLE error.
  */
 svn_error_t *
 svn_tree_get_kind(svn_tree_t *tree,
@@ -75,8 +74,9 @@ svn_tree_get_kind(svn_tree_t *tree,
  * versioned properties of the file (not 'wcprops', 'entryprops', etc.).
  * The hash maps (const char *) names to (#svn_string_t *) values.
  *
- * If the node at @a relpath is not a symlink, return a
- * #SVN_ERR_WRONG_KIND error.
+ * If the node at @a relpath 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_get_file(svn_tree_t *tree,
@@ -98,8 +98,9 @@ svn_tree_get_file(svn_tree_t *tree,
  * versioned properties of the file (not 'wcprops', 'entryprops', etc.).
  * The hash maps (const char *) names to (#svn_string_t *) values.
  *
- * If the node at @a relpath is not a symlink, return a
- * #SVN_ERR_WRONG_KIND error.
+ * If the node at @a relpath 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_get_dir(svn_tree_t *tree,
@@ -118,8 +119,9 @@ svn_tree_get_dir(svn_tree_t *tree,
  * versioned properties of the file (not 'wcprops', 'entryprops', etc.).
  * The hash maps (const char *) names to (#svn_string_t *) values.
  *
- * If the node at @a relpath is not a symlink, return a
- * #SVN_ERR_WRONG_KIND error.
+ * If the node at @a relpath is unreadable 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_get_symlink(svn_tree_t *tree,
@@ -129,6 +131,31 @@ svn_tree_get_symlink(svn_tree_t *tree,
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool);
 
+/* */
+typedef svn_error_t *(*svn_tree_walk_func_t)(svn_tree_t *tree,
+                                             const char *relpath,
+                                             svn_kind_t kind,
+                                             void *baton,
+                                             apr_pool_t *scratch_pool);
+
+/** Walk the generic @a tree, starting at @a relpath, recursing to @a depth.
+ * 
+ * Call @a callback_func for each node, passing @a callback_baton and the
+ * node kind. If a node that is reached through recursion is unreadable due
+ * to lack of authorization, pass #svn_kind_unknown for the kind.
+ *
+ * Use @a cancel_func with @a cancel_baton to check for cancellation.
+ */
+svn_error_t *
+svn_tree_walk(svn_tree_t *tree,
+              const char *relpath,
+              svn_depth_t depth,
+              svn_tree_walk_func_t callback_func,
+              void *callback_baton,
+              svn_cancel_func_t cancel_func,
+              void *cancel_baton,
+              apr_pool_t *scratch_pool);
+
 /*-----------------------------------------------------------------*/