You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2012/05/16 22:32:54 UTC

svn commit: r1339349 [20/37] - in /subversion/branches/fix-rdump-editor: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/client-side/vim/ contrib/server-side/ notes/ notes/api-errat...

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/xml.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/xml.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/xml.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/xml.c Wed May 16 20:32:43 2012
@@ -24,9 +24,6 @@
 
 
 #include <apr_uri.h>
-
-#include <expat.h>
-
 #include <serf.h>
 
 #include "svn_pools.h"
@@ -37,121 +34,183 @@
 #include "svn_config.h"
 #include "svn_delta.h"
 #include "svn_path.h"
+
 #include "svn_private_config.h"
+#include "private/svn_string_private.h"
 
 #include "ra_serf.h"
 
 
-void
-svn_ra_serf__define_ns(svn_ra_serf__ns_t **ns_list,
-                       const char **attrs,
-                       apr_pool_t *pool)
+struct svn_ra_serf__xml_context_t {
+  /* Current state information.  */
+  svn_ra_serf__xml_estate_t *current;
+
+  /* If WAITING.NAMESPACE != NULL, wait for NAMESPACE:NAME element to be
+     closed before looking for transitions from CURRENT->STATE.  */
+  svn_ra_serf__dav_props_t waiting;
+
+  /* The transition table.  */
+  const svn_ra_serf__xml_transition_t *ttable;
+
+  /* The callback information.  */
+  svn_ra_serf__xml_opened_t opened_cb;
+  svn_ra_serf__xml_closed_t closed_cb;
+  void *baton;
+
+  /* Linked list of free states.  */
+  svn_ra_serf__xml_estate_t *free_states;
+
+#ifdef SVN_DEBUG
+  /* Used to verify we are not re-entering a callback, specifically to
+     ensure SCRATCH_POOL is not cleared while an outer callback is
+     trying to use it.  */
+  svn_boolean_t within_callback;
+#define START_CALLBACK(xmlctx) \
+  do {                                                    \
+    svn_ra_serf__xml_context_t *xmlctx__tmp = (xmlctx);   \
+    SVN_ERR_ASSERT(!xmlctx__tmp->within_callback);        \
+    xmlctx__tmp->within_callback = TRUE;                  \
+  } while (0)
+#define END_CALLBACK(xmlctx) ((xmlctx)->within_callback = FALSE)
+#else
+#define START_CALLBACK(xmlctx)  /* empty */
+#define END_CALLBACK(xmlctx)  /* empty */
+#endif /* SVN_DEBUG  */
+
+  apr_pool_t *scratch_pool;
+
+};
+
+struct svn_ra_serf__xml_estate_t {
+  /* The current state value.  */
+  int state;
+
+  /* The xml tag that opened this state. Waiting for the tag to close.  */
+  svn_ra_serf__dav_props_t tag;
+
+  /* Should the CLOSED_CB function be called for custom processing when
+     this tag is closed?  */
+  svn_boolean_t custom_close;
+
+  /* A pool may be constructed for this state.  */
+  apr_pool_t *state_pool;
+
+  /* The namespaces extent for this state/element. This will start with
+     the parent's NS_LIST, and we will push new namespaces into our
+     local list. The parent will be unaffected by our locally-scoped data. */
+  svn_ra_serf__ns_t *ns_list;
+
+  /* Any collected attribute values. char * -> svn_string_t *. May be NULL
+     if no attributes have been collected.  */
+  apr_hash_t *attrs;
+
+  /* Any collected cdata. May be NULL if no cdata is being collected.  */
+  svn_stringbuf_t *cdata;
+
+  /* Previous/outer state.  */
+  svn_ra_serf__xml_estate_t *prev;
+
+};
+
+
+static void
+define_namespaces(svn_ra_serf__ns_t **ns_list,
+                  const char *const *attrs,
+                  apr_pool_t *(*get_pool)(void *baton),
+                  void *baton)
 {
-  const char **tmp_attrs = attrs;
+  const char *const *tmp_attrs = attrs;
 
-  while (*tmp_attrs)
+  for (tmp_attrs = attrs; *tmp_attrs != NULL; tmp_attrs += 2)
     {
       if (strncmp(*tmp_attrs, "xmlns", 5) == 0)
         {
-          svn_ra_serf__ns_t *new_ns, *cur_ns;
-          int found = 0;
+          const svn_ra_serf__ns_t *cur_ns;
+          svn_boolean_t found = FALSE;
+          const char *prefix;
+
+          /* The empty prefix, or a named-prefix.  */
+          if (tmp_attrs[0][5] == ':')
+            prefix = &tmp_attrs[0][6];
+          else
+            prefix = "";
 
           /* Have we already defined this ns previously? */
           for (cur_ns = *ns_list; cur_ns; cur_ns = cur_ns->next)
             {
-              if (strcmp(cur_ns->namespace, tmp_attrs[0] + 6) == 0)
+              if (strcmp(cur_ns->namespace, prefix) == 0)
                 {
-                  found = 1;
+                  found = TRUE;
                   break;
                 }
             }
 
           if (!found)
             {
+              apr_pool_t *pool;
+              svn_ra_serf__ns_t *new_ns;
+
+              if (get_pool)
+                pool = get_pool(baton);
+              else
+                pool = baton;
               new_ns = apr_palloc(pool, sizeof(*new_ns));
-              new_ns->namespace = apr_pstrdup(pool, tmp_attrs[0] + 6);
+              new_ns->namespace = apr_pstrdup(pool, prefix);
               new_ns->url = apr_pstrdup(pool, tmp_attrs[1]);
 
+              /* Push into the front of NS_LIST. Parent states will point
+                 to later in the chain, so will be unaffected by
+                 shadowing/other namespaces pushed onto NS_LIST.  */
               new_ns->next = *ns_list;
-
               *ns_list = new_ns;
             }
         }
-      tmp_attrs += 2;
     }
 }
 
+
+void
+svn_ra_serf__define_ns(svn_ra_serf__ns_t **ns_list,
+                       const char *const *attrs,
+                       apr_pool_t *result_pool)
+{
+  define_namespaces(ns_list, attrs, NULL /* get_pool */, result_pool);
+}
+
+
 /*
  * Look up NAME in the NS_LIST list for previously declared namespace
  * definitions and return a DAV_PROPS_T-tuple that has values.
  */
 void
 svn_ra_serf__expand_ns(svn_ra_serf__dav_props_t *returned_prop_name,
-                       svn_ra_serf__ns_t *ns_list,
+                       const svn_ra_serf__ns_t *ns_list,
                        const char *name)
 {
   const char *colon;
-  svn_ra_serf__dav_props_t prop_name;
 
   colon = strchr(name, ':');
   if (colon)
     {
-      svn_ra_serf__ns_t *ns;
-
-      prop_name.namespace = NULL;
+      const svn_ra_serf__ns_t *ns;
 
       for (ns = ns_list; ns; ns = ns->next)
         {
           if (strncmp(ns->namespace, name, colon - name) == 0)
             {
-              prop_name.namespace = ns->url;
-              break;
+              returned_prop_name->namespace = ns->url;
+              returned_prop_name->name = colon + 1;
+              return;
             }
         }
-
-      SVN_ERR_ASSERT_NO_RETURN(prop_name.namespace);
-
-      prop_name.name = colon + 1;
-    }
-  else
-    {
-      /* use default namespace for now */
-      prop_name.namespace = "";
-      prop_name.name = name;
     }
 
-  *returned_prop_name = prop_name;
-  return;
+  /* If there is no prefix, or if the prefix is not found, then the
+     name is NOT within a namespace.  */
+  returned_prop_name->namespace = "";
+  returned_prop_name->name = name;
 }
 
-void
-svn_ra_serf__expand_string(const char **cur, apr_size_t *cur_len,
-                           const char *new, apr_size_t new_len,
-                           apr_pool_t *pool)
-{
-  if (!*cur)
-    {
-      *cur = apr_pstrmemdup(pool, new, new_len);
-      *cur_len = new_len;
-    }
-  else
-    {
-      char *new_cur;
-
-      /* append the data we received before. */
-      new_cur = apr_palloc(pool, *cur_len + new_len + 1);
-
-      memcpy(new_cur, *cur, *cur_len);
-      memcpy(new_cur + *cur_len, new, new_len);
-
-      /* NULL-term our new string */
-      new_cur[*cur_len + new_len] = '\0';
-
-      /* update our length */
-      *cur_len += new_len;
-      *cur = new_cur;
-    }
-}
 
 #define XML_HEADER "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
 
@@ -350,3 +409,344 @@ void svn_ra_serf__xml_pop_state(svn_ra_s
   cur_state->prev = parser->free_state;
   parser->free_state = cur_state;
 }
+
+
+/* Return a pool for XES to use for self-alloc (and other specifics).  */
+static apr_pool_t *
+xes_pool(const svn_ra_serf__xml_estate_t *xes)
+{
+  /* Move up through parent states looking for one with a pool. This
+     will always terminate since the initial state has a pool.  */
+  while (xes->state_pool == NULL)
+    xes = xes->prev;
+  return xes->state_pool;
+}
+
+
+static void
+ensure_pool(svn_ra_serf__xml_estate_t *xes)
+{
+  if (xes->state_pool == NULL)
+    xes->state_pool = svn_pool_create(xes_pool(xes));
+}
+
+
+/* This callback is used by define_namespaces() to wait until a pool is
+   required before constructing it.  */
+static apr_pool_t *
+lazy_create_pool(void *baton)
+{
+  svn_ra_serf__xml_estate_t *xes = baton;
+
+  ensure_pool(xes);
+  return xes->state_pool;
+}
+
+
+svn_ra_serf__xml_context_t *
+svn_ra_serf__xml_context_create(
+  const svn_ra_serf__xml_transition_t *ttable,
+  svn_ra_serf__xml_opened_t opened_cb,
+  svn_ra_serf__xml_closed_t closed_cb,
+  void *baton,
+  apr_pool_t *result_pool)
+{
+  svn_ra_serf__xml_context_t *xmlctx;
+  svn_ra_serf__xml_estate_t *xes;
+
+  xmlctx = apr_pcalloc(result_pool, sizeof(*xmlctx));
+  xmlctx->ttable = ttable;
+  xmlctx->opened_cb = opened_cb;
+  xmlctx->closed_cb = closed_cb;
+  xmlctx->baton = baton;
+  xmlctx->scratch_pool = svn_pool_create(result_pool);
+
+  xes = apr_pcalloc(result_pool, sizeof(*xes));
+  /* XES->STATE == 0  */
+
+  /* Child states may use this pool to allocate themselves. If a child
+     needs to collect information, then it will construct a subpool and
+     will use that to allocate itself and its collected data.  */
+  xes->state_pool = result_pool;
+
+  xmlctx->current = xes;
+
+  return xmlctx;
+}
+
+
+apr_hash_t *
+svn_ra_serf__xml_gather_since(svn_ra_serf__xml_estate_t *xes,
+                              int stop_state)
+{
+  apr_hash_t *data;
+
+  ensure_pool(xes);
+
+  data = apr_hash_make(xes->state_pool);
+
+  /* ### gather data  */
+
+  return data;
+}
+
+
+void
+svn_ra_serf__xml_note(svn_ra_serf__xml_estate_t *xes,
+                      int state,
+                      const char *name,
+                      const char *value)
+{
+  svn_ra_serf__xml_estate_t *scan;
+
+  for (scan = xes; scan != NULL && scan->state != state; scan = scan->prev)
+    /* pass */ ;
+
+  SVN_ERR_ASSERT_NO_RETURN(scan != NULL);
+
+  /* Make sure the target state has a pool.  */
+  ensure_pool(scan);
+
+  /* ... and attribute storage.  */
+  if (scan->attrs == NULL)
+    scan->attrs = apr_hash_make(scan->state_pool);
+
+  /* In all likelihood, NAME is a string constant. But we can't really
+     be sure. And it isn't like we're storing a billion of these into
+     the state pool.  */
+  apr_hash_set(scan->attrs,
+               apr_pstrdup(scan->state_pool, name), APR_HASH_KEY_STRING,
+               apr_pstrdup(scan->state_pool, value));
+}
+
+
+apr_pool_t *
+svn_ra_serf__xml_state_pool(svn_ra_serf__xml_estate_t *xes)
+{
+  /* If they asked for a pool, then ensure that we have one to provide.  */
+  ensure_pool(xes);
+
+  return xes->state_pool;
+}
+
+
+svn_error_t *
+svn_ra_serf__xml_cb_start(svn_ra_serf__xml_context_t *xmlctx,
+                          const char *raw_name,
+                          const char *const *attrs)
+{
+  svn_ra_serf__xml_estate_t *current = xmlctx->current;
+  svn_ra_serf__dav_props_t elemname;
+  const svn_ra_serf__xml_transition_t *scan;
+  apr_pool_t *new_pool;
+  svn_ra_serf__xml_estate_t *new_xes;
+
+  /* If we're waiting for an element to close, then just ignore all
+     other element-opens.  */
+  if (xmlctx->waiting.namespace != NULL)
+    return SVN_NO_ERROR;
+
+  /* Look for xmlns: attributes. Lazily create the state pool if any
+     were found.  */
+  define_namespaces(&current->ns_list, attrs, lazy_create_pool, current);
+
+  svn_ra_serf__expand_ns(&elemname, current->ns_list, raw_name);
+
+  for (scan = xmlctx->ttable; scan->ns != NULL; ++scan)
+    {
+      if (scan->from_state != current->state)
+        continue;
+
+      if (strcmp(elemname.name, scan->name) == 0
+          && strcmp(elemname.namespace, scan->ns) == 0)
+        break;
+    }
+  if (scan->ns == NULL)
+    {
+      xmlctx->waiting = elemname;
+      /* ### return?  */
+      return SVN_NO_ERROR;
+    }
+
+  /* We should not be told to collect cdata if the closed_cb will not
+     be called.  */
+  SVN_ERR_ASSERT(!scan->collect_cdata || scan->custom_close);
+
+  /* Found a transition. Make it happen.  */
+
+  /* ### todo. push state  */
+
+  /* ### how to use free states?  */
+  /* This state should be allocated in the extent pool. If we will be
+     collecting information for this state, then construct a subpool.
+
+     ### potentially optimize away the subpool if none of the
+     ### attributes are present. subpools are cheap, tho...  */
+  new_pool = xes_pool(current);
+  if (scan->collect_cdata || scan->collect_attrs[0])
+    {
+      new_pool = svn_pool_create(new_pool);
+
+      /* Prep the new state.  */
+      new_xes = apr_pcalloc(new_pool, sizeof(*new_xes));
+      new_xes->state_pool = new_pool;
+
+      /* If we're supposed to collect cdata, then set up a buffer for
+         this. The existence of this buffer will instruct our cdata
+         callback to collect the cdata.  */
+      if (scan->collect_cdata)
+        new_xes->cdata = svn_stringbuf_create_empty(new_pool);
+
+      if (scan->collect_attrs[0] != NULL)
+        {
+          const char *const *saveattr = &scan->collect_attrs[0];
+
+          new_xes->attrs = apr_hash_make(new_pool);
+          for (; *saveattr != NULL; ++saveattr)
+            {
+              const char *name;
+              const char *value;
+
+              if (**saveattr == '?')
+                {
+                  name = *saveattr + 1;
+                  value = svn_xml_get_attr_value(name, attrs);
+                }
+              else
+                {
+                  name = *saveattr;
+                  value = svn_xml_get_attr_value(name, attrs);
+                  if (value == NULL)
+                    return svn_error_createf(SVN_ERR_XML_ATTRIB_NOT_FOUND,
+                                             NULL,
+                                             _("Missing XML attribute: '%s'"),
+                                             name);
+                }
+
+              if (value)
+                apr_hash_set(new_xes->attrs, name, APR_HASH_KEY_STRING, value);
+            }
+        }
+    }
+  else
+    {
+      /* Prep the new state.  */
+      new_xes = apr_pcalloc(new_pool, sizeof(*new_xes));
+      /* STATE_POOL remains NULL.  */
+    }
+
+  /* Some basic copies to set up the new estate.  */
+  new_xes->state = scan->to_state;
+  new_xes->tag = elemname;
+  new_xes->custom_close = scan->custom_close;
+
+  /* Start with the parent's namespace set.  */
+  new_xes->ns_list = current->ns_list;
+
+  /* The new state is prepared. Make it current.  */
+  new_xes->prev = current;
+  xmlctx->current = new_xes;
+
+  if (scan->custom_open)
+    {
+      START_CALLBACK(xmlctx);
+      SVN_ERR(xmlctx->opened_cb(new_xes, xmlctx->baton,
+                                new_xes->state, xmlctx->scratch_pool));
+      END_CALLBACK(xmlctx);
+      svn_pool_clear(xmlctx->scratch_pool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_ra_serf__xml_cb_end(svn_ra_serf__xml_context_t *xmlctx,
+                        const char *raw_name)
+{
+  svn_ra_serf__xml_estate_t *xes = xmlctx->current;
+  svn_ra_serf__dav_props_t elemname;
+
+  svn_ra_serf__expand_ns(&elemname, xes->ns_list, raw_name);
+
+  if (xmlctx->waiting.namespace != NULL)
+    {
+      /* If this element is not the closer, then keep waiting... */
+      if (strcmp(elemname.name, xmlctx->waiting.name) != 0
+          || strcmp(elemname.namespace, xmlctx->waiting.namespace) != 0)
+        return SVN_NO_ERROR;
+
+      /* Found it. Stop waiting, and go back for more.  */
+      xmlctx->waiting.namespace = NULL;
+      return SVN_NO_ERROR;
+    }
+
+  /* We should be looking at the same tag that opened the current state.
+
+     Unknown elements are simply skipped, so we wouldn't reach this check.
+
+     Known elements push a new state for a given tag. Some other elemname
+     would imply closing an ancestor tag (where did ours go?) or a spurious
+     tag closure.  */
+  if (strcmp(elemname.name, xes->tag.name) != 0
+      || strcmp(elemname.namespace, xes->tag.namespace) != 0)
+    return svn_error_create(SVN_ERR_XML_MALFORMED, NULL,
+                            _("The response contains invalid XML"));
+
+  if (xes->custom_close)
+    {
+      const svn_string_t *cdata;
+
+      if (xes->cdata)
+        {
+          cdata = svn_stringbuf__morph_into_string(xes->cdata);
+#ifdef SVN_DEBUG
+          /* We might toss the pool holding this structure, but it could also
+             be within a parent pool. In any case, for safety's sake, disable
+             the stringbuf against future Badness.  */
+          xes->cdata->pool = NULL;
+#endif
+        }
+      else
+        cdata = NULL;
+
+      START_CALLBACK(xmlctx);
+      SVN_ERR(xmlctx->closed_cb(xes, xmlctx->baton, xes->state,
+                                cdata, xes->attrs,
+                                xmlctx->scratch_pool));
+      END_CALLBACK(xmlctx);
+      svn_pool_clear(xmlctx->scratch_pool);
+    }
+
+  /* Pop the state.  */
+  xmlctx->current = xes->prev;
+
+  /* ### not everything should go on the free state list. XES may go
+     ### away with the state pool.  */
+  xes->prev = xmlctx->free_states;
+  xmlctx->free_states = xes;
+
+  /* If there is a STATE_POOL, then toss it. This will get rid of as much
+     memory as possible. Potentially the XES (if we didn't create a pool
+     right away, then XES may be in a parent pool).  */
+  if (xes->state_pool)
+    svn_pool_destroy(xes->state_pool);
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_ra_serf__xml_cb_cdata(svn_ra_serf__xml_context_t *xmlctx,
+                          const char *data,
+                          apr_size_t len)
+{
+  /* If we're collecting cdata, but NOT waiting for a closing tag
+     (ie. not within an unknown tag), then copy the cdata.  */
+  if (xmlctx->current->cdata != NULL
+      && xmlctx->waiting.namespace == NULL)
+    svn_stringbuf_appendbytes(xmlctx->current->cdata, data, len);
+
+  return SVN_NO_ERROR;
+}
+

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/client.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/client.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/client.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/client.c Wed May 16 20:32:43 2012
@@ -1152,7 +1152,18 @@ static svn_error_t *ra_svn_get_dir(svn_r
       dirent->size = size;/* FIXME: svn_filesize_t */
       dirent->has_props = has_props;
       dirent->created_rev = crev;
-      SVN_ERR(svn_time_from_cstring(&dirent->time, cdate, pool));
+      /* NOTE: the tuple's format string says CDATE may be NULL. But this
+         function does not allow that. The server has always sent us some
+         random date, however, so this just happens to work. But let's
+         be wary of servers that are (improperly) fixed to send NULL.
+
+         Note: they should NOT be "fixed" to send NULL, as that would break
+         any older clients which received that NULL. But we may as well
+         be defensive against a malicous server.  */
+      if (cdate == NULL)
+        dirent->time = 0;
+      else
+        SVN_ERR(svn_time_from_cstring(&dirent->time, cdate, pool));
       dirent->last_author = cauthor;
       apr_hash_set(*dirents, name, APR_HASH_KEY_STRING, dirent);
     }

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/cyrus_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/cyrus_auth.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/cyrus_auth.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/cyrus_auth.c Wed May 16 20:32:43 2012
@@ -533,7 +533,7 @@ static svn_error_t *try_auth(svn_ra_svn_
       clear_sasl_errno();
       result = sasl_client_step(sasl_ctx,
                                 in->data,
-                                in->len,
+                                (const unsigned int) in->len,
                                 &client_interact,
                                 &out, /* Filled in by SASL. */
                                 &outlen);
@@ -620,7 +620,7 @@ static svn_error_t *sasl_read_cb(void *b
           return SVN_NO_ERROR;
         }
       clear_sasl_errno();
-      result = sasl_decode(sasl_baton->ctx, buffer, len2,
+      result = sasl_decode(sasl_baton->ctx, buffer, (unsigned int) len2,
                            &sasl_baton->read_buf,
                            &sasl_baton->read_len);
       if (result != SASL_OK)
@@ -662,7 +662,7 @@ sasl_write_cb(void *baton, const char *b
       /* Make sure we don't write too much. */
       *len = (*len > sasl_baton->maxsize) ? sasl_baton->maxsize : *len;
       clear_sasl_errno();
-      result = sasl_encode(sasl_baton->ctx, buffer, *len,
+      result = sasl_encode(sasl_baton->ctx, buffer, (unsigned int) *len,
                            &sasl_baton->write_buf,
                            &sasl_baton->write_len);
 
@@ -755,9 +755,8 @@ svn_error_t *svn_ra_svn__enable_sasl_enc
             {
               clear_sasl_errno();
               result = sasl_decode(sasl_ctx, conn->read_ptr,
-                                   conn->read_end - conn->read_ptr,
-                                   &sasl_baton->read_buf,
-                                   &sasl_baton->read_len);
+                             (unsigned int) (conn->read_end - conn->read_ptr),
+                             &sasl_baton->read_buf, &sasl_baton->read_len);
               if (result != SASL_OK)
                 return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                         get_sasl_error(sasl_ctx, result, pool));

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/editorp.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/editorp.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/editorp.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/editorp.c Wed May 16 20:32:43 2012
@@ -437,7 +437,8 @@ void svn_ra_svn_get_editor(const svn_del
   *edit_baton = eb;
 
   svn_error_clear(svn_editor__insert_shims(editor, edit_baton, *editor,
-                                           *edit_baton, conn->shim_callbacks,
+                                           *edit_baton, NULL, NULL,
+                                           conn->shim_callbacks,
                                            pool, pool));
 }
 

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/marshal.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/marshal.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/marshal.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/marshal.c Wed May 16 20:32:43 2012
@@ -231,7 +231,7 @@ static svn_error_t *writebuf_output(svn_
 /* Write data from the write buffer out to the socket. */
 static svn_error_t *writebuf_flush(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
 {
-  int write_pos = conn->write_pos;
+  apr_size_t write_pos = conn->write_pos;
 
   /* Clear conn->write_pos first in case the block handler does a read. */
   conn->write_pos = 0;
@@ -258,19 +258,36 @@ static svn_error_t *writebuf_write(svn_r
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *writebuf_printf(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                    const char *fmt, ...)
-  __attribute__ ((format(printf, 3, 4)));
-static svn_error_t *writebuf_printf(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
-                                    const char *fmt, ...)
+static svn_error_t *
+writebuf_write_short_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
+                            const char *data, apr_size_t len)
+{
+  apr_size_t left = sizeof(conn->write_buf) - conn->write_pos;
+  if (len <= left)
+  {
+    memcpy(conn->write_buf + conn->write_pos, data, len);
+    conn->write_pos += len;
+    return SVN_NO_ERROR;
+  }
+  else
+    return writebuf_write(conn, pool, data, len);
+}
+
+static APR_INLINE svn_error_t *
+writebuf_writechar(svn_ra_svn_conn_t *conn, apr_pool_t *pool, char data)
 {
-  va_list ap;
-  char *str;
+  if (conn->write_pos < sizeof(conn->write_buf))
+  {
+    conn->write_buf[conn->write_pos] = data;
+    conn->write_pos++;
 
-  va_start(ap, fmt);
-  str = apr_pvsprintf(pool, fmt, ap);
-  va_end(ap);
-  return writebuf_write(conn, pool, str, strlen(str));
+    return SVN_NO_ERROR;
+  }
+  else
+  {
+    char temp = data;
+    return writebuf_write(conn, pool, &temp, 1);
+  }
 }
 
 /* --- READ BUFFER MANAGEMENT --- */
@@ -417,31 +434,71 @@ static svn_error_t *readbuf_skip_leading
 
 /* --- WRITING DATA ITEMS --- */
 
+static svn_error_t *write_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
+                                 apr_uint64_t number, char follow)
+{
+  apr_size_t written;
+
+  /* SVN_INT64_BUFFER_SIZE includes space for a terminating NUL that
+   * svn__ui64toa will always append. */
+  if (conn->write_pos + SVN_INT64_BUFFER_SIZE >= sizeof(conn->write_buf))
+    SVN_ERR(writebuf_flush(conn, pool));
+
+  written = svn__ui64toa(conn->write_buf + conn->write_pos, number);
+  conn->write_buf[conn->write_pos + written] = follow;
+  conn->write_pos += written + 1;
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *svn_ra_svn_write_number(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                                      apr_uint64_t number)
 {
-  return writebuf_printf(conn, pool, "%" APR_UINT64_T_FMT " ", number);
+  return write_number(conn, pool, number, ' ');
 }
 
 svn_error_t *svn_ra_svn_write_string(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                                      const svn_string_t *str)
 {
-  SVN_ERR(writebuf_printf(conn, pool, "%" APR_SIZE_T_FMT ":", str->len));
+  if (str->len < 10)
+    {
+      SVN_ERR(writebuf_writechar(conn, pool, (char)str->len + '0'));
+      SVN_ERR(writebuf_writechar(conn, pool, ':'));
+    }
+  else
+    SVN_ERR(write_number(conn, pool, str->len, ':'));
+
   SVN_ERR(writebuf_write(conn, pool, str->data, str->len));
-  SVN_ERR(writebuf_write(conn, pool, " ", 1));
+  SVN_ERR(writebuf_writechar(conn, pool, ' '));
   return SVN_NO_ERROR;
 }
 
 svn_error_t *svn_ra_svn_write_cstring(svn_ra_svn_conn_t *conn,
                                       apr_pool_t *pool, const char *s)
 {
-  return writebuf_printf(conn, pool, "%" APR_SIZE_T_FMT ":%s ", strlen(s), s);
+  apr_size_t len = strlen(s);
+
+  if (len < 10)
+    {
+      SVN_ERR(writebuf_writechar(conn, pool, (char)len + '0'));
+      SVN_ERR(writebuf_writechar(conn, pool, ':'));
+    }
+  else
+    SVN_ERR(write_number(conn, pool, len, ':'));
+
+  SVN_ERR(writebuf_write(conn, pool, s, len));
+  SVN_ERR(writebuf_writechar(conn, pool, ' '));
+
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *svn_ra_svn_write_word(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                                    const char *word)
 {
-  return writebuf_printf(conn, pool, "%s ", word);
+  SVN_ERR(writebuf_write_short_string(conn, pool, word, strlen(word)));
+  SVN_ERR(writebuf_writechar(conn, pool, ' '));
+
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *svn_ra_svn_write_proplist(svn_ra_svn_conn_t *conn,
@@ -474,11 +531,27 @@ svn_error_t *svn_ra_svn_write_proplist(s
 
 svn_error_t *svn_ra_svn_start_list(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
 {
+  if (conn->write_pos + 2 <= sizeof(conn->write_buf))
+    {
+      conn->write_buf[conn->write_pos] = '(';
+      conn->write_buf[conn->write_pos+1] = ' ';
+      conn->write_pos += 2;
+      return SVN_NO_ERROR;
+    }
+
   return writebuf_write(conn, pool, "( ", 2);
 }
 
 svn_error_t *svn_ra_svn_end_list(svn_ra_svn_conn_t *conn, apr_pool_t *pool)
 {
+  if (conn->write_pos + 2 <= sizeof(conn->write_buf))
+  {
+    conn->write_buf[conn->write_pos] = ')';
+    conn->write_buf[conn->write_pos+1] = ' ';
+    conn->write_pos += 2;
+    return SVN_NO_ERROR;
+  }
+
   return writebuf_write(conn, pool, ") ", 2);
 }
 
@@ -503,50 +576,54 @@ static svn_error_t *vwrite_tuple(svn_ra_
     SVN_ERR(svn_ra_svn_start_list(conn, pool));
   for (; *fmt; fmt++)
     {
-      if (*fmt == 'n' && !opt)
-        SVN_ERR(svn_ra_svn_write_number(conn, pool, va_arg(ap, apr_uint64_t)));
-      else if (*fmt == 'r')
+      if (*fmt == 'c')
         {
-          rev = va_arg(ap, svn_revnum_t);
-          SVN_ERR_ASSERT(opt || SVN_IS_VALID_REVNUM(rev));
-          if (SVN_IS_VALID_REVNUM(rev))
-            SVN_ERR(svn_ra_svn_write_number(conn, pool, rev));
+          cstr = va_arg(ap, const char *);
+          if (cstr)
+            SVN_ERR(svn_ra_svn_write_cstring(conn, pool, cstr));
+          else
+            SVN_ERR_ASSERT(opt);
         }
       else if (*fmt == 's')
         {
           str = va_arg(ap, const svn_string_t *);
-          SVN_ERR_ASSERT(opt || str);
           if (str)
             SVN_ERR(svn_ra_svn_write_string(conn, pool, str));
+          else
+            SVN_ERR_ASSERT(opt);
         }
-      else if (*fmt == 'c')
+      else if (*fmt == '(' && !opt)
+        SVN_ERR(svn_ra_svn_start_list(conn, pool));
+      else if (*fmt == ')')
         {
-          cstr = va_arg(ap, const char *);
-          SVN_ERR_ASSERT(opt || cstr);
-          if (cstr)
-            SVN_ERR(svn_ra_svn_write_cstring(conn, pool, cstr));
+          SVN_ERR(svn_ra_svn_end_list(conn, pool));
+          opt = FALSE;
         }
+      else if (*fmt == '?')
+        opt = TRUE;
       else if (*fmt == 'w')
         {
           cstr = va_arg(ap, const char *);
-          SVN_ERR_ASSERT(opt || cstr);
           if (cstr)
             SVN_ERR(svn_ra_svn_write_word(conn, pool, cstr));
+          else
+            SVN_ERR_ASSERT(opt);
         }
+      else if (*fmt == 'r')
+        {
+          rev = va_arg(ap, svn_revnum_t);
+          if (SVN_IS_VALID_REVNUM(rev))
+            SVN_ERR(svn_ra_svn_write_number(conn, pool, rev));
+          else
+            SVN_ERR_ASSERT(opt);
+        }
+      else if (*fmt == 'n' && !opt)
+        SVN_ERR(svn_ra_svn_write_number(conn, pool, va_arg(ap, apr_uint64_t)));
       else if (*fmt == 'b' && !opt)
         {
           cstr = va_arg(ap, svn_boolean_t) ? "true" : "false";
           SVN_ERR(svn_ra_svn_write_word(conn, pool, cstr));
         }
-      else if (*fmt == '?')
-        opt = TRUE;
-      else if (*fmt == '(' && !opt)
-        SVN_ERR(svn_ra_svn_start_list(conn, pool));
-      else if (*fmt == ')')
-        {
-          SVN_ERR(svn_ra_svn_end_list(conn, pool));
-          opt = FALSE;
-        }
       else if (*fmt == '!' && !*(fmt + 1))
         return SVN_NO_ERROR;
       else
@@ -668,7 +745,8 @@ static svn_error_t *read_item(svn_ra_svn
           if (!svn_ctype_isdigit(c))
             break;
           val = val * 10 + (c - '0');
-          if ((val / 10) != prev_val) /* val wrapped past maximum value */
+          /* val wrapped past maximum value? */
+          if (prev_val >= (APR_UINT64_MAX / 10) && (val / 10) != prev_val)
             return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                     _("Number is larger than maximum"));
         }

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/ra_svn.h
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/ra_svn.h?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/ra_svn.h (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_svn/ra_svn.h Wed May 16 20:32:43 2012
@@ -57,8 +57,8 @@ typedef svn_error_t *(*ra_svn_block_hand
                                                void *baton);
 
 /* The size of our per-connection read and write buffers. */
-#define SVN_RA_SVN__READBUF_SIZE 4096
-#define SVN_RA_SVN__WRITEBUF_SIZE 4096
+#define SVN_RA_SVN__READBUF_SIZE (4*4096)
+#define SVN_RA_SVN__WRITEBUF_SIZE (4*4096)
 
 /* Create forward reference */
 typedef struct svn_ra_svn__session_baton_t svn_ra_svn__session_baton_t;
@@ -79,7 +79,7 @@ struct svn_ra_svn_conn_st {
   char *read_ptr;
   char *read_end;
   char write_buf[SVN_RA_SVN__WRITEBUF_SIZE];
-  int write_pos;
+  apr_size_t write_pos;
   const char *uuid;
   const char *repos_root;
   ra_svn_block_handler_t block_handler;

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_repos/commit.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_repos/commit.c Wed May 16 20:32:43 2012
@@ -37,8 +37,11 @@
 #include "svn_checksum.h"
 #include "svn_props.h"
 #include "svn_mergeinfo.h"
-#include "repos.h"
 #include "svn_private_config.h"
+#include "svn_editor.h"
+
+#include "repos.h"
+
 #include "private/svn_fspath.h"
 #include "private/svn_repos_private.h"
 
@@ -128,6 +131,29 @@ struct file_baton
 };
 
 
+struct ev2_baton
+{
+  /* The repository we are editing.  */
+  svn_repos_t *repos;
+
+  /* The authz baton for checks; NULL to skip authz.  */
+  svn_authz_t *authz;
+
+  /* The repository name and user for performing authz checks.  */
+  const char *authz_repos_name;
+  const char *authz_user;
+
+  /* Callback to provide info about the committed revision.  */
+  svn_commit_callback2_t commit_cb;
+  void *commit_baton;
+
+  /* The FS txn editor  */
+  svn_editor_t *inner;
+
+  /* The name of the open transaction (so we know what to commit)  */
+  const char *txn_name;
+};
+
 
 /* Create and return a generic out-of-dateness error. */
 static svn_error_t *
@@ -143,6 +169,40 @@ out_of_date(const char *path, svn_node_k
 }
 
 
+static svn_error_t *
+invoke_commit_cb(svn_commit_callback2_t commit_cb,
+                 void *commit_baton,
+                 svn_fs_t *fs,
+                 svn_revnum_t revision,
+                 const char *post_commit_errstr,
+                 apr_pool_t *scratch_pool)
+{
+  /* FS interface returns non-const values.  */
+  /* const */ svn_string_t *date;
+  /* const */ svn_string_t *author;
+  svn_commit_info_t *commit_info;
+
+  if (commit_cb == NULL)
+    return SVN_NO_ERROR;
+
+  SVN_ERR(svn_fs_revision_prop(&date, fs, revision, SVN_PROP_REVISION_DATE,
+                               scratch_pool));
+  SVN_ERR(svn_fs_revision_prop(&author, fs, revision,
+                               SVN_PROP_REVISION_AUTHOR,
+                               scratch_pool));
+
+  commit_info = svn_create_commit_info(scratch_pool);
+
+  /* fill up the svn_commit_info structure */
+  commit_info->revision = revision;
+  commit_info->date = date ? date->data : NULL;
+  commit_info->author = author ? author->data : NULL;
+  commit_info->post_commit_err = post_commit_errstr;
+
+  return svn_error_trace(commit_cb(commit_info, commit_baton, scratch_pool));
+}
+
+
 
 /* If EDITOR_BATON contains a valid authz callback, verify that the
    REQUIRED access to PATH in ROOT is authorized.  Return an error
@@ -631,7 +691,8 @@ svn_repos__post_commit_error_str(svn_err
   else
     hook_err2 = hook_err1;
 
-  /* This implementation counts on svn_repos_fs_commit_txn() returning
+  /* This implementation counts on svn_repos_fs_commit_txn() and
+     libsvn_repos/commit.c:complete_cb() returning
      svn_fs_commit_txn() as the parent error with a child
      SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED error.  If the parent error
      is SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED then there was no error
@@ -703,7 +764,6 @@ close_edit(void *edit_baton,
              display it as a warning) and clear the error. */
           post_commit_err = svn_repos__post_commit_error_str(err, pool);
           svn_error_clear(err);
-          err = SVN_NO_ERROR;
         }
     }
   else
@@ -730,41 +790,19 @@ close_edit(void *edit_baton,
                                          svn_fs_abort_txn(eb->txn, pool)));
     }
 
-  /* Pass new revision information to the caller's callback. */
-  {
-    svn_string_t *date, *author;
-    svn_commit_info_t *commit_info;
-
-    /* Even if there was a post-commit hook failure, it's more serious
-       if one of the calls here fails, so we explicitly check for errors
-       here, while saving the possible post-commit error for later. */
-
-    err = svn_fs_revision_prop(&date, svn_repos_fs(eb->repos),
-                                new_revision, SVN_PROP_REVISION_DATE,
-                                pool);
-    if (! err)
-      {
-        err = svn_fs_revision_prop(&author, svn_repos_fs(eb->repos),
-                                   new_revision, SVN_PROP_REVISION_AUTHOR,
-                                   pool);
-      }
-
-    if ((! err) && eb->commit_callback)
-      {
-        commit_info = svn_create_commit_info(pool);
-
-        /* fill up the svn_commit_info structure */
-        commit_info->revision = new_revision;
-        commit_info->date = date ? date->data : NULL;
-        commit_info->author = author ? author->data : NULL;
-        commit_info->post_commit_err = post_commit_err;
-        err = (*eb->commit_callback)(commit_info,
-                                     eb->commit_callback_baton,
-                                     pool);
-      }
-  }
+  /* At this point, the post-commit error has been converted to a string.
+     That information will be passed to a callback, if provided. If the
+     callback invocation fails in some way, that failure is returned here.
+     IOW, the post-commit error information is low priority compared to
+     other gunk here.  */
 
-  return svn_error_trace(err);
+  /* Pass new revision information to the caller's callback. */
+  return svn_error_trace(invoke_commit_cb(eb->commit_callback,
+                                          eb->commit_callback_baton,
+                                          eb->repos->fs,
+                                          new_revision,
+                                          post_commit_err,
+                                          pool));
 }
 
 
@@ -783,33 +821,6 @@ abort_edit(void *edit_baton,
 
 
 static svn_error_t *
-rationalize_shim_path(const char **fs_path,
-                      struct edit_baton *eb,
-                      const char *path,
-                      apr_pool_t *result_pool,
-                      apr_pool_t *scratch_pool)
-{
-  if (svn_path_is_url(path))
-    {
-      /* This is a copyfrom URL. */
-      path = svn_uri_skip_ancestor(eb->repos_url, path, scratch_pool);
-      *fs_path = svn_fspath__canonicalize(path, scratch_pool);
-    }
-  else
-    {
-      /* This is a base-relative path. */
-      if (path[0] != '/')
-        /* Get an absolute path for use in the FS. */
-        *fs_path = svn_fspath__join(eb->base_path, path, scratch_pool);
-      else
-        *fs_path = path;
-    }
-
-  return SVN_NO_ERROR;
-}
-
-
-static svn_error_t *
 fetch_props_func(apr_hash_t **props,
                  void *baton,
                  const char *path,
@@ -821,7 +832,6 @@ fetch_props_func(apr_hash_t **props,
   svn_fs_root_t *fs_root;
   svn_error_t *err;
 
-  SVN_ERR(rationalize_shim_path(&path, eb, path, scratch_pool, scratch_pool));
   SVN_ERR(svn_fs_revision_root(&fs_root, eb->fs,
                                svn_fs_txn_base_revision(eb->txn),
                                scratch_pool));
@@ -852,7 +862,6 @@ fetch_kind_func(svn_kind_t *kind,
   if (!SVN_IS_VALID_REVNUM(base_revision))
     base_revision = svn_fs_txn_base_revision(eb->txn);
 
-  SVN_ERR(rationalize_shim_path(&path, eb, path, scratch_pool, scratch_pool));
   SVN_ERR(svn_fs_revision_root(&fs_root, eb->fs, base_revision, scratch_pool));
 
   SVN_ERR(svn_fs_check_path(&node_kind, fs_root, path, scratch_pool));
@@ -879,7 +888,6 @@ fetch_base_func(const char **filename,
   if (!SVN_IS_VALID_REVNUM(base_revision))
     base_revision = svn_fs_txn_base_revision(eb->txn);
 
-  SVN_ERR(rationalize_shim_path(&path, eb, path, scratch_pool, scratch_pool));
   SVN_ERR(svn_fs_revision_root(&fs_root, eb->fs, base_revision, scratch_pool));
 
   err = svn_fs_file_contents(&contents, fs_root, path, scratch_pool);
@@ -981,7 +989,378 @@ svn_repos_get_commit_editor5(const svn_d
   shim_callbacks->fetch_baton = eb;
 
   SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
+                                   eb->repos_url, eb->base_path,
                                    shim_callbacks, pool, pool));
 
   return SVN_NO_ERROR;
 }
+
+
+#if 0
+static svn_error_t *
+ev2_check_authz(const struct ev2_baton *eb,
+                const char *relpath,
+                svn_repos_authz_access_t required,
+                apr_pool_t *scratch_pool)
+{
+  const char *fspath;
+  svn_boolean_t allowed;
+
+  if (eb->authz == NULL)
+    return SVN_NO_ERROR;
+
+  if (relpath)
+    fspath = apr_pstrcat(scratch_pool, "/", relpath, NULL);
+  else
+    fspath = NULL;
+
+  SVN_ERR(svn_repos_authz_check_access(eb->authz, eb->authz_repos_name, fspath,
+                                       eb->authz_user, required,
+                                       &allowed, scratch_pool));
+  if (!allowed)
+    return svn_error_create(required & svn_authz_write
+                            ? SVN_ERR_AUTHZ_UNWRITABLE
+                            : SVN_ERR_AUTHZ_UNREADABLE,
+                            NULL, "Access denied");
+
+  return SVN_NO_ERROR;
+}
+#endif
+
+
+/* This implements svn_editor_cb_add_directory_t */
+static svn_error_t *
+add_directory_cb(void *baton,
+                 const char *relpath,
+                 const apr_array_header_t *children,
+                 apr_hash_t *props,
+                 svn_revnum_t replaces_rev,
+                 apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_add_directory(eb->inner, relpath, children, props,
+                                   replaces_rev));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_add_file_t */
+static svn_error_t *
+add_file_cb(void *baton,
+            const char *relpath,
+            const svn_checksum_t *checksum,
+            svn_stream_t *contents,
+            apr_hash_t *props,
+            svn_revnum_t replaces_rev,
+            apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_add_file(eb->inner, relpath, checksum, contents, props,
+                              replaces_rev));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_add_symlink_t */
+static svn_error_t *
+add_symlink_cb(void *baton,
+               const char *relpath,
+               const char *target,
+               apr_hash_t *props,
+               svn_revnum_t replaces_rev,
+               apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_add_symlink(eb->inner, relpath, target, props,
+                                 replaces_rev));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_add_absent_t */
+static svn_error_t *
+add_absent_cb(void *baton,
+              const char *relpath,
+              svn_kind_t kind,
+              svn_revnum_t replaces_rev,
+              apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_add_absent(eb->inner, relpath, kind, replaces_rev));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_alter_directory_t */
+static svn_error_t *
+alter_directory_cb(void *baton,
+                   const char *relpath,
+                   svn_revnum_t revision,
+                   const apr_array_header_t *children,
+                   apr_hash_t *props,
+                   apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_alter_directory(eb->inner, relpath, revision,
+                                     children, props));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_alter_file_t */
+static svn_error_t *
+alter_file_cb(void *baton,
+              const char *relpath,
+              svn_revnum_t revision,
+              apr_hash_t *props,
+              const svn_checksum_t *checksum,
+              svn_stream_t *contents,
+              apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_alter_file(eb->inner, relpath, revision, props,
+                                checksum, contents));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_alter_symlink_t */
+static svn_error_t *
+alter_symlink_cb(void *baton,
+                 const char *relpath,
+                 svn_revnum_t revision,
+                 apr_hash_t *props,
+                 const char *target,
+                 apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_alter_symlink(eb->inner, relpath, revision, props,
+                                   target));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_delete_t */
+static svn_error_t *
+delete_cb(void *baton,
+          const char *relpath,
+          svn_revnum_t revision,
+          apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_delete(eb->inner, relpath, revision));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_copy_t */
+static svn_error_t *
+copy_cb(void *baton,
+        const char *src_relpath,
+        svn_revnum_t src_revision,
+        const char *dst_relpath,
+        svn_revnum_t replaces_rev,
+        apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_copy(eb->inner, src_relpath, src_revision, dst_relpath,
+                          replaces_rev));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_move_t */
+static svn_error_t *
+move_cb(void *baton,
+        const char *src_relpath,
+        svn_revnum_t src_revision,
+        const char *dst_relpath,
+        svn_revnum_t replaces_rev,
+        apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_move(eb->inner, src_relpath, src_revision, dst_relpath,
+                          replaces_rev));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_rotate_t */
+static svn_error_t *
+rotate_cb(void *baton,
+          const apr_array_header_t *relpaths,
+          const apr_array_header_t *revisions,
+          apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_rotate(eb->inner, relpaths, revisions));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_complete_t */
+static svn_error_t *
+complete_cb(void *baton,
+            apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+  svn_revnum_t revision;
+  svn_error_t *post_commit_err;
+  const char *conflict_path;
+  svn_error_t *err;
+  const char *post_commit_errstr;
+
+  /* The transaction has been fully edited. Let the pre-commit hook
+     have a look at the thing.  */
+  SVN_ERR(svn_repos__hooks_pre_commit(eb->repos, eb->txn_name, scratch_pool));
+
+  /* Hook is done. Let's do the actual commit.  */
+  SVN_ERR(svn_fs_editor_commit(&revision, &post_commit_err, &conflict_path,
+                               eb->inner, scratch_pool, scratch_pool));
+
+  /* Did a conflict occur during the commit process?  */
+  if (conflict_path != NULL)
+    return svn_error_createf(SVN_ERR_FS_CONFLICT, NULL,
+                             _("Conflict at '%s'"), conflict_path);
+
+  /* Since did not receive an error during the commit process, and no
+     conflict was specified... we committed a revision. Run the hooks.
+     Other errors may have occurred within the FS (specified by the
+     POST_COMMIT_ERR localvar), but we need to run the hooks.  */
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
+  err = svn_repos__hooks_post_commit(eb->repos, revision, eb->txn_name,
+                                     scratch_pool);
+  if (err)
+    err = svn_error_create(SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err,
+                           _("Commit succeeded, but post-commit hook failed"));
+
+  /* Combine the FS errors with the hook errors, and stringify.  */
+  err = svn_error_compose_create(post_commit_err, err);
+  if (err)
+    {
+      post_commit_errstr = svn_repos__post_commit_error_str(err, scratch_pool);
+      svn_error_clear(err);
+    }
+  else
+    {
+      post_commit_errstr = NULL;
+    }
+
+  return svn_error_trace(invoke_commit_cb(eb->commit_cb, eb->commit_baton,
+                                          eb->repos->fs, revision,
+                                          post_commit_errstr,
+                                          scratch_pool));
+}
+
+
+/* This implements svn_editor_cb_abort_t */
+static svn_error_t *
+abort_cb(void *baton,
+         apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_abort(eb->inner));
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+apply_revprops(svn_fs_t *fs,
+               const char *txn_name,
+               apr_hash_t *revprops,
+               apr_pool_t *scratch_pool)
+{
+  svn_fs_txn_t *txn;
+  const apr_array_header_t *revprops_array;
+
+  /* The FS editor has a TXN inside it, but we can't access it. Open another
+     based on the TXN_NAME.  */
+  SVN_ERR(svn_fs_open_txn(&txn, fs, txn_name, scratch_pool));
+
+  /* Validate and apply the revision properties.  */
+  revprops_array = svn_prop_hash_to_array(revprops, scratch_pool);
+  SVN_ERR(svn_repos_fs_change_txn_props(txn, revprops_array, scratch_pool));
+
+  /* ### do we need to force the txn to close, or is it enough to wait
+     ### for the pool to be cleared?  */
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_repos__get_commit_ev2(svn_editor_t **editor,
+                          svn_repos_t *repos,
+                          svn_authz_t *authz,
+                          const char *authz_repos_name,
+                          const char *authz_user,
+                          apr_hash_t *revprops,
+                          svn_commit_callback2_t commit_cb,
+                          void *commit_baton,
+                          svn_cancel_func_t cancel_func,
+                          void *cancel_baton,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
+{
+  static const svn_editor_cb_many_t editor_cbs = {
+    add_directory_cb,
+    add_file_cb,
+    add_symlink_cb,
+    add_absent_cb,
+    alter_directory_cb,
+    alter_file_cb,
+    alter_symlink_cb,
+    delete_cb,
+    copy_cb,
+    move_cb,
+    rotate_cb,
+    complete_cb,
+    abort_cb
+  };
+  struct ev2_baton *eb;
+  const svn_string_t *author;
+
+  /* Can the user modify the repository at all?  */
+  /* ### check against AUTHZ.  */
+
+  /* Okay... some access is allowed. Let's run the start-commit hook.  */
+  author = apr_hash_get(revprops, SVN_PROP_REVISION_AUTHOR,
+                        APR_HASH_KEY_STRING);
+  SVN_ERR(svn_repos__hooks_start_commit(repos, author ? author->data : NULL,
+                                        repos->client_capabilities,
+                                        scratch_pool));
+
+  eb = apr_palloc(result_pool, sizeof(*eb));
+  eb->repos = repos;
+  eb->authz = authz;
+  eb->authz_repos_name = authz_repos_name;
+  eb->authz_user = authz_user;
+  eb->commit_cb = commit_cb;
+  eb->commit_baton = commit_baton;
+
+  SVN_ERR(svn_fs_editor_create(&eb->inner, &eb->txn_name,
+                               repos->fs, SVN_FS_TXN_CHECK_LOCKS,
+                               cancel_func, cancel_baton,
+                               result_pool, scratch_pool));
+
+  /* The TXN has been created. Go ahead and apply all revision properties.  */
+  SVN_ERR(apply_revprops(repos->fs, eb->txn_name, revprops, scratch_pool));
+
+  /* Wrap the FS editor within our editor.  */
+  SVN_ERR(svn_editor_create(editor, eb, cancel_func, cancel_baton,
+                            result_pool, scratch_pool));
+  SVN_ERR(svn_editor_setcb_many(*editor, &editor_cbs, scratch_pool));
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_repos/deprecated.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_repos/deprecated.c Wed May 16 20:32:43 2012
@@ -32,6 +32,8 @@
 
 #include "svn_private_config.h"
 
+#include "repos.h"
+
 
 
 
@@ -570,8 +572,7 @@ repos_notify_handler(void *baton,
   switch (notify->action)
   {
     case svn_repos_notify_warning:
-      len = strlen(notify->warning_str);
-      svn_error_clear(svn_stream_write(feedback_stream, notify->warning_str, &len));
+      svn_error_clear(svn_stream_puts(feedback_stream, notify->warning_str));
       return;
 
     case svn_repos_notify_dump_rev_end:
@@ -878,3 +879,32 @@ svn_repos_get_fs_build_parser(const svn_
   *parser_callbacks = fns_from_fns2(fns2, pool);
   return SVN_NO_ERROR;
 }
+
+
+svn_error_t *
+svn_repos_fs_begin_txn_for_update(svn_fs_txn_t **txn_p,
+                                  svn_repos_t *repos,
+                                  svn_revnum_t rev,
+                                  const char *author,
+                                  apr_pool_t *pool)
+{
+  /* ### someday, we might run a read-hook here. */
+
+  /* Begin the transaction. */
+  SVN_ERR(svn_fs_begin_txn2(txn_p, repos->fs, rev, 0, pool));
+
+  /* We pass the author to the filesystem by adding it as a property
+     on the txn. */
+
+  /* User (author). */
+  if (author)
+    {
+      svn_string_t val;
+      val.data = author;
+      val.len = strlen(author);
+      SVN_ERR(svn_fs_change_txn_prop(*txn_p, SVN_PROP_REVISION_AUTHOR,
+                                     &val, pool));
+    }
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_repos/dump.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_repos/dump.c Wed May 16 20:32:43 2012
@@ -282,11 +282,11 @@ dump_node(struct edit_baton *eb,
                             SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n",
                             path));
   if (kind == svn_node_file)
-    SVN_ERR(svn_stream_printf(eb->stream, pool,
-                              SVN_REPOS_DUMPFILE_NODE_KIND ": file\n"));
+    SVN_ERR(svn_stream_puts(eb->stream,
+                            SVN_REPOS_DUMPFILE_NODE_KIND ": file\n"));
   else if (kind == svn_node_dir)
-    SVN_ERR(svn_stream_printf(eb->stream, pool,
-                              SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n"));
+    SVN_ERR(svn_stream_puts(eb->stream,
+                            SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n"));
 
   /* Remove leading slashes from copyfrom paths. */
   if (cmp_path)
@@ -301,9 +301,8 @@ dump_node(struct edit_baton *eb,
 
   if (action == svn_node_action_change)
     {
-      SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                SVN_REPOS_DUMPFILE_NODE_ACTION
-                                ": change\n"));
+      SVN_ERR(svn_stream_puts(eb->stream,
+                              SVN_REPOS_DUMPFILE_NODE_ACTION ": change\n"));
 
       /* either the text or props changed, or possibly both. */
       SVN_ERR(svn_fs_revision_root(&compare_root,
@@ -323,9 +322,9 @@ dump_node(struct edit_baton *eb,
       if (! is_copy)
         {
           /* a simple delete+add, implied by a single 'replace' action. */
-          SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                    SVN_REPOS_DUMPFILE_NODE_ACTION
-                                    ": replace\n"));
+          SVN_ERR(svn_stream_puts(eb->stream,
+                                  SVN_REPOS_DUMPFILE_NODE_ACTION
+                                  ": replace\n"));
 
           /* definitely need to dump all content for a replace. */
           if (kind == svn_node_file)
@@ -338,9 +337,9 @@ dump_node(struct edit_baton *eb,
 
           /* the path & kind headers have already been printed;  just
              add a delete action, and end the current record.*/
-          SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                    SVN_REPOS_DUMPFILE_NODE_ACTION
-                                    ": delete\n\n"));
+          SVN_ERR(svn_stream_puts(eb->stream,
+                                  SVN_REPOS_DUMPFILE_NODE_ACTION
+                                  ": delete\n\n"));
 
           /* recurse:  print an additional add-with-history record. */
           SVN_ERR(dump_node(eb, path, kind, svn_node_action_add,
@@ -354,9 +353,8 @@ dump_node(struct edit_baton *eb,
     }
   else if (action == svn_node_action_delete)
     {
-      SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                SVN_REPOS_DUMPFILE_NODE_ACTION
-                                ": delete\n"));
+      SVN_ERR(svn_stream_puts(eb->stream,
+                              SVN_REPOS_DUMPFILE_NODE_ACTION ": delete\n"));
 
       /* we can leave this routine quietly now, don't need to dump
          any content. */
@@ -365,8 +363,8 @@ dump_node(struct edit_baton *eb,
     }
   else if (action == svn_node_action_add)
     {
-      SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
+      SVN_ERR(svn_stream_puts(eb->stream,
+                              SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
 
       if (! is_copy)
         {
@@ -511,9 +509,8 @@ dump_node(struct edit_baton *eb,
              saying that our property contents are a delta. */
           SVN_ERR(svn_fs_node_proplist(&oldhash, compare_root, compare_path,
                                        pool));
-          SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                    SVN_REPOS_DUMPFILE_PROP_DELTA
-                                    ": true\n"));
+          SVN_ERR(svn_stream_puts(eb->stream,
+                                  SVN_REPOS_DUMPFILE_PROP_DELTA ": true\n"));
         }
       else
         oldhash = apr_hash_make(pool);
@@ -544,9 +541,8 @@ dump_node(struct edit_baton *eb,
              saying our text contents are a delta. */
           SVN_ERR(store_delta(&delta_file, &textlen, compare_root,
                               compare_path, eb->fs_root, path, pool));
-          SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                    SVN_REPOS_DUMPFILE_TEXT_DELTA
-                                    ": true\n"));
+          SVN_ERR(svn_stream_puts(eb->stream,
+                                  SVN_REPOS_DUMPFILE_TEXT_DELTA ": true\n"));
 
           if (compare_root)
             {
@@ -1009,7 +1005,7 @@ get_dump_editor(const svn_delta_editor_t
   shim_callbacks->fetch_baton = eb;
 
   SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
-                                   shim_callbacks, pool, pool));
+                                   NULL, NULL, shim_callbacks, pool, pool));
 
   return SVN_NO_ERROR;
 }
@@ -1406,7 +1402,7 @@ svn_repos_verify_fs2(svn_repos_t *repos,
 
   for (rev = start_rev; rev <= end_rev; rev++)
     {
-      svn_delta_editor_t *dump_editor;
+      const svn_delta_editor_t *dump_editor;
       void *dump_edit_baton;
       const svn_delta_editor_t *cancel_editor;
       void *cancel_edit_baton;
@@ -1416,8 +1412,8 @@ svn_repos_verify_fs2(svn_repos_t *repos,
       svn_pool_clear(iterpool);
 
       /* Get cancellable dump editor, but with our close_directory handler. */
-      SVN_ERR(get_dump_editor((const svn_delta_editor_t **)&dump_editor,
-                              &dump_edit_baton, fs, rev, "",
+      SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton,
+                              fs, rev, "",
                               svn_stream_empty(iterpool),
                               NULL, NULL,
                               verify_close_directory,

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_repos/fs-wrap.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_repos/fs-wrap.c Wed May 16 20:32:43 2012
@@ -124,36 +124,6 @@ svn_repos_fs_begin_txn_for_commit(svn_fs
                                             pool);
 }
 
-
-svn_error_t *
-svn_repos_fs_begin_txn_for_update(svn_fs_txn_t **txn_p,
-                                  svn_repos_t *repos,
-                                  svn_revnum_t rev,
-                                  const char *author,
-                                  apr_pool_t *pool)
-{
-  /* ### someday, we might run a read-hook here. */
-
-  /* Begin the transaction. */
-  SVN_ERR(svn_fs_begin_txn2(txn_p, repos->fs, rev, 0, pool));
-
-  /* We pass the author to the filesystem by adding it as a property
-     on the txn. */
-
-  /* User (author). */
-  if (author)
-    {
-      svn_string_t val;
-      val.data = author;
-      val.len = strlen(author);
-      SVN_ERR(svn_fs_change_txn_prop(*txn_p, SVN_PROP_REVISION_AUTHOR,
-                                     &val, pool));
-    }
-
-  return SVN_NO_ERROR;
-}
-
-
 
 /*** Property wrappers ***/
 
@@ -162,7 +132,7 @@ svn_repos__validate_prop(const char *nam
                          const svn_string_t *value,
                          apr_pool_t *pool)
 {
-  svn_prop_kind_t kind = svn_property_kind(NULL, name);
+  svn_prop_kind_t kind = svn_property_kind2(name);
 
   /* Disallow setting non-regular properties. */
   if (kind != svn_prop_regular_kind)

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_repos/hooks.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_repos/hooks.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_repos/hooks.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_repos/hooks.c Wed May 16 20:32:43 2012
@@ -30,6 +30,7 @@
 #include "svn_error.h"
 #include "svn_dirent_uri.h"
 #include "svn_path.h"
+#include "svn_pools.h"
 #include "svn_repos.h"
 #include "svn_utf.h"
 #include "repos.h"
@@ -172,7 +173,7 @@ env_from_env_hash(apr_hash_t *env_hash,
   const char **env;
   const char **envp;
 
-  if (!env_hash || apr_hash_count(env_hash) == 0)
+  if (!env_hash)
     return NULL;
 
   env = apr_palloc(result_pool,
@@ -212,7 +213,8 @@ run_hook_cmd(svn_string_t **result,
   apr_file_t *null_handle;
   apr_status_t apr_err;
   svn_error_t *err;
-  apr_proc_t cmd_proc;
+  apr_proc_t cmd_proc = {0};
+  apr_pool_t *cmd_pool;
 
   if (result)
     {
@@ -228,42 +230,39 @@ run_hook_cmd(svn_string_t **result,
             (apr_err, _("Can't create null stdout for hook '%s'"), cmd);
     }
 
+  /* Tie resources allocated for the command to a special pool which we can
+   * destroy in order to clean up the stderr pipe opened for the process. */
+  cmd_pool = svn_pool_create(pool);
+
   err = svn_io_start_cmd3(&cmd_proc, ".", cmd, args,
                           env_from_env_hash(hooks_env, pool, pool),
                           FALSE, FALSE, stdin_handle, result != NULL,
-                          null_handle, TRUE, NULL, pool);
-
-  if (err)
-    {
-      /* CMD_PROC is not safe to use. Bail. */
-      return svn_error_createf
-        (SVN_ERR_REPOS_HOOK_FAILURE, err, _("Failed to start '%s' hook"), cmd);
-    }
+                          null_handle, TRUE, NULL, cmd_pool);
+  if (!err)
+    err = check_hook_result(name, cmd, &cmd_proc, cmd_proc.err, pool);
   else
     {
-      err = check_hook_result(name, cmd, &cmd_proc, cmd_proc.err, pool);
+      /* The command could not be started for some reason. */
+      err = svn_error_createf(SVN_ERR_REPOS_BAD_ARGS, err,
+                              _("Failed to start '%s' hook"), cmd);
     }
 
   /* Hooks are fallible, and so hook failure is "expected" to occur at
      times.  When such a failure happens we still want to close the pipe
      and null file */
-  apr_err = apr_file_close(cmd_proc.err);
-  if (!err && apr_err)
-    return svn_error_wrap_apr
-      (apr_err, _("Error closing read end of stderr pipe"));
-
-  if (result)
+  if (!err && result)
     {
       svn_stringbuf_t *native_stdout;
-      SVN_ERR(svn_stringbuf_from_aprfile(&native_stdout, cmd_proc.out, pool));
-      apr_err = apr_file_close(cmd_proc.out);
-      if (!err && apr_err)
-        return svn_error_wrap_apr
-          (apr_err, _("Error closing read end of stderr pipe"));
-
-      *result = svn_stringbuf__morph_into_string(native_stdout);
+      err = svn_stringbuf_from_aprfile(&native_stdout, cmd_proc.out, pool);
+      if (!err)
+        *result = svn_stringbuf__morph_into_string(native_stdout);
     }
-  else
+
+  /* Close resources allocated by svn_io_start_cmd3(), such as the pipe. */
+  svn_pool_destroy(cmd_pool);
+
+  /* Close the null handle. */
+  if (null_handle)
     {
       apr_err = apr_file_close(null_handle);
       if (!err && apr_err)

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_repos/log.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_repos/log.c Wed May 16 20:32:43 2012
@@ -1742,7 +1742,7 @@ reduce_search(apr_array_header_t *paths,
       if (!ranges)
         continue;
 
-      /* ranges is ordered, could we use some sort of binay search
+      /* ranges is ordered, could we use some sort of binary search
          rather than iterating? */
       for (j = 0; j < ranges->nelts; ++j)
         {

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_repos/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_repos/replay.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_repos/replay.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_repos/replay.c Wed May 16 20:32:43 2012
@@ -415,7 +415,12 @@ was_readable(svn_boolean_t *readable,
    revision root, fspath, and revnum of the copyfrom of CHANGE, which
    corresponds to PATH under ROOT.  If the copyfrom info is valid
    (i.e., is not (NULL, SVN_INVALID_REVNUM)), then initialize SRC_READABLE
-   too, consulting AUTHZ_READ_FUNC and AUTHZ_READ_BATON if provided. */
+   too, consulting AUTHZ_READ_FUNC and AUTHZ_READ_BATON if provided.
+
+   NOTE: If the copyfrom information in CHANGE is marked as unknown
+   (meaning, its ->copyfrom_rev and ->copyfrom_path cannot be
+   trusted), this function will also update those members of the
+   CHANGE structure to carry accurate copyfrom information.  */
 static svn_error_t *
 fill_copyfrom(svn_fs_root_t **copyfrom_root,
               const char **copyfrom_path,
@@ -698,10 +703,18 @@ path_driver_cb_func(void **dir_baton,
         }
     }
 
-  /* Handle property modifications. */
   if (! do_delete || do_add)
     {
-      if (change->prop_mod)
+      /* Is this a copy that was downgraded to a raw add?  (If so,
+         we'll need to transmit properties and file contents and such
+         for it regardless of what the CHANGE structure's text_mod
+         and prop_mod flags say.)  */
+      svn_boolean_t downgraded_copy = (change->copyfrom_known
+                                       && change->copyfrom_path
+                                       && (! copyfrom_path));
+
+      /* Handle property modifications. */
+      if (change->prop_mod || downgraded_copy)
         {
           apr_array_header_t *prop_diffs;
           apr_hash_t *old_props;
@@ -731,14 +744,9 @@ path_driver_cb_func(void **dir_baton,
             }
         }
 
-      /* Handle textual modifications.
-
-         Note that this needs to happen in the "copy from a file we
-         aren't allowed to see" case since otherwise the caller will
-         have no way to actually get the new file's contents, which
-         they are apparently allowed to see. */
+      /* Handle textual modifications. */
       if (change->node_kind == svn_node_file
-          && (change->text_mod || (change->copyfrom_path && ! copyfrom_path)))
+          && (change->text_mod || downgraded_copy))
         {
           svn_txdelta_window_handler_t delta_handler;
           void *delta_handler_baton;

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_repos/reporter.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_repos/reporter.c Wed May 16 20:32:43 2012
@@ -640,14 +640,20 @@ delta_files(report_baton_t *b, void *fil
   /* Send the delta stream if desired, or just a NULL window if not. */
   SVN_ERR(b->editor->apply_textdelta(file_baton, s_hex_digest, pool,
                                      &dhandler, &dbaton));
-  if (b->text_deltas)
+
+  if (dhandler != svn_delta_noop_window_handler)
     {
-      SVN_ERR(svn_fs_get_file_delta_stream(&dstream, s_root, s_path,
-                                           b->t_root, t_path, pool));
-      return svn_txdelta_send_txstream(dstream, dhandler, dbaton, pool);
+      if (b->text_deltas)
+        {
+          SVN_ERR(svn_fs_get_file_delta_stream(&dstream, s_root, s_path,
+                                               b->t_root, t_path, pool));
+          SVN_ERR(svn_txdelta_send_txstream(dstream, dhandler, dbaton, pool));
+        }
+      else
+        SVN_ERR(dhandler(NULL, dbaton));
     }
-  else
-    return dhandler(NULL, dbaton);
+
+  return SVN_NO_ERROR;
 }
 
 /* Determine if the user is authorized to view B->t_root/PATH. */

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_repos/repos.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_repos/repos.c Wed May 16 20:32:43 2012
@@ -36,6 +36,7 @@
 #include "svn_version.h"
 
 #include "private/svn_repos_private.h"
+#include "private/svn_subr_private.h"
 #include "svn_private_config.h" /* for SVN_TEMPLATE_ROOT_DIR */
 
 #include "repos.h"
@@ -1184,9 +1185,9 @@ create_repos_structure(svn_repos_t *repo
   /* Write the top-level README file. */
   {
     const char * const readme_header =
-      "This is a Subversion repository; use the 'svnadmin' tool to examine"  NL
-      "it.  Do not add, delete, or modify files here unless you know how"    NL
-      "to avoid corrupting the repository."                                  NL
+      "This is a Subversion repository; use the 'svnadmin' and 'svnlook' "   NL
+      "tools to examine it.  Do not add, delete, or modify files here "      NL
+      "unless you know how to avoid corrupting the repository."              NL
       ""                                                                     NL;
     const char * const readme_bdb_insert =
       "The directory \"" SVN_REPOS__DB_DIR "\" contains a Berkeley DB environment."  NL
@@ -1968,3 +1969,17 @@ svn_repos_remember_client_capabilities(s
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_repos__fs_type(const char **fs_type,
+                   const char *repos_path,
+                   apr_pool_t *pool)
+{
+  svn_repos_t repos;
+  repos.path = (char*)repos_path;
+
+  SVN_ERR(check_repos_format(&repos, pool));
+
+  return svn_fs_type(fs_type,
+                     svn_dirent_join(repos_path, SVN_REPOS__DB_DIR, pool),
+                     pool);
+}

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_repos/rev_hunt.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_repos/rev_hunt.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_repos/rev_hunt.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_repos/rev_hunt.c Wed May 16 20:32:43 2012
@@ -155,7 +155,7 @@ svn_repos_get_committed_info(svn_revnum_
                              apr_pool_t *pool)
 {
   apr_hash_t *revprops;
-  
+
   svn_fs_t *fs = svn_fs_root_fs(root);
 
   /* ### It might be simpler just to declare that revision

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_subr/cache-inprocess.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_subr/cache-inprocess.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_subr/cache-inprocess.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_subr/cache-inprocess.c Wed May 16 20:32:43 2012
@@ -304,7 +304,7 @@ inprocess_cache_set_internal(inprocess_c
       cache->data_size -= existing_entry->size;
       if (value)
         {
-          SVN_ERR(cache->serialize_func((char **)&existing_entry->value,
+          SVN_ERR(cache->serialize_func(&existing_entry->value,
                                         &existing_entry->size,
                                         value,
                                         page->page_pool));
@@ -356,7 +356,7 @@ inprocess_cache_set_internal(inprocess_c
     new_entry->key = duplicate_key(cache, key, page->page_pool);
     if (value)
       {
-        SVN_ERR(cache->serialize_func((char **)&new_entry->value,
+        SVN_ERR(cache->serialize_func(&new_entry->value,
                                       &new_entry->size,
                                       value,
                                       page->page_pool));
@@ -512,10 +512,10 @@ inprocess_cache_set_partial_internal(inp
       SVN_ERR(move_page_to_front(cache, entry->page));
 
       cache->data_size -= entry->size;
-      SVN_ERR(func((char **)&entry->value,
-                  &entry->size,
-                  baton,
-                  entry->page->page_pool));
+      SVN_ERR(func(&entry->value,
+                   &entry->size,
+                   baton,
+                   entry->page->page_pool));
       cache->data_size += entry->size;
     }