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/30 19:13:02 UTC

svn commit: r1415773 [3/6] - in /subversion/branches/tree-read-api: ./ build/ac-macros/ build/generator/ notes/ subversion/bindings/cxxhl/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_delta/ subversion/lib...

Modified: subversion/branches/tree-read-api/subversion/libsvn_ra_serf/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_ra_serf/update.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_ra_serf/update.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_ra_serf/update.c Fri Nov 30 18:12:52 2012
@@ -357,6 +357,10 @@ struct report_context_t {
 
   /* completed PROPFIND requests (contains svn_ra_serf__handler_t) */
   svn_ra_serf__list_t *done_propfinds;
+  svn_ra_serf__list_t *done_dir_propfinds;
+
+  /* list of outstanding prop changes (contains report_dir_t) */
+  svn_ra_serf__list_t *active_dir_propfinds;
 
   /* list of files that only have prop changes (contains report_info_t) */
   svn_ra_serf__list_t *file_propchanges_only;
@@ -1347,6 +1351,27 @@ maybe_close_dir_chain(report_dir_t *dir)
     {
       report_dir_t *parent = cur_dir->parent_dir;
       report_context_t *report_context = cur_dir->report_context;
+      svn_boolean_t propfind_in_done_list = FALSE;
+      svn_ra_serf__list_t *done_list;
+
+      /* Make sure there are no references to this dir in the
+         active_dir_propfinds list.  If there are, don't close the
+         directory -- which would delete the pool from which the
+         relevant active_dir_propfinds list item is allocated -- and
+         of course don't crawl upward to check the parents for
+         a closure opportunity, either.  */
+      done_list = report_context->active_dir_propfinds;
+      while (done_list)
+        {
+          if (done_list->data == cur_dir)
+            {
+              propfind_in_done_list = TRUE;
+              break;
+            }
+          done_list = done_list->next;
+        }
+      if (propfind_in_done_list)
+        break;
 
       SVN_ERR(close_dir(cur_dir));
       if (parent)
@@ -1377,6 +1402,10 @@ handle_propchange_only(report_info_t *in
 
   info->dir->ref_count--;
 
+  /* See if the parent directory of this file (and perhaps even
+     parents of that) can be closed now.  */
+  SVN_ERR(maybe_close_dir_chain(info->dir));
+
   return SVN_NO_ERROR;
 }
 
@@ -1401,6 +1430,10 @@ handle_local_content(report_info_t *info
 
   info->dir->ref_count--;
 
+  /* See if the parent directory of this fetched item (and
+     perhaps even parents of that) can be closed now. */
+  SVN_ERR(maybe_close_dir_chain(info->dir));
+
   return SVN_NO_ERROR;
 }
 
@@ -1565,12 +1598,7 @@ fetch_file(report_context_t *ctx, report
     }
   else
     {
-      /* No propfind or GET request.  Just handle the prop changes now.
-
-         Note: we'll use INFO->POOL for the scratch_pool here since it will
-         be destroyed at the end of handle_propchange_only(). That pool
-         would be quite fine, but it is unclear how long INFO->POOL will
-         stick around since its lifetime and usage are unclear.  */
+      /* No propfind or GET request.  Just handle the prop changes now. */
       SVN_ERR(handle_propchange_only(info, info->pool));
     }
 
@@ -2126,13 +2154,15 @@ end_report(svn_ra_serf__xml_parser_t *pa
        */
       if (info->dir->fetch_props)
         {
+          svn_ra_serf__list_t *list_item;
+ 
           SVN_ERR(svn_ra_serf__deliver_props(&info->dir->propfind_handler,
                                              info->dir->props, ctx->sess,
                                              get_best_connection(ctx),
                                              info->dir->url,
                                              ctx->target_rev, "0",
                                              all_props,
-                                             &ctx->done_propfinds,
+                                             &ctx->done_dir_propfinds,
                                              info->dir->pool));
           SVN_ERR_ASSERT(info->dir->propfind_handler);
 
@@ -2141,6 +2171,11 @@ end_report(svn_ra_serf__xml_parser_t *pa
 
           ctx->num_active_propfinds++;
 
+          list_item = apr_pcalloc(info->dir->pool, sizeof(*list_item));
+          list_item->data = info->dir;
+          list_item->next = ctx->active_dir_propfinds;
+          ctx->active_dir_propfinds = list_item;
+
           if (ctx->num_active_fetches + ctx->num_active_propfinds
               > REQUEST_COUNT_TO_PAUSE)
             ctx->parser_ctx->paused = TRUE;
@@ -2150,6 +2185,12 @@ end_report(svn_ra_serf__xml_parser_t *pa
           info->dir->propfind_handler = NULL;
         }
 
+      /* See if this directory (and perhaps even parents of that) can
+         be closed now.  This is likely to be the case only if we
+         didn't need to contact the server for supplemental
+         information required to handle any of this directory's
+         children.  */
+      SVN_ERR(maybe_close_dir_chain(info->dir));
       svn_ra_serf__xml_pop_state(parser);
     }
   else if (state == OPEN_FILE && strcmp(name.name, "open-file") == 0)
@@ -2562,7 +2603,7 @@ finish_report(void *report_baton,
   svn_stringbuf_t *buf = NULL;
   apr_pool_t *iterpool = svn_pool_create(pool);
   svn_error_t *err;
-  apr_short_interval_time_t waittime_left = sess->timeout;
+  apr_interval_time_t waittime_left = sess->timeout;
 
   svn_xml_make_close_tag(&buf, iterpool, "S:update-report");
   SVN_ERR(svn_io_file_write_full(report->body_file, buf->data, buf->len,
@@ -2666,14 +2707,17 @@ finish_report(void *report_baton,
           err = SVN_NO_ERROR;
           status = 0;
 
-          if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
-            {
-              waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
-            }
-          else
+          if (sess->timeout)
             {
-              return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
-                                      _("Connection timed out"));
+              if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
+                {
+                  waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
+                }
+              else
+                {
+                  return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
+                                          _("Connection timed out"));
+                }
             }
         }
       else
@@ -2692,10 +2736,12 @@ finish_report(void *report_baton,
         SVN_ERR(open_connection_if_needed(sess, report->num_active_fetches +
                                           report->num_active_propfinds));
 
-      /* prune our propfind list if they are done. */
+      /* Prune completed file PROPFINDs. */
       done_list = report->done_propfinds;
       while (done_list)
         {
+          svn_ra_serf__list_t *next_done = done_list->next;
+
           svn_pool_clear(iterpool_inner);
 
           report->num_active_propfinds--;
@@ -2730,39 +2776,46 @@ finish_report(void *report_baton,
                 {
                   report_info_t *info = cur->data;
 
-                  /* If we've got cached file content for this file,
-                     take care of the locally collected properties and
-                     file content at once.  Otherwise, just deal with
-                     the collected properties. */
-                  if (info->cached_contents)
+                  if (!prev)
                     {
-                      SVN_ERR(handle_local_content(info, iterpool_inner));
+                      report->file_propchanges_only = cur->next;
                     }
                   else
                     {
-                      SVN_ERR(handle_propchange_only(info, iterpool_inner));
+                      prev->next = cur->next;
                     }
 
-                  if (!prev)
+                  /* If we've got cached file content for this file,
+                     take care of the locally collected properties and
+                     file content at once.  Otherwise, just deal with
+                     the collected properties.
+
+                     NOTE:  These functions below could delete
+                     info->dir->pool (via maybe_close_dir_chain()),
+                     from which is allocated the list item in
+                     report->file_propchanges_only.
+                  */
+                  if (info->cached_contents)
                     {
-                      report->file_propchanges_only = cur->next;
+                      SVN_ERR(handle_local_content(info, iterpool_inner));
                     }
                   else
                     {
-                      prev->next = cur->next;
+                      SVN_ERR(handle_propchange_only(info, iterpool_inner));
                     }
                 }
             }
 
-          done_list = done_list->next;
+          done_list = next_done;
         }
       report->done_propfinds = NULL;
 
-      /* Prune completely fetches from our list. */
+      /* Prune completed fetches from our list. */
       done_list = report->done_fetches;
       while (done_list)
         {
           report_fetch_t *done_fetch = done_list->data;
+          svn_ra_serf__list_t *next_done = done_list->next;
           report_dir_t *cur_dir;
 
           /* Decrease the refcount in the parent directory of the file
@@ -2773,14 +2826,77 @@ finish_report(void *report_baton,
           /* Decrement our active fetch count. */
           report->num_active_fetches--;
 
-          done_list = done_list->next;
-
           /* See if the parent directory of this fetched item (and
-             perhaps even parents of that) can be closed now. */
+             perhaps even parents of that) can be closed now. 
+
+             NOTE:  This could delete cur_dir->pool, from which is
+             allocated the list item in report->done_fetches.
+          */
           SVN_ERR(maybe_close_dir_chain(cur_dir));
+
+          done_list = next_done;
         }
       report->done_fetches = NULL;
 
+      /* Prune completed directory PROPFINDs. */
+      done_list = report->done_dir_propfinds;
+      while (done_list)
+        {
+          svn_ra_serf__list_t *next_done = done_list->next;
+
+          report->num_active_propfinds--;
+
+          if (report->active_dir_propfinds)
+            {
+              svn_ra_serf__list_t *cur, *prev;
+
+              prev = NULL;
+              cur = report->active_dir_propfinds;
+
+              while (cur)
+                {
+                  report_dir_t *item = cur->data;
+
+                  if (item->propfind_handler == done_list->data)
+                    {
+                      break;
+                    }
+
+                  prev = cur;
+                  cur = cur->next;
+                }
+              SVN_ERR_ASSERT(cur); /* we expect to find a matching propfind! */
+
+              /* If we found a match, set the new props and remove this
+               * propchange from our list.
+               */
+              if (cur)
+                {
+                  report_dir_t *cur_dir = cur->data;
+
+                  if (!prev)
+                    {
+                      report->active_dir_propfinds = cur->next;
+                    }
+                  else
+                    {
+                      prev->next = cur->next;
+                    }
+
+                  /* See if this directory (and perhaps even parents of that)
+                     can be closed now.
+
+                     NOTE:  This could delete cur_dir->pool, from which is
+                     allocated the list item in report->active_dir_propfinds.
+                  */
+                  SVN_ERR(maybe_close_dir_chain(cur_dir));
+                }
+            }
+
+          done_list = next_done;
+        }
+      report->done_dir_propfinds = NULL;
+
       /* If the parser is paused, and the number of active requests has
          dropped far enough, then resume parsing.  */
       if (parser_ctx->paused

Modified: subversion/branches/tree-read-api/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_ra_serf/util.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_ra_serf/util.c Fri Nov 30 18:12:52 2012
@@ -657,6 +657,10 @@ setup_serf_req(serf_request_t *request,
       SVN_ERR(svn_ra_serf__copy_into_spillbuf(&buf, body_bkt,
                                               request_pool,
                                               scratch_pool));
+      /* Destroy original bucket since it content is already copied 
+         to spillbuf. */
+      serf_bucket_destroy(body_bkt);
+
       body_bkt = svn_ra_serf__create_sb_bucket(buf, allocator,
                                                request_pool,
                                                scratch_pool);
@@ -718,7 +722,7 @@ svn_ra_serf__context_run_wait(svn_boolea
                               apr_pool_t *scratch_pool)
 {
   apr_pool_t *iterpool;
-  apr_short_interval_time_t waittime_left = sess->timeout;
+  apr_interval_time_t waittime_left = sess->timeout;
   
   assert(sess->pending_error == SVN_NO_ERROR);
 
@@ -751,14 +755,17 @@ svn_ra_serf__context_run_wait(svn_boolea
           err = SVN_NO_ERROR;
           status = 0;
 
-          if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
-            {
-              waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
-            }
-          else
+          if (sess->timeout)
             {
-              return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
-                                      _("Connection timed out"));
+              if (waittime_left > SVN_RA_SERF__CONTEXT_RUN_DURATION)
+                {
+                  waittime_left -= SVN_RA_SERF__CONTEXT_RUN_DURATION;
+                }
+              else 
+                {
+                  return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
+                                          _("Connection timed out"));
+                }
             }
         }
       else

Modified: subversion/branches/tree-read-api/subversion/libsvn_ra_svn/cyrus_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_ra_svn/cyrus_auth.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_ra_svn/cyrus_auth.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_ra_svn/cyrus_auth.c Fri Nov 30 18:12:52 2012
@@ -871,12 +871,12 @@ svn_ra_svn__do_cyrus_auth(svn_ra_svn__se
 
   /* The username callback. */
   callbacks[0].id = SASL_CB_AUTHNAME;
-  callbacks[0].proc = (void*)get_username_cb;
+  callbacks[0].proc = (int (*)(void))get_username_cb;
   callbacks[0].context = &cred_baton;
 
   /* The password callback. */
   callbacks[1].id = SASL_CB_PASS;
-  callbacks[1].proc = (void*)get_password_cb;
+  callbacks[1].proc = (int (*)(void))get_password_cb;
   callbacks[1].context = &cred_baton;
 
   /* Mark the end of the array. */

Modified: subversion/branches/tree-read-api/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_repos/reporter.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_repos/reporter.c Fri Nov 30 18:12:52 2012
@@ -717,11 +717,13 @@ delta_files(report_baton_t *b, void *fil
              zero-copy code. */
           if (b->zero_copy_limit > 0 && s_path == NULL)
             {
-              zero_copy_baton_t baton = { b->zero_copy_limit
-                                        , dhandler
-                                        , dbaton
-                                        , FALSE};
+              zero_copy_baton_t baton;
               svn_boolean_t called = FALSE;
+
+              baton.zero_copy_limit = b->zero_copy_limit;
+              baton.dhandler = dhandler;
+              baton.dbaton = dbaton;
+              baton.zero_copy_succeeded = FALSE;
               SVN_ERR(svn_fs_try_process_file_contents(&called,
                                                        b->t_root, t_path,
                                                        send_zero_copy_delta,

Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/named_atomic.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/named_atomic.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/named_atomic.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/named_atomic.c Fri Nov 30 18:12:52 2012
@@ -308,7 +308,7 @@ delete_lock_file(void *arg)
   const char *lock_name = NULL;
 
   /* locks have already been cleaned up. Simply close the file */
-  apr_file_close(mutex->lock_file);
+  apr_status_t status = apr_file_close(mutex->lock_file);
 
   /* Remove the file from disk. This will fail if there ares still other
    * users of this lock file, i.e. namespace. */
@@ -316,10 +316,12 @@ delete_lock_file(void *arg)
   if (lock_name)
     apr_file_remove(lock_name, mutex->pool);
 
-  return 0;
+  return status;
 }
 
-/* Validate the ATOMIC parameter, i.e it's address.
+/* Validate the ATOMIC parameter, i.e it's address.  Correct code will
+ * never need this but if someone should accidentally to use a NULL or
+ * incomplete structure, let's catch that here instead of segfaulting.
  */
 static svn_error_t *
 validate(svn_named_atomic__t *atomic)
@@ -416,7 +418,9 @@ svn_atomic_namespace__create(svn_atomic_
                            APR_OS_DEFAULT,
                            result_pool));
 
-  /* Make sure the last user of our lock file will actually remove it
+  /* Make sure the last user of our lock file will actually remove it.
+   * Please note that only the last file handle begin closed will actually
+   * remove the underlying file (see docstring for apr_file_remove).
    */
   apr_pool_cleanup_register(result_pool, &new_ns->mutex,
                             delete_lock_file,

Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/properties.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/properties.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/properties.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/properties.c Fri Nov 30 18:12:52 2012
@@ -33,6 +33,90 @@
 #include "svn_ctype.h"
 
 
+/* All Subversion-specific versioned node properties
+ * known to this client, that are applicable to both a file and a dir.
+ */
+#define SVN_PROP__NODE_COMMON_PROPS SVN_PROP_MERGEINFO, \
+                                    SVN_PROP_TEXT_TIME, \
+                                    SVN_PROP_OWNER, \
+                                    SVN_PROP_GROUP, \
+                                    SVN_PROP_UNIX_MODE,
+
+/* All Subversion-specific versioned node properties
+ * known to this client, that are applicable to a dir only.
+ */
+#define SVN_PROP__NODE_DIR_ONLY_PROPS SVN_PROP_IGNORE, \
+                                      SVN_PROP_INHERITABLE_IGNORES, \
+                                      SVN_PROP_INHERITABLE_AUTO_PROPS, \
+                                      SVN_PROP_EXTERNALS,
+
+/* All Subversion-specific versioned node properties
+ * known to this client, that are applicable to a file only.
+ */
+#define SVN_PROP__NODE_FILE_ONLY_PROPS SVN_PROP_MIME_TYPE, \
+                                       SVN_PROP_EOL_STYLE, \
+                                       SVN_PROP_KEYWORDS, \
+                                       SVN_PROP_EXECUTABLE, \
+                                       SVN_PROP_NEEDS_LOCK, \
+                                       SVN_PROP_SPECIAL,
+
+static const char *const known_rev_props[]
+ = { SVN_PROP_REVISION_ALL_PROPS
+     NULL };
+
+static const char *const known_node_props[]
+ = { SVN_PROP__NODE_COMMON_PROPS
+     SVN_PROP__NODE_DIR_ONLY_PROPS
+     SVN_PROP__NODE_FILE_ONLY_PROPS
+     NULL };
+
+static const char *const known_dir_props[]
+ = { SVN_PROP__NODE_COMMON_PROPS
+     SVN_PROP__NODE_DIR_ONLY_PROPS
+     NULL };
+
+static const char *const known_file_props[]
+ = { SVN_PROP__NODE_COMMON_PROPS
+     SVN_PROP__NODE_FILE_ONLY_PROPS
+     NULL };
+
+static svn_boolean_t
+is_known_prop(const char *prop_name,
+              const char *const *known_props)
+{
+  while (*known_props)
+    {
+      if (strcmp(prop_name, *known_props++) == 0)
+        return TRUE;
+    }
+  return FALSE;
+}
+
+svn_boolean_t
+svn_prop_is_known_svn_rev_prop(const char *prop_name)
+{
+  return is_known_prop(prop_name, known_rev_props);
+}
+
+svn_boolean_t
+svn_prop_is_known_svn_node_prop(const char *prop_name)
+{
+  return is_known_prop(prop_name, known_node_props);
+}
+
+svn_boolean_t
+svn_prop_is_known_svn_file_prop(const char *prop_name)
+{
+  return is_known_prop(prop_name, known_file_props);
+}
+
+svn_boolean_t
+svn_prop_is_known_svn_dir_prop(const char *prop_name)
+{
+  return is_known_prop(prop_name, known_dir_props);
+}
+
+
 svn_boolean_t
 svn_prop_is_svn_prop(const char *prop_name)
 {

Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/sqlite.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/sqlite.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/sqlite.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/sqlite.c Fri Nov 30 18:12:52 2012
@@ -168,7 +168,7 @@ exec_sql2(svn_sqlite__db_t *db, const ch
   if (sqlite_err != SQLITE_OK && sqlite_err != ignored_err)
     {
       svn_error_t *err = svn_error_createf(SQLITE_ERROR_CODE(sqlite_err), NULL,
-                                           _("%s, executing statement '%s'"),
+                                           _("sqlite: %s, executing statement '%s'"),
                                            err_msg, sql);
       sqlite3_free(err_msg);
       return err;
@@ -256,8 +256,8 @@ step_with_expectation(svn_sqlite__stmt_t
     return svn_error_create(SVN_ERR_SQLITE_ERROR,
                             svn_sqlite__reset(stmt),
                             expecting_row
-                              ? _("Expected database row missing")
-                              : _("Extra database row found"));
+                              ? _("sqlite: Expected database row missing")
+                              : _("sqlite: Extra database row found"));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/string.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/string.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/string.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/string.c Fri Nov 30 18:12:52 2012
@@ -37,30 +37,108 @@
 #include "svn_private_config.h"
 
 
-/* Our own realloc, since APR doesn't have one.  Note: this is a
-   generic realloc for memory pools, *not* for strings. */
-static void *
-my__realloc(char *data, apr_size_t oldsize, apr_size_t request,
-            apr_pool_t *pool)
-{
-  void *new_area;
-
-  /* kff todo: it's a pity APR doesn't give us this -- sometimes it
-     could realloc the block merely by extending in place, sparing us
-     a memcpy(), but only the pool would know enough to be able to do
-     this.  We should add a realloc() to APR if someone hasn't
-     already. */
-
-  /* malloc new area */
-  new_area = apr_palloc(pool, request);
 
-  /* copy data to new area */
-  memcpy(new_area, data, oldsize);
+/* Allocate the space for a memory buffer from POOL.
+ * Return a pointer to the new buffer in *DATA and its size in *SIZE.
+ * The buffer size will be at least MINIMUM_SIZE.
+ *
+ * N.B.: The stringbuf creation functions use this, but since stringbufs
+ *       always consume at least 1 byte for the NUL terminator, the
+ *       resulting data pointers will never be NULL.
+ */
+static APR_INLINE void
+membuf_create(void **data, apr_size_t *size,
+              apr_size_t minimum_size, apr_pool_t *pool)
+{
+  /* apr_palloc will allocate multiples of 8.
+   * Thus, we would waste some of that memory if we stuck to the
+   * smaller size. Note that this is safe even if apr_palloc would
+   * use some other aligment or none at all. */
+  minimum_size = APR_ALIGN_DEFAULT(minimum_size);
+  *data = (!minimum_size ? NULL : apr_palloc(pool, minimum_size));
+  *size = minimum_size;
+}
+
+/* Ensure that the size of a given memory buffer is at least MINIMUM_SIZE
+ * bytes. If *SIZE is already greater than or equal to MINIMUM_SIZE,
+ * this function does nothing.
+ *
+ * If *SIZE is 0, the allocated buffer size will be MINIMUM_SIZE
+ * rounded up to the nearest APR alignment boundary. Otherwse, *SIZE
+ * will be multiplied by a power of two such that the result is
+ * greater or equal to MINIMUM_SIZE. The pointer to the new buffer
+ * will be returned in *DATA, and its size in *SIZE.
+ */
+static APR_INLINE void
+membuf_ensure(void **data, apr_size_t *size,
+              apr_size_t minimum_size, apr_pool_t *pool)
+{
+  if (minimum_size > *size)
+    {
+      apr_size_t new_size = *size;
+
+      if (new_size == 0)
+        /* APR will increase odd allocation sizes to the next
+         * multiple for 8, for instance. Take advantage of that
+         * knowledge and allow for the extra size to be used. */
+        new_size = minimum_size;
+      else
+        while (new_size < minimum_size)
+          {
+            /* new_size is aligned; doubling it should keep it aligned */
+            const apr_size_t prev_size = new_size;
+            new_size *= 2;
+
+            /* check for apr_size_t overflow */
+            if (prev_size > new_size)
+              {
+                new_size = minimum_size;
+                break;
+              }
+          }
 
-  /* I'm NOT freeing old area here -- cuz we're using pools, ugh. */
+      membuf_create(data, size, new_size, pool);
+    }
+}
 
-  /* return new area */
-  return new_area;
+void
+svn_membuf__create(svn_membuf_t *membuf, apr_size_t size, apr_pool_t *pool)
+{
+  membuf_create(&membuf->data, &membuf->size, size, pool);
+  membuf->pool = pool;
+}
+
+void
+svn_membuf__ensure(svn_membuf_t *membuf, apr_size_t size)
+{
+  membuf_ensure(&membuf->data, &membuf->size, size, membuf->pool);
+}
+
+void
+svn_membuf__resize(svn_membuf_t *membuf, apr_size_t size)
+{
+  const void *const old_data = membuf->data;
+  const apr_size_t old_size = membuf->size;
+
+  membuf_ensure(&membuf->data, &membuf->size, size, membuf->pool);
+  if (membuf->data && old_data && old_data != membuf->data)
+    memcpy(membuf->data, old_data, old_size);
+}
+
+/* Always provide an out-of-line implementation of svn_membuf__zero */
+#undef svn_membuf__zero
+void
+svn_membuf__zero(svn_membuf_t *membuf)
+{
+  SVN_MEMBUF__ZERO(membuf);
+}
+
+/* Always provide an out-of-line implementation of svn_membuf__nzero */
+#undef svn_membuf__nzero
+void
+svn_membuf__nzero(svn_membuf_t *membuf, apr_size_t size)
+{
+  SVN_MEMBUF__NZERO(membuf, size);
 }
 
 static APR_INLINE svn_boolean_t
@@ -283,28 +361,6 @@ svn_stringbuf__morph_into_string(svn_str
 
 /* svn_stringbuf functions */
 
-/* Create a stringbuf referring to (not copying) an existing block of memory
- * at DATA, of which SIZE bytes are the user data and BLOCKSIZE bytes are
- * allocated in total.  DATA[SIZE] must be a zero byte. */
-static svn_stringbuf_t *
-create_stringbuf(char *data, apr_size_t size, apr_size_t blocksize,
-                 apr_pool_t *pool)
-{
-  svn_stringbuf_t *new_string;
-
-  new_string = apr_palloc(pool, sizeof(*new_string));
-
-  SVN_ERR_ASSERT_NO_RETURN(size < blocksize);
-  SVN_ERR_ASSERT_NO_RETURN(data[size] == '\0');
-
-  new_string->data = data;
-  new_string->len = size;
-  new_string->blocksize = blocksize;
-  new_string->pool = pool;
-
-  return new_string;
-}
-
 svn_stringbuf_t *
 svn_stringbuf_create_empty(apr_pool_t *pool)
 {
@@ -317,24 +373,17 @@ svn_stringbuf_create_ensure(apr_size_t b
   void *mem;
   svn_stringbuf_t *new_string;
 
-  /* apr_palloc will allocate multiples of 8.
-   * Thus, we would waste some of that memory if we stuck to the
-   * smaller size. Note that this is safe even if apr_palloc would
-   * use some other aligment or none at all. */
-
   ++blocksize; /* + space for '\0' */
-  blocksize = APR_ALIGN_DEFAULT(blocksize);
 
   /* Allocate memory for svn_string_t and data in one chunk. */
-  mem = apr_palloc(pool, sizeof(*new_string) + blocksize);
+  membuf_create(&mem, &blocksize, blocksize + sizeof(*new_string), pool);
 
   /* Initialize header and string */
   new_string = mem;
-
   new_string->data = (char*)mem + sizeof(*new_string);
   new_string->data[0] = '\0';
   new_string->len = 0;
-  new_string->blocksize = blocksize;
+  new_string->blocksize = blocksize - sizeof(*new_string);
   new_string->pool = pool;
 
   return new_string;
@@ -375,9 +424,15 @@ svn_stringbuf_createv(apr_pool_t *pool, 
 {
   char *data = apr_pvsprintf(pool, fmt, ap);
   apr_size_t size = strlen(data);
+  svn_stringbuf_t *new_string;
+
+  new_string = apr_palloc(pool, sizeof(*new_string));
+  new_string->data = data;
+  new_string->len = size;
+  new_string->blocksize = size + 1;
+  new_string->pool = pool;
 
-  /* wrap an svn_stringbuf_t around the new data */
-  return create_stringbuf(data, size, size + 1, pool);
+  return new_string;
 }
 
 
@@ -444,38 +499,15 @@ svn_stringbuf_isempty(const svn_stringbu
 void
 svn_stringbuf_ensure(svn_stringbuf_t *str, apr_size_t minimum_size)
 {
+  void *mem = NULL;
   ++minimum_size;  /* + space for '\0' */
 
-  /* Keep doubling capacity until have enough. */
-  if (str->blocksize < minimum_size)
+  membuf_ensure(&mem, &str->blocksize, minimum_size, str->pool);
+  if (mem && mem != str->data)
     {
-      if (str->blocksize == 0)
-        /* APR will increase odd allocation sizes to the next
-         * multiple for 8, for instance. Take advantage of that
-         * knowledge and allow for the extra size to be used. */
-        str->blocksize = APR_ALIGN_DEFAULT(minimum_size);
-      else
-        while (str->blocksize < minimum_size)
-          {
-            /* str->blocksize is aligned;
-             * doubling it should keep it aligned */
-            apr_size_t prev_size = str->blocksize;
-            str->blocksize *= 2;
-
-            /* check for apr_size_t overflow */
-            if (prev_size > str->blocksize)
-              {
-                str->blocksize = minimum_size;
-                break;
-              }
-          }
-
-      str->data = (char *) my__realloc(str->data,
-                                       str->len + 1,
-                                       /* We need to maintain (and thus copy)
-                                          the trailing nul */
-                                       str->blocksize,
-                                       str->pool);
+      if (str->data)
+        memcpy(mem, str->data, str->len + 1);
+      str->data = mem;
     }
 }
 
@@ -1134,3 +1166,108 @@ svn__i64toa_sep(apr_int64_t number, char
   return apr_pstrdup(pool, buffer);
 }
 
+unsigned int
+svn_cstring__similarity(const char *stra, const char *strb,
+                        svn_membuf_t *buffer, apr_size_t *rlcs)
+{
+  svn_string_t stringa, stringb;
+  stringa.data = stra;
+  stringa.len = strlen(stra);
+  stringb.data = strb;
+  stringb.len = strlen(strb);
+  return svn_string__similarity(&stringa, &stringb, buffer, rlcs);
+}
+
+unsigned int
+svn_string__similarity(const svn_string_t *stringa,
+                       const svn_string_t *stringb,
+                       svn_membuf_t *buffer, apr_size_t *rlcs)
+{
+  const char *stra = stringa->data;
+  const char *strb = stringb->data;
+  const apr_size_t lena = stringa->len;
+  const apr_size_t lenb = stringb->len;
+  const apr_size_t total = lena + lenb;
+  const char *enda = stra + lena;
+  const char *endb = strb + lenb;
+  apr_size_t lcs = 0;
+
+  /* Skip the common prefix ... */
+  while (stra < enda && strb < endb && *stra == *strb)
+    {
+      ++stra; ++strb;
+      ++lcs;
+    }
+
+  /* ... and the common suffix */
+  while (stra < enda && strb < endb)
+    {
+      --enda; --endb;
+      if (*enda != *endb)
+        {
+          ++enda; ++endb;
+          break;
+        }
+
+      ++lcs;
+    }
+
+  if (stra < enda && strb < endb)
+    {
+      const apr_size_t resta = enda - stra;
+      const apr_size_t restb = endb - strb;
+      const apr_size_t slots = (resta > restb ? restb : resta);
+      apr_size_t *curr, *prev;
+      const char *pstr;
+
+      /* The outer loop must iterate on the longer string. */
+      if (resta < restb)
+        {
+          pstr = stra;
+          stra = strb;
+          strb = pstr;
+
+          pstr = enda;
+          enda = endb;
+          endb = pstr;
+        }
+
+      /* Allocate two columns in the LCS matrix
+         ### Optimize this to (slots + 2) instesd of 2 * (slots + 1) */
+      svn_membuf__ensure(buffer, 2 * (slots + 1) * sizeof(apr_size_t));
+      svn_membuf__nzero(buffer, (slots + 2) * sizeof(apr_size_t));
+      prev = buffer->data;
+      curr = prev + slots + 1;
+
+      /* Calculate LCS length of the remainder */
+      for (pstr = stra; pstr < enda; ++pstr)
+        {
+          int i;
+          for (i = 1; i <= slots; ++i)
+            {
+              if (*pstr == strb[i-1])
+                curr[i] = prev[i-1] + 1;
+              else
+                curr[i] = (curr[i-1] > prev[i] ? curr[i-1] : prev[i]);
+            }
+
+          /* Swap the buffers, making the previous one current */
+          {
+            apr_size_t *const temp = prev;
+            prev = curr;
+            curr = temp;
+          }
+        }
+
+      lcs += prev[slots];
+    }
+
+  if (rlcs)
+    *rlcs = lcs;
+
+  /* Return similarity ratio rounded to 4 significant digits */
+  if (total)
+    return(unsigned int)((2000 * lcs + total/2) / total);
+  else
+    return 1000;
+}

Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/temp_serializer.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/temp_serializer.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/temp_serializer.c Fri Nov 30 18:12:52 2012
@@ -86,11 +86,11 @@ align_buffer_end(svn_temp_serializer__co
 {
   apr_size_t current_len = context->buffer->len;
   apr_size_t aligned_len = APR_ALIGN_DEFAULT(current_len);
-  if (aligned_len != current_len)
-    {
-      svn_stringbuf_ensure(context->buffer, aligned_len);
-      context->buffer->len = aligned_len;
-    }
+
+  if (aligned_len + 1 > context->buffer->blocksize)
+    svn_stringbuf_ensure(context->buffer, aligned_len);
+
+   context->buffer->len = aligned_len;
 }
 
 /* Begin the serialization process for the SOURCE_STRUCT and all objects

Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/win32_crashrpt.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/win32_crashrpt.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/win32_crashrpt.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/win32_crashrpt.c Fri Nov 30 18:12:52 2012
@@ -21,6 +21,9 @@
  * ====================================================================
  */
 
+/* prevent "empty compilation unit" warning on e.g. UNIX */
+typedef int win32_crashrpt__dummy;
+
 #ifdef WIN32
 #ifdef SVN_USE_WIN32_CRASHHANDLER
 

Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/win32_crypto.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/win32_crypto.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/win32_crypto.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/win32_crypto.c Fri Nov 30 18:12:52 2012
@@ -21,6 +21,9 @@
  * ====================================================================
  */
 
+/* prevent "empty compilation unit" warning on e.g. UNIX */
+typedef int win32_crypto__dummy;
+
 /* ==================================================================== */
 
 #if defined(WIN32) && !defined(__MINGW32__)

Modified: subversion/branches/tree-read-api/subversion/libsvn_subr/win32_xlate.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_subr/win32_xlate.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_subr/win32_xlate.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_subr/win32_xlate.c Fri Nov 30 18:12:52 2012
@@ -21,6 +21,9 @@
  * ====================================================================
  */
 
+/* prevent "empty compilation unit" warning on e.g. UNIX */
+typedef int win32_xlate__dummy;
+
 #ifdef WIN32
 
 /* Define _WIN32_DCOM for CoInitializeEx(). */

Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/adm_ops.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/adm_ops.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/adm_ops.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/adm_ops.c Fri Nov 30 18:12:52 2012
@@ -2446,9 +2446,19 @@ svn_wc_add_lock2(svn_wc_context_t *wc_ct
     }
 
   /* if svn:needs-lock is present, then make the file read-write. */
-  SVN_ERR(svn_wc__internal_propget(&needs_lock, wc_ctx->db, local_abspath,
-                                   SVN_PROP_NEEDS_LOCK, scratch_pool,
-                                   scratch_pool));
+  err = svn_wc__internal_propget(&needs_lock, wc_ctx->db, local_abspath,
+                                 SVN_PROP_NEEDS_LOCK, scratch_pool,
+                                 scratch_pool);
+
+  if (err && err->apr_err == SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
+    {
+      /* The node has non wc representation (e.g. deleted), so
+         we don't want to touch the in-wc file */
+      svn_error_clear(err);
+      return SVN_NO_ERROR;
+    }
+  SVN_ERR(err);
+
   if (needs_lock)
     SVN_ERR(svn_io_set_file_read_write(local_abspath, FALSE, scratch_pool));
 

Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/deprecated.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/deprecated.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/deprecated.c Fri Nov 30 18:12:52 2012
@@ -3196,6 +3196,38 @@ svn_wc_get_actual_target(const char *pat
   return svn_error_trace(svn_wc_context_destroy(wc_ctx));
 }
 
+/* This function has no internal variant as its behavior on switched
+   non-directories is not what you would expect. But this happens to
+   be the legacy behavior of this function. */
+svn_error_t *
+svn_wc_is_wc_root2(svn_boolean_t *wc_root,
+                   svn_wc_context_t *wc_ctx,
+                   const char *local_abspath,
+                   apr_pool_t *scratch_pool)
+{
+  svn_boolean_t is_root;
+  svn_boolean_t is_switched;
+  svn_kind_t kind;
+  svn_error_t *err;
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  err = svn_wc__check_wc_root(&is_root, &kind, &is_switched,
+                              wc_ctx->db, local_abspath, scratch_pool);
+
+  if (err)
+    {
+      if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND &&
+          err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
+        return svn_error_trace(err);
+
+      return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND, err, err->message);
+    }
+
+  *wc_root = is_root || (kind == svn_kind_dir && is_switched);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_wc_is_wc_root(svn_boolean_t *wc_root,
                   const char *path,

Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/diff_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/diff_editor.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/diff_editor.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/diff_editor.c Fri Nov 30 18:12:52 2012
@@ -610,8 +610,8 @@ file_diff(struct edit_baton *eb,
       apr_hash_t *baseprops;
 
       /* Get svn:mime-type from pristine props (in BASE or WORKING) of PATH. */
-      SVN_ERR(svn_wc__get_pristine_props(&baseprops, db, local_abspath,
-                                         scratch_pool, scratch_pool));
+      SVN_ERR(svn_wc__db_read_pristine_props(&baseprops, db, local_abspath,
+                                             scratch_pool, scratch_pool));
       if (baseprops)
         base_mimetype = get_prop_mimetype(baseprops);
       else
@@ -731,8 +731,8 @@ file_diff(struct edit_baton *eb,
                          || status == svn_wc__db_status_copied
                          || status == svn_wc__db_status_moved_here);
 
-          SVN_ERR(svn_wc__get_pristine_props(&baseprops, db, local_abspath,
-                                             scratch_pool, scratch_pool));
+          SVN_ERR(svn_wc__db_read_pristine_props(&baseprops, db, local_abspath,
+                                                 scratch_pool, scratch_pool));
 
           /* baseprops will be NULL for added nodes */
           if (!baseprops)
@@ -984,8 +984,8 @@ report_wc_file_as_added(struct edit_bato
   emptyprops = apr_hash_make(scratch_pool);
 
   if (eb->use_text_base)
-    SVN_ERR(svn_wc__get_pristine_props(&wcprops, db, local_abspath,
-                                       scratch_pool, scratch_pool));
+    SVN_ERR(svn_wc__db_read_pristine_props(&wcprops, db, local_abspath,
+                                           scratch_pool, scratch_pool));
   else
     SVN_ERR(svn_wc__get_actual_props(&wcprops, db, local_abspath,
                                      scratch_pool, scratch_pool));
@@ -996,16 +996,21 @@ report_wc_file_as_added(struct edit_bato
 
 
   if (eb->use_text_base)
-    SVN_ERR(get_pristine_file(&source_file, db, local_abspath,
-                              FALSE, scratch_pool, scratch_pool));
+    {
+      SVN_ERR(get_pristine_file(&source_file, db, local_abspath,
+                                FALSE, scratch_pool, scratch_pool));
+      translated_file = source_file; /* No translation needed */
+    }
   else
-    source_file = local_abspath;
+    {
+      source_file = local_abspath;
 
-  SVN_ERR(svn_wc__internal_translated_file(
+      SVN_ERR(svn_wc__internal_translated_file(
            &translated_file, source_file, db, local_abspath,
            SVN_WC_TRANSLATE_TO_NF | SVN_WC_TRANSLATE_USE_GLOBAL_TMP,
            eb->cancel_func, eb->cancel_baton,
            scratch_pool, scratch_pool));
+    }
 
   SVN_ERR(eb->callbacks->file_added(NULL, NULL, NULL,
                                     path,
@@ -1054,8 +1059,8 @@ report_wc_directory_as_added(struct edit
                                         eb->changelist_hash, scratch_pool))
     {
       if (eb->use_text_base)
-        SVN_ERR(svn_wc__get_pristine_props(&wcprops, db, local_abspath,
-                                           scratch_pool, scratch_pool));
+        SVN_ERR(svn_wc__db_read_pristine_props(&wcprops, db, local_abspath,
+                                               scratch_pool, scratch_pool));
       else
         SVN_ERR(svn_wc__get_actual_props(&wcprops, db, local_abspath,
                                          scratch_pool, scratch_pool));
@@ -1227,8 +1232,9 @@ delete_entry(const char *path,
           SVN_ERR(get_pristine_file(&textbase, db, local_abspath,
                                     eb->use_text_base, pool, pool));
 
-          SVN_ERR(svn_wc__get_pristine_props(&baseprops, eb->db, local_abspath,
-                                             pool, pool));
+          SVN_ERR(svn_wc__db_read_pristine_props(&baseprops,
+                                                 eb->db, local_abspath,
+                                                 pool, pool));
           base_mimetype = get_prop_mimetype(baseprops);
 
           SVN_ERR(eb->callbacks->file_deleted(NULL, NULL, path,
@@ -1349,9 +1355,10 @@ close_directory(void *dir_baton,
         {
           if (db->eb->use_text_base)
             {
-              SVN_ERR(svn_wc__get_pristine_props(&originalprops,
-                                                 eb->db, db->local_abspath,
-                                                 scratch_pool, scratch_pool));
+              SVN_ERR(svn_wc__db_read_pristine_props(&originalprops,
+                                                     eb->db, db->local_abspath,
+                                                     scratch_pool,
+                                                     scratch_pool));
             }
           else
             {
@@ -1362,9 +1369,9 @@ close_directory(void *dir_baton,
                                                scratch_pool, scratch_pool));
 
               /* Load the BASE and repository directory properties. */
-              SVN_ERR(svn_wc__get_pristine_props(&base_props,
-                                                 eb->db, db->local_abspath,
-                                                 scratch_pool, scratch_pool));
+              SVN_ERR(svn_wc__db_base_get_props(&base_props,
+                                                eb->db, db->local_abspath,
+                                                scratch_pool, scratch_pool));
 
               repos_props = apply_propchanges(base_props, db->propchanges);
 

Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/diff_local.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/diff_local.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/diff_local.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/diff_local.c Fri Nov 30 18:12:52 2012
@@ -239,8 +239,8 @@ file_diff(struct diff_baton *eb,
           /* We show a deletion of what was actually deleted */
           SVN_ERR_ASSERT(status == svn_wc__db_status_deleted);
 
-          SVN_ERR(svn_wc__get_pristine_props(&del_props, db, local_abspath,
-                                             scratch_pool, scratch_pool));
+          SVN_ERR(svn_wc__db_read_pristine_props(&del_props, db, local_abspath,
+                                                 scratch_pool, scratch_pool));
 
           SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, NULL, NULL, NULL,
                                                 NULL, &del_checksum, NULL,
@@ -513,9 +513,7 @@ diff_status_callback(void *baton,
       /* Report the prop change. */
       /* ### This case should probably be extended for git-diff, but this
              is what the old diff code provided */
-      if (status->node_status == svn_wc_status_deleted
-          || status->node_status == svn_wc_status_replaced
-          || status->prop_status == svn_wc_status_modified)
+      if (status->prop_status == svn_wc_status_modified)
         {
           apr_array_header_t *propchanges;
           apr_hash_t *baseprops;

Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/externals.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/externals.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/externals.c Fri Nov 30 18:12:52 2012
@@ -164,16 +164,15 @@ svn_wc_parse_externals_description3(apr_
                                     apr_pool_t *pool)
 {
   int i;
-  int j;
   apr_array_header_t *externals = NULL;
   apr_array_header_t *lines = svn_cstring_split(desc, "\n\r", TRUE, pool);
   const char *parent_directory_display = svn_path_is_url(parent_directory) ?
     parent_directory : svn_dirent_local_style(parent_directory, pool);
 
   /* If an error occurs halfway through parsing, *externals_p should stay
-   * untouched. So, store the list in a local var first. Since we are checking
-   * for duplicate targets, always compose the list regardless. */
-  externals = apr_array_make(pool, 1, sizeof(svn_wc_external_item2_t *));
+   * untouched. So, store the list in a local var first. */
+  if (externals_p)
+    externals = apr_array_make(pool, 1, sizeof(svn_wc_external_item2_t *));
 
   for (i = 0; i < lines->nelts; i++)
     {
@@ -331,23 +330,8 @@ svn_wc_parse_externals_description3(apr_
             item->url = svn_dirent_canonicalize(item->url, pool);
         }
 
-      /* Has the same WC target path already been mentioned in this prop? */
-      for (j = 0; j < externals->nelts; j++)
-        {
-          svn_wc_external_item2_t *other_item =
-              APR_ARRAY_IDX(externals, j, svn_wc_external_item2_t *);
-
-          if (strcmp(item->target_dir, other_item->target_dir) == 0)
-            return svn_error_createf
-              (SVN_ERR_CLIENT_INVALID_EXTERNALS_DESCRIPTION, NULL,
-               _("Invalid %s property on '%s': "
-                 "target '%s' appears more than once"),
-               SVN_PROP_EXTERNALS,
-               parent_directory_display,
-               item->target_dir);
-        }
-
-      APR_ARRAY_PUSH(externals, svn_wc_external_item2_t *) = item;
+      if (externals)
+        APR_ARRAY_PUSH(externals, svn_wc_external_item2_t *) = item;
     }
 
   if (externals_p)
@@ -356,6 +340,53 @@ svn_wc_parse_externals_description3(apr_
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_wc__externals_find_target_dups(apr_array_header_t **duplicate_targets,
+                                   apr_array_header_t *externals,
+                                   apr_pool_t *pool,
+                                   apr_pool_t *scratch_pool)
+{
+  int i;
+  unsigned int len;
+  unsigned int len2;
+  const char *target;
+  apr_hash_t *targets = apr_hash_make(scratch_pool);
+  apr_hash_t *targets2 = NULL;
+  *duplicate_targets = NULL;
+
+  for (i = 0; i < externals->nelts; i++)
+    {
+      target = APR_ARRAY_IDX(externals, i,
+                                         svn_wc_external_item2_t*)->target_dir;
+      len = apr_hash_count(targets);
+      apr_hash_set(targets, target, APR_HASH_KEY_STRING, "");
+      if (len == apr_hash_count(targets))
+        {
+          /* Hashtable length is unchanged. This must be a duplicate. */
+
+          /* Collapse multiple duplicates of the same target by using a second
+           * hash layer. */
+          if (! targets2)
+            targets2 = apr_hash_make(scratch_pool);
+          len2 = apr_hash_count(targets2);
+          apr_hash_set(targets2, target, APR_HASH_KEY_STRING, "");
+          if (len2 < apr_hash_count(targets2))
+            {
+              /* The second hash list just got bigger, i.e. this target has
+               * not been counted as duplicate before. */
+              if (! *duplicate_targets)
+                {
+                  *duplicate_targets = apr_array_make(
+                                    pool, 1, sizeof(svn_wc_external_item2_t*));
+                }
+              APR_ARRAY_PUSH((*duplicate_targets), const char *) = target;
+            }
+          /* Else, this same target has already been recorded as a duplicate,
+           * don't count it again. */
+        }
+    }
+  return SVN_NO_ERROR;
+}
 
 struct edit_baton
 {

Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/lock.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/lock.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/lock.c Fri Nov 30 18:12:52 2012
@@ -1066,75 +1066,21 @@ child_is_disjoint(svn_boolean_t *disjoin
                   const char *local_abspath,
                   apr_pool_t *scratch_pool)
 {
-  const char *node_repos_root, *node_repos_relpath, *node_repos_uuid;
-  const char *parent_repos_root, *parent_repos_relpath, *parent_repos_uuid;
-  svn_wc__db_status_t parent_status;
-  const char *parent_abspath, *base;
+  svn_boolean_t is_switched;
 
   /* Check if the parent directory knows about this node */
-  SVN_ERR(svn_wc__db_is_wcroot(disjoint, db, local_abspath, scratch_pool));
+  SVN_ERR(svn_wc__db_is_switched(disjoint, &is_switched, NULL,
+                                 db, local_abspath, scratch_pool));
 
   if (*disjoint)
     return SVN_NO_ERROR;
 
-  svn_dirent_split(&parent_abspath, &base, local_abspath, scratch_pool);
-
-  SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL, &node_repos_relpath,
-                               &node_repos_root, &node_repos_uuid, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL,
-                               db, local_abspath,
-                               scratch_pool, scratch_pool));
-
-  /* If the node does not have its own repos_relpath, its value is inherited
-     from a parent node, which implies that the node is not disjoint. */
-  if (node_repos_relpath == NULL)
-    {
-      *disjoint = FALSE;
-      return SVN_NO_ERROR;
-    }
-
-  SVN_ERR(svn_wc__db_read_info(&parent_status, NULL, NULL,
-                               &parent_repos_relpath, &parent_repos_root,
-                               &parent_repos_uuid, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL,
-                               db, parent_abspath,
-                               scratch_pool, scratch_pool));
-
-  if (parent_repos_relpath == NULL)
-    {
-      if (parent_status == svn_wc__db_status_added)
-        SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, &parent_repos_relpath,
-                                         &parent_repos_root,
-                                         &parent_repos_uuid,
-                                         NULL, NULL, NULL, NULL, NULL, NULL,
-                                         db, parent_abspath,
-                                         scratch_pool, scratch_pool));
-      else
-        SVN_ERR(svn_wc__db_scan_base_repos(&parent_repos_relpath,
-                                           &parent_repos_root,
-                                           &parent_repos_uuid,
-                                           db, parent_abspath,
-                                           scratch_pool, scratch_pool));
-    }
-
-  if (strcmp(parent_repos_root, node_repos_root) != 0 ||
-      strcmp(parent_repos_uuid, node_repos_uuid) != 0 ||
-      strcmp(svn_relpath_join(parent_repos_relpath, base, scratch_pool),
-             node_repos_relpath) != 0)
-    {
-      *disjoint = TRUE;
-    }
-  else
-    *disjoint = FALSE;
+  if (is_switched)
+    *disjoint = TRUE;
 
   return SVN_NO_ERROR;
 }
 
-
 /* */
 static svn_error_t *
 open_anchor(svn_wc_adm_access_t **anchor_access,
@@ -1522,13 +1468,25 @@ svn_wc__acquire_write_lock(const char **
                            apr_pool_t *scratch_pool)
 {
   svn_wc__db_t *db = wc_ctx->db;
+  svn_boolean_t is_wcroot;
+  svn_boolean_t is_switched;
   svn_kind_t kind;
   svn_error_t *err;
 
-  SVN_ERR(svn_wc__db_read_kind(&kind, wc_ctx->db, local_abspath,
-                               (lock_root_abspath != NULL) /* allow_missing*/,
-                               FALSE /* show_hidden */,
-                               scratch_pool));
+  err = svn_wc__db_is_switched(&is_wcroot, &is_switched, &kind,
+                               db, local_abspath, scratch_pool);
+
+  if (err)
+    {
+      if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
+        return svn_error_trace(err);
+
+      svn_error_clear(err);
+
+      kind = svn_kind_none;
+      is_wcroot = FALSE;
+      is_switched = FALSE;
+    }
 
   if (!lock_root_abspath && kind != svn_kind_dir)
     return svn_error_createf(SVN_ERR_WC_NOT_DIRECTORY, NULL,
@@ -1538,15 +1496,6 @@ svn_wc__acquire_write_lock(const char **
 
   if (lock_anchor && kind == svn_kind_dir)
     {
-      svn_boolean_t is_wcroot;
-
-      SVN_ERR_ASSERT(lock_root_abspath != NULL);
-
-      /* Perform a cheap check to avoid looking for a parent working copy,
-         which might be very expensive in some specific scenarios */
-      SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, db, local_abspath,
-                                   scratch_pool));
-
       if (is_wcroot)
         lock_anchor = FALSE;
     }
@@ -1554,58 +1503,48 @@ svn_wc__acquire_write_lock(const char **
   if (lock_anchor)
     {
       const char *parent_abspath;
-      svn_kind_t parent_kind;
-
       SVN_ERR_ASSERT(lock_root_abspath != NULL);
 
       parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
-      err = svn_wc__db_read_kind(&parent_kind, db, parent_abspath,
-                                 TRUE /* allow_missing */,
-                                 FALSE /* show_missing */,
-                                 scratch_pool);
-      if (err && SVN_WC__ERR_IS_NOT_CURRENT_WC(err))
+
+      if (kind == svn_kind_dir)
         {
-          svn_error_clear(err);
-          parent_kind = svn_kind_unknown;
+          if (! is_switched)
+            local_abspath = parent_abspath;
+        }
+      else if (kind != svn_kind_none && kind != svn_kind_unknown)
+        {
+          /* In the single-DB world we know parent exists */
+          local_abspath = parent_abspath;
         }
       else
-        SVN_ERR(err);
-
-      if (kind == svn_kind_dir && parent_kind == svn_kind_dir)
         {
-          svn_boolean_t disjoint;
-          SVN_ERR(child_is_disjoint(&disjoint, wc_ctx->db, local_abspath,
-                                    scratch_pool));
-          if (!disjoint)
-            local_abspath = parent_abspath;
+          /* Can't lock parents that don't exist */
+          svn_kind_t parent_kind;
+          err = svn_wc__db_read_kind(&parent_kind, db, parent_abspath,
+                                     TRUE /* allow_missing */,
+                                     FALSE /* show_hidden */,
+                                     scratch_pool);
+          if (err && SVN_WC__ERR_IS_NOT_CURRENT_WC(err))
+            {
+              svn_error_clear(err);
+              parent_kind = svn_kind_unknown;
+            }
+          else
+            SVN_ERR(err);
+
+          if (parent_kind != svn_kind_dir)
+            return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
+                                     _("'%s' is not a working copy"),
+                                     svn_dirent_local_style(local_abspath,
+                                                            scratch_pool));
+
+          local_abspath = parent_abspath;
         }
-      else if (parent_kind == svn_kind_dir)
-        local_abspath = parent_abspath;
-      else if (kind != svn_kind_dir)
-        return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
-                                 _("'%s' is not a working copy"),
-                                 svn_dirent_local_style(local_abspath,
-                                                        scratch_pool));
     }
   else if (kind != svn_kind_dir)
     {
       local_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
-
-      /* Can't lock parents that don't exist */
-      if (kind == svn_kind_unknown)
-        {
-          SVN_ERR(svn_wc__db_read_kind(&kind, db, local_abspath,
-                                       FALSE /* allow_missing */,
-                                       FALSE /* show_hidden */,
-                                       scratch_pool));
-
-          if (kind != svn_kind_dir)
-            return svn_error_createf(
-                             SVN_ERR_WC_NOT_DIRECTORY, NULL,
-                             _("Can't obtain lock on non-directory '%s'."),
-                             svn_dirent_local_style(local_abspath,
-                                                    scratch_pool));
-        }
     }
 
   if (lock_root_abspath)

Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/props.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/props.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/props.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/props.c Fri Nov 30 18:12:52 2012
@@ -280,8 +280,8 @@ svn_wc__perform_props_merge(svn_wc_notif
     }
 
   if (had_props)
-    SVN_ERR(svn_wc__get_pristine_props(&pristine_props, db, local_abspath,
-                                       scratch_pool, scratch_pool));
+    SVN_ERR(svn_wc__db_read_pristine_props(&pristine_props, db, local_abspath,
+                                           scratch_pool, scratch_pool));
   if (pristine_props == NULL)
     pristine_props = apr_hash_make(scratch_pool);
 
@@ -1513,13 +1513,13 @@ svn_wc__prop_retrieve_recursive(apr_hash
 }
 
 svn_error_t *
-svn_wc__get_pristine_props(apr_hash_t **props,
-                           svn_wc__db_t *db,
-                           const char *local_abspath,
-                           apr_pool_t *result_pool,
-                           apr_pool_t *scratch_pool)
+svn_wc_get_pristine_props(apr_hash_t **props,
+                          svn_wc_context_t *wc_ctx,
+                          const char *local_abspath,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
 {
-  svn_wc__db_status_t status;
+  svn_error_t *err;
 
   SVN_ERR_ASSERT(props != NULL);
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
@@ -1527,60 +1527,23 @@ svn_wc__get_pristine_props(apr_hash_t **
   /* Certain node stats do not have properties defined on them. Check the
      state, and return NULL for these situations.  */
 
-  SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL,
-                               db, local_abspath,
-                               scratch_pool, scratch_pool));
-  if (status == svn_wc__db_status_added)
-    {
-      /* Resolve the status. copied and moved_here arrive with properties,
-         while a simple add does not.  */
-      SVN_ERR(svn_wc__db_scan_addition(&status, NULL,
-                                       NULL, NULL, NULL,
-                                       NULL, NULL, NULL, NULL, NULL, NULL,
-                                       db, local_abspath,
-                                       scratch_pool, scratch_pool));
-    }
-  if (status == svn_wc__db_status_added
-#if 0
-      /* ### the update editor needs to fetch properties while the directory
-         ### is still marked incomplete  */
-      || status == svn_wc__db_status_incomplete
-#endif
-      || status == svn_wc__db_status_excluded
-      || status == svn_wc__db_status_server_excluded
-      || status == svn_wc__db_status_not_present)
-    {
-      *props = NULL;
-      return SVN_NO_ERROR;
-    }
+  err = svn_wc__db_read_pristine_props(props, wc_ctx->db, local_abspath,
+                                       result_pool, scratch_pool);
 
-  /* status: normal, moved_here, copied, deleted  */
+  if (err)
+    {
+      if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
+        return svn_error_trace(err);
 
-  /* After the above checks, these pristines should always be present.  */
-  return svn_error_trace(
-               svn_wc__db_read_pristine_props(props, db, local_abspath,
-                                              result_pool, scratch_pool));
-}
+      svn_error_clear(err);
 
+      /* Documented behavior is to set *PROPS to NULL */
+      *props = NULL;
+    }
 
-svn_error_t *
-svn_wc_get_pristine_props(apr_hash_t **props,
-                          svn_wc_context_t *wc_ctx,
-                          const char *local_abspath,
-                          apr_pool_t *result_pool,
-                          apr_pool_t *scratch_pool)
-{
-  return svn_error_trace(svn_wc__get_pristine_props(props,
-                                                    wc_ctx->db,
-                                                    local_abspath,
-                                                    result_pool,
-                                                    scratch_pool));
+  return SVN_NO_ERROR;
 }
 
-
 svn_error_t *
 svn_wc_prop_get2(const svn_string_t **value,
                  svn_wc_context_t *wc_ctx,
@@ -1590,6 +1553,7 @@ svn_wc_prop_get2(const svn_string_t **va
                  apr_pool_t *scratch_pool)
 {
   enum svn_prop_kind kind = svn_property_kind2(name);
+  svn_error_t *err;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
@@ -1600,8 +1564,18 @@ svn_wc_prop_get2(const svn_string_t **va
                                _("Property '%s' is an entry property"), name);
     }
 
-  SVN_ERR(svn_wc__internal_propget(value, wc_ctx->db, local_abspath, name,
-                                   result_pool, scratch_pool));
+  err = svn_wc__internal_propget(value, wc_ctx->db, local_abspath, name,
+                                 result_pool, scratch_pool);
+
+  if (err)
+    {
+      if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
+        return svn_error_trace(err);
+
+      svn_error_clear(err);
+      /* Documented behavior is to set *VALUE to NULL */
+      *value = NULL;
+    }
 
   return SVN_NO_ERROR;
 }
@@ -1616,35 +1590,15 @@ svn_wc__internal_propget(const svn_strin
 {
   apr_hash_t *prophash = NULL;
   enum svn_prop_kind kind = svn_property_kind2(name);
-  svn_boolean_t hidden;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
   SVN_ERR_ASSERT(kind != svn_prop_entry_kind);
 
-  /* This returns SVN_ERR_WC_PATH_NOT_FOUND for unversioned paths for us */
-  SVN_ERR(svn_wc__db_node_hidden(&hidden, db, local_abspath, scratch_pool));
-  if (hidden)
-    {
-      /* The node is not present, or not really "here". Therefore, the
-         property is not present.  */
-      *value = NULL;
-      return SVN_NO_ERROR;
-    }
-
   if (kind == svn_prop_wc_kind)
     {
-      svn_error_t *err;
-      /* If no dav cache can be found, just set VALUE to NULL (for
-         compatibility with pre-WC-NG code). */
-      err = svn_wc__db_base_get_dav_cache(&prophash, db, local_abspath,
-                                          result_pool, scratch_pool);
-      if (err && (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND))
-        {
-          *value = NULL;
-          svn_error_clear(err);
-          return SVN_NO_ERROR;
-        }
-      SVN_ERR_W(err, _("Failed to load properties"));
+      SVN_ERR_W(svn_wc__db_base_get_dav_cache(&prophash, db, local_abspath,
+                                              result_pool, scratch_pool),
+                _("Failed to load properties"));
     }
   else
     {
@@ -1665,47 +1619,38 @@ svn_wc__internal_propget(const svn_strin
 
 /* The special Subversion properties are not valid for all node kinds.
    Return an error if NAME is an invalid Subversion property for PATH which
-   is of kind NODE_KIND. */
+   is of kind NODE_KIND.  NAME must be in the "svn:" name space.
+
+   Note that we only disallow the property if we're sure it's one that
+   already has a meaning for a different node kind.  We don't disallow
+   setting an *unknown* svn: prop here, at this level; a higher level
+   should disallow that if desired.
+  */
 static svn_error_t *
 validate_prop_against_node_kind(const char *name,
                                 const char *path,
                                 svn_node_kind_t node_kind,
                                 apr_pool_t *pool)
 {
-
-  const char *file_prohibit[] = { SVN_PROP_IGNORE,
-                                  SVN_PROP_EXTERNALS,
-                                  SVN_PROP_INHERITABLE_AUTO_PROPS,
-                                  SVN_PROP_INHERITABLE_IGNORES,
-                                  NULL };
-  const char *dir_prohibit[] = { SVN_PROP_EXECUTABLE,
-                                 SVN_PROP_KEYWORDS,
-                                 SVN_PROP_EOL_STYLE,
-                                 SVN_PROP_MIME_TYPE,
-                                 SVN_PROP_NEEDS_LOCK,
-                                 NULL };
-  const char **node_kind_prohibit;
   const char *path_display
     = svn_path_is_url(path) ? path : svn_dirent_local_style(path, pool);
 
   switch (node_kind)
     {
     case svn_node_dir:
-      node_kind_prohibit = dir_prohibit;
-      while (*node_kind_prohibit)
-        if (strcmp(name, *node_kind_prohibit++) == 0)
-          return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
-                                   _("Cannot set '%s' on a directory ('%s')"),
-                                   name, path_display);
+      if (! svn_prop_is_known_svn_dir_prop(name)
+          && svn_prop_is_known_svn_file_prop(name))
+        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                                 _("Cannot set '%s' on a directory ('%s')"),
+                                 name, path_display);
       break;
     case svn_node_file:
-      node_kind_prohibit = file_prohibit;
-      while (*node_kind_prohibit)
-        if (strcmp(name, *node_kind_prohibit++) == 0)
-          return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
-                                   _("Cannot set '%s' on a file ('%s')"),
-                                   name,
-                                   path_display);
+      if (! svn_prop_is_known_svn_file_prop(name)
+          && svn_prop_is_known_svn_dir_prop(name))
+        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                                 _("Cannot set '%s' on a file ('%s')"),
+                                 name,
+                                 path_display);
       break;
     default:
       return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
@@ -1952,6 +1897,7 @@ do_propset(svn_wc__db_t *db,
                                                      notify_action,
                                                      scratch_pool);
       notify->prop_name = name;
+      notify->kind = kind;
 
       (*notify_func)(notify_baton, notify, scratch_pool);
     }
@@ -2168,9 +2114,34 @@ svn_wc_canonicalize_svn_prop(const svn_s
              an svn:externals line.  As it happens, our parse code
              checks for this, so all we have to is invoke it --
              we're not interested in the parsed result, only in
-             whether or the parsing errored. */
-          SVN_ERR(svn_wc_parse_externals_description3
-                  (NULL, path, propval->data, FALSE, pool));
+             whether or not the parsing errored. */
+          apr_array_header_t *externals = NULL;
+          apr_array_header_t *duplicate_targets = NULL;
+          SVN_ERR(svn_wc_parse_externals_description3(&externals, path,
+                                                      propval->data, FALSE,
+                                                      /*scratch_*/pool));
+          SVN_ERR(svn_wc__externals_find_target_dups(&duplicate_targets,
+                                                     externals,
+                                                     /*scratch_*/pool,
+                                                     /*scratch_*/pool));
+          if (duplicate_targets && duplicate_targets->nelts > 0)
+            {
+              const char *more_str = "";
+              if (duplicate_targets->nelts > 1)
+                {
+                  more_str = apr_psprintf(/*scratch_*/pool,
+                               _(" (%d more duplicate targets found)"),
+                               duplicate_targets->nelts - 1);
+                }
+              return svn_error_createf(
+                SVN_ERR_WC_DUPLICATE_EXTERNALS_TARGET, NULL,
+                _("Invalid %s property on '%s': "
+                  "target '%s' appears more than once%s"),
+                SVN_PROP_EXTERNALS,
+                svn_dirent_local_style(path, pool),
+                APR_ARRAY_IDX(duplicate_targets, 0, const char*),
+                more_str);
+            }
         }
     }
   else if (strcmp(propname, SVN_PROP_KEYWORDS) == 0)
@@ -2338,129 +2309,6 @@ svn_wc__has_magic_property(const apr_arr
   return FALSE;
 }
 
-/* Remove all prop name value pairs from PROP_HASH where the property
-   name is not PROPNAME. */
-static void
-filter_unwanted_props(apr_hash_t *prop_hash,
-                      const char * propname,
-                      apr_pool_t *scratch_pool)
-{
-  apr_hash_index_t *hi;
-
-  for (hi = apr_hash_first(scratch_pool, prop_hash);
-       hi;
-       hi = apr_hash_next(hi))
-    {
-      const char *ipropname = svn__apr_hash_index_key(hi);
-
-      if (strcmp(ipropname, propname) != 0)
-        apr_hash_set(prop_hash, ipropname, APR_HASH_KEY_STRING, NULL);
-    }
-  return;
-}
-
-svn_error_t *
-svn_wc__internal_get_iprops(apr_array_header_t **inherited_props,
-                            svn_wc__db_t *db,
-                            const char *local_abspath,
-                            const char *propname,
-                            apr_pool_t *result_pool,
-                            apr_pool_t *scratch_pool)
-{
-  int i;
-  apr_array_header_t *cached_iprops = NULL;
-  const char *parent_abspath = local_abspath;
-  svn_boolean_t is_wc_root = FALSE;
-  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-
-  SVN_ERR_ASSERT(inherited_props);
-  *inherited_props = apr_array_make(result_pool, 1,
-                                    sizeof(svn_prop_inherited_item_t *));
-
-  /* Walk up to the root of the WC looking for inherited properties.  When we
-     reach the WC root also check for cached inherited properties. */
-  while (TRUE)
-    {
-      apr_hash_t *actual_props;
-
-      svn_pool_clear(iterpool);
-
-      SVN_ERR(svn_wc__internal_is_wc_root(&is_wc_root, db, parent_abspath,
-                                          iterpool));
-
-      if (is_wc_root)
-        {
-          /* If the WC root is also the root of the repository then by
-             definition there are no inheritable properties to be had,
-             but checking for that is just as expensive as fetching them
-             anyway. */
-
-          /* Grab the cached inherited properties for the WC root. */
-          SVN_ERR(svn_wc__db_read_cached_iprops(&cached_iprops, db,
-                                                parent_abspath,
-                                                scratch_pool, iterpool));
-        }
-
-      /* If PARENT_ABSPATH is a true parent of LOCAL_ABSPATH, then
-         LOCAL_ABSPATH can inherit properties from it. */
-      if (strcmp(local_abspath, parent_abspath) != 0)
-        {
-          SVN_ERR(svn_wc__db_read_props(&actual_props, db, parent_abspath,
-                                        result_pool, iterpool));
-          if (actual_props)
-            {
-              /* If we only want PROPNAME filter out any other properties. */
-              if (propname)
-                filter_unwanted_props(actual_props, propname, iterpool);
-
-              if (apr_hash_count(actual_props))
-                {
-                  svn_prop_inherited_item_t *iprop_elt =
-                    apr_pcalloc(result_pool,
-                                sizeof(svn_prop_inherited_item_t));
-                  iprop_elt->path_or_url = apr_pstrdup(result_pool,
-                                                       parent_abspath);
-                  iprop_elt->prop_hash = actual_props;
-                  /* Build the output array in depth-first order. */
-                  svn_sort__array_insert(&iprop_elt, *inherited_props, 0);
-                }
-            }
-        }
-
-      /* Inheritance only goes as far as the nearest WC root. */
-      if (is_wc_root)
-        break;
-
-      /* Keep looking for the WC root. */
-      parent_abspath = svn_dirent_dirname(parent_abspath, scratch_pool);
-    }
-
-  if (cached_iprops)
-    {
-      for (i = cached_iprops->nelts - 1; i >= 0; i--)
-        {
-          svn_prop_inherited_item_t *cached_iprop =
-            APR_ARRAY_IDX(cached_iprops, i, svn_prop_inherited_item_t *);
-
-          /* An empty property hash in the iprops cache means there are no
-             inherited properties. */
-          if (apr_hash_count(cached_iprop->prop_hash) == 0)
-            continue;
-
-          if (propname)
-            filter_unwanted_props(cached_iprop->prop_hash, propname,
-                                  scratch_pool);
-
-          /* If we didn't filter everything then keep this iprop. */
-          if (apr_hash_count(cached_iprop->prop_hash))
-            svn_sort__array_insert(&cached_iprop, *inherited_props, 0);
-        }
-    }
-
-  svn_pool_destroy(iterpool);
-  return SVN_NO_ERROR;
-}
-
 svn_error_t *
 svn_wc__get_iprops(apr_array_header_t **inherited_props,
                    svn_wc_context_t *wc_ctx,
@@ -2469,9 +2317,11 @@ svn_wc__get_iprops(apr_array_header_t **
                    apr_pool_t *result_pool,
                    apr_pool_t *scratch_pool)
 {
-  return svn_error_trace(svn_wc__internal_get_iprops(inherited_props, wc_ctx->db,
-                                               local_abspath, propname,
-                                               result_pool, scratch_pool));
+  return svn_error_trace(
+            svn_wc__db_read_inherited_props(inherited_props,
+                                            wc_ctx->db, local_abspath,
+                                            propname,
+                                            result_pool, scratch_pool));
 }
 
 svn_error_t *

Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/props.h
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/props.h?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/props.h (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/props.h Fri Nov 30 18:12:52 2012
@@ -127,15 +127,6 @@ svn_wc__props_modified(svn_boolean_t *mo
                        const char *local_abspath,
                        apr_pool_t *scratch_pool);
 
-/* Internal version of svn_wc_get_pristine_props().  */
-svn_error_t *
-svn_wc__get_pristine_props(apr_hash_t **props,
-                           svn_wc__db_t *db,
-                           const char *local_abspath,
-                           apr_pool_t *result_pool,
-                           apr_pool_t *scratch_pool);
-
-
 /* Internal version of svn_wc_prop_list2().  */
 svn_error_t *
 svn_wc__get_actual_props(apr_hash_t **props,

Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/status.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/status.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/status.c Fri Nov 30 18:12:52 2012
@@ -1028,9 +1028,10 @@ collect_ignore_patterns(apr_array_header
                                      FALSE, result_pool);      
         }
 
-      SVN_ERR(svn_wc__internal_get_iprops(&inherited_props, db, local_abspath,
-                                          SVN_PROP_INHERITABLE_IGNORES,
-                                          scratch_pool, scratch_pool));
+      SVN_ERR(svn_wc__db_read_inherited_props(&inherited_props,
+                                              db, local_abspath,
+                                              SVN_PROP_INHERITABLE_IGNORES,
+                                              scratch_pool, scratch_pool));
       for (i = 0; i < inherited_props->nelts; i++)
         {
           apr_hash_index_t *hi;

Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/translate.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/translate.c?rev=1415773&r1=1415772&r2=1415773&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/translate.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/translate.c Fri Nov 30 18:12:52 2012
@@ -409,8 +409,8 @@ svn_wc__sync_flags_with_props(svn_boolea
          set the file read_only just yet.  That happens upon commit. */
       apr_hash_t *pristine_props;
 
-      SVN_ERR(svn_wc__get_pristine_props(&pristine_props, db, local_abspath,
-                                         scratch_pool, scratch_pool));
+      SVN_ERR(svn_wc__db_read_pristine_props(&pristine_props, db, local_abspath,
+                                             scratch_pool, scratch_pool));
 
       if (pristine_props
             && apr_hash_get(pristine_props,