You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2010/11/07 15:30:36 UTC

svn commit: r1032285 [3/4] - in /subversion/branches/performance: ./ build/ build/ac-macros/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bindings/javahl/src/org/apache/subversion/javahl/cal...

Modified: subversion/branches/performance/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_wc/wc_db.c?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/performance/subversion/libsvn_wc/wc_db.c Sun Nov  7 14:30:34 2010
@@ -710,6 +710,84 @@ blank_ibb(insert_base_baton_t *pibb)
 }
 
 
+/* Extend any delete of the parent of LOCAL_RELPATH to LOCAL_RELPATH.
+
+   Given a wc:
+
+              0         1         2         3         4
+              normal
+   A          normal          
+   A/B        normal              normal
+   A/B/C                          not-pres  normal
+   A/B/C/D                                            normal
+
+   That is checkout, delete A/B, copy a replacement A/B, delete copied
+   child A/B/C, add replacement A/B/C, add A/B/C/D.
+
+   Now an update that adds base nodes for A/B/C, A/B/C/D and A/B/C/D/E
+   must extend the A/B deletion:
+   
+              0         1         2         3         4
+              normal
+   A          normal
+   A/B        normal              normal
+   A/B/C      normal              not-pres  normal
+   A/B/C/D    normal              base-del            normal
+   A/B/C/D/E  normal              base-del
+
+   When adding a base node if the parent has a working node then the
+   parent base is deleted and this must be extended to cover new base
+   node.
+
+   In the example above A/B/C/D and A/B/C/D/E are the nodes that get
+   the extended delete, A/B/C is already deleted.
+ */
+static svn_error_t *
+extend_parent_delete(svn_sqlite__db_t *sdb,
+                     apr_int64_t wc_id,
+                     const char *local_relpath,
+                     apr_pool_t *scratch_pool)
+{
+  svn_boolean_t have_row;
+  svn_sqlite__stmt_t *stmt;
+  apr_int64_t parent_op_depth;
+  const char *parent_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
+
+  SVN_ERR_ASSERT(local_relpath[0]);
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                                    STMT_SELECT_LOWEST_WORKING_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, parent_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  if (have_row)
+    parent_op_depth = svn_sqlite__column_int64(stmt, 0);
+  SVN_ERR(svn_sqlite__reset(stmt));
+  if (have_row)
+    {
+      apr_int64_t op_depth;
+
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+      if (have_row)
+        op_depth = svn_sqlite__column_int64(stmt, 0);
+      SVN_ERR(svn_sqlite__reset(stmt));
+      if (!have_row || parent_op_depth < op_depth)
+        {
+          SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                                          STMT_INSERT_WORKING_NODE_FROM_BASE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "isit", wc_id,
+                                    local_relpath, parent_op_depth,
+                                    presence_map,
+                                    svn_wc__db_status_base_deleted));
+          SVN_ERR(svn_sqlite__update(NULL, stmt));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
+
 /* */
 static svn_error_t *
 insert_base_node(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
@@ -773,6 +851,10 @@ insert_base_node(void *baton, svn_sqlite
                                        0 /* BASE */,
                                        scratch_pool));
 
+  if (parent_relpath)
+    SVN_ERR(extend_parent_delete(sdb, pibb->wc_id, pibb->local_relpath,
+                                 scratch_pool));
+
   SVN_ERR(add_work_items(sdb, pibb->work_items, scratch_pool));
 
   return SVN_NO_ERROR;
@@ -791,49 +873,6 @@ blank_iwb(insert_working_baton_t *piwb)
 }
 
 
-/* Copy the row specified by BATON->(wc_id,local_relpath) from BASE to
- * WORKING, changing its 'presence' and 'op_depth' to the values in BATON. */
-static svn_error_t *
-copy_working_from_base(void *baton,
-                       svn_sqlite__db_t *sdb,
-                       apr_pool_t *scratch_pool)
-{
-  const insert_working_baton_t *piwb = baton;
-  svn_sqlite__stmt_t *stmt;
-#ifdef SVN_WC__OP_DEPTH
-  const char *like_arg;
-#endif
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                         STMT_INSERT_WORKING_NODE_FROM_BASE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isit", piwb->wc_id,
-                            piwb->local_relpath,
-                            piwb->op_depth,
-                            presence_map, piwb->presence));
-  SVN_ERR(svn_sqlite__insert(NULL, stmt));
-
-#ifdef SVN_WC__OP_DEPTH
-  /* Need to update the op_depth of all deleted child trees -- this
-     relies on the recursion having already deleted the trees so
-     that they are all at op_depth+1.
-
-     ### Rewriting the op_depth means that the number of queries is
-     ### O(depth^2).  Fix it by implementing svn_wc__db_op_delete so
-     ### that the recursion gets moved from adm_ops.c to wc_db.c and
-     ### one transaction does the whole tree and thus each op_depth
-     ### only gets written once. */
-  like_arg = construct_like_arg(piwb->local_relpath, scratch_pool);
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                    STMT_UPDATE_OP_DEPTH_RECURSIVE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isi",
-                            piwb->wc_id, like_arg, piwb->op_depth));
-  SVN_ERR(svn_sqlite__update(NULL, stmt));
-#endif
-
-  return SVN_NO_ERROR;
-}
-
-
 /* Insert a row in NODES for each (const char *) child name in CHILDREN,
    whose parent directory is LOCAL_RELPATH, at op_depth=OP_DEPTH.  Set each
    child's presence to 'incomplete', kind to 'unknown', repos_id to REPOS_ID,
@@ -1814,40 +1853,31 @@ svn_wc__db_base_remove(svn_wc__db_t *db,
 }
 
 
-svn_error_t *
-svn_wc__db_base_get_info(svn_wc__db_status_t *status,
-                         svn_wc__db_kind_t *kind,
-                         svn_revnum_t *revision,
-                         const char **repos_relpath,
-                         const char **repos_root_url,
-                         const char **repos_uuid,
-                         svn_revnum_t *changed_rev,
-                         apr_time_t *changed_date,
-                         const char **changed_author,
-                         apr_time_t *last_mod_time,
-                         svn_depth_t *depth,
-                         const svn_checksum_t **checksum,
-                         svn_filesize_t *translated_size,
-                         const char **target,
-                         svn_wc__db_lock_t **lock,
-                         svn_wc__db_t *db,
-                         const char *local_abspath,
-                         apr_pool_t *result_pool,
-                         apr_pool_t *scratch_pool)
+static svn_error_t *
+base_get_info(svn_wc__db_status_t *status,
+              svn_wc__db_kind_t *kind,
+              svn_revnum_t *revision,
+              const char **repos_relpath,
+              const char **repos_root_url,
+              const char **repos_uuid,
+              svn_revnum_t *changed_rev,
+              apr_time_t *changed_date,
+              const char **changed_author,
+              apr_time_t *last_mod_time,
+              svn_depth_t *depth,
+              const svn_checksum_t **checksum,
+              svn_filesize_t *translated_size,
+              const char **target,
+              svn_wc__db_lock_t **lock,
+              svn_wc__db_pdh_t *pdh,
+              const char *local_relpath,
+              apr_pool_t *result_pool,
+              apr_pool_t *scratch_pool)
 {
-  svn_wc__db_pdh_t *pdh;
-  const char *local_relpath;
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
   svn_error_t *err = SVN_NO_ERROR;
 
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-
-  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
-                              local_abspath, svn_sqlite__mode_readonly,
-                              scratch_pool, scratch_pool));
-  VERIFY_USABLE_PDH(pdh);
-
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
                                     lock ? STMT_SELECT_BASE_NODE_WITH_LOCK
                                          : STMT_SELECT_BASE_NODE));
@@ -1924,7 +1954,8 @@ svn_wc__db_base_get_info(svn_wc__db_stat
                 err = svn_error_createf(
                         err->apr_err, err,
                         _("The node '%s' has a corrupt checksum value."),
-                        svn_dirent_local_style(local_abspath, scratch_pool));
+                        path_for_error_message(pdh->wcroot, local_relpath,
+                                               scratch_pool));
             }
         }
       if (translated_size)
@@ -1943,7 +1974,7 @@ svn_wc__db_base_get_info(svn_wc__db_stat
     {
       err = svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
                               _("The node '%s' was not found."),
-                              svn_dirent_local_style(local_abspath,
+                              path_for_error_message(pdh->wcroot, local_relpath,
                                                      scratch_pool));
     }
 
@@ -1953,6 +1984,45 @@ svn_wc__db_base_get_info(svn_wc__db_stat
 
 
 svn_error_t *
+svn_wc__db_base_get_info(svn_wc__db_status_t *status,
+                         svn_wc__db_kind_t *kind,
+                         svn_revnum_t *revision,
+                         const char **repos_relpath,
+                         const char **repos_root_url,
+                         const char **repos_uuid,
+                         svn_revnum_t *changed_rev,
+                         apr_time_t *changed_date,
+                         const char **changed_author,
+                         apr_time_t *last_mod_time,
+                         svn_depth_t *depth,
+                         const svn_checksum_t **checksum,
+                         svn_filesize_t *translated_size,
+                         const char **target,
+                         svn_wc__db_lock_t **lock,
+                         svn_wc__db_t *db,
+                         const char *local_abspath,
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool)
+{
+  svn_wc__db_pdh_t *pdh;
+  const char *local_relpath;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+                              local_abspath, svn_sqlite__mode_readonly,
+                              scratch_pool, scratch_pool));
+  VERIFY_USABLE_PDH(pdh);
+
+  SVN_ERR(base_get_info(status, kind, revision, repos_relpath, repos_root_url,
+                        repos_uuid, changed_rev, changed_date, changed_author,
+                        last_mod_time, depth, checksum, translated_size,
+                        target, lock,
+                        pdh, local_relpath, result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_wc__db_base_get_prop(const svn_string_t **propval,
                          svn_wc__db_t *db,
                          const char *local_abspath,
@@ -3174,8 +3244,8 @@ copy_actual_rows(svn_wc__db_pdh_t *src_p
                             src_pdh->wcroot->wc_id, src_relpath,
                             construct_like_arg(src_relpath, scratch_pool),
                             dst_relpath, dst_parent_relpath,
-                            strlen(src_relpath) + 1,
-                            strlen(src_parent_relpath) + 1));
+                            (apr_int64_t)(strlen(src_relpath) + 1),
+                            (apr_int64_t)(strlen(src_parent_relpath) + 1)));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
   return SVN_NO_ERROR;
@@ -4425,7 +4495,7 @@ svn_wc__db_temp_op_remove_working(svn_wc
   SVN_ERR(flush_entries(db, pdh, local_abspath, scratch_pool));
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
-                                    STMT_DELETE_WORKING_NODES));
+                                    STMT_DELETE_WORKING_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
@@ -4526,57 +4596,67 @@ delete_not_present_children(svn_wc__db_p
 /* Update the working node for LOCAL_ABSPATH setting presence=STATUS */
 static svn_error_t *
 db_working_update_presence(svn_wc__db_status_t status,
-                           svn_wc__db_t *db,
-                           const char *local_abspath,
+                           svn_wc__db_pdh_t *pdh,
+                           const char *local_relpath,
                            apr_pool_t *scratch_pool)
 {
-  svn_wc__db_pdh_t *pdh;
-  const char *local_relpath;
   svn_sqlite__stmt_t *stmt;
 
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
-                              local_abspath, svn_sqlite__mode_readwrite,
-                              scratch_pool, scratch_pool));
-  VERIFY_USABLE_PDH(pdh);
-
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
                                     STMT_UPDATE_NODE_WORKING_PRESENCE));
   SVN_ERR(svn_sqlite__bindf(stmt, "ist", pdh->wcroot->wc_id, local_relpath,
                             presence_map, status));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
-  /* Switching to base-deleted is undoing an add/copy.  If this was a
-     copy then any children of the copy will now be not-present and
-     should be removed.  By this stage an add will have no children. */
   if (status == svn_wc__db_status_base_deleted)
-    SVN_ERR(delete_not_present_children(pdh, local_relpath, scratch_pool));
+    {
+      /* Switching to base-deleted is undoing an add/copy.  If this
+         was a copy then any children of the copy will now be
+         not-present and should be removed.  By this stage an add will
+         have no children. */
+      SVN_ERR(delete_not_present_children(pdh, local_relpath, scratch_pool));
+
+      /* Reset the copyfrom in case this was a copy.
+         ### What else should be reset? Properties? Or copy the node again? */
+      SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                        STMT_UPDATE_COPYFROM_TO_INHERIT));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+    }
+
+  /* ### Should the switch to not-present remove an ACTUAL row? */
 
   return SVN_NO_ERROR;
 }
 
 
 /* Delete working and actual nodes for LOCAL_ABSPATH.  When called any
-   remain working child sub-trees should be presence=not-present and will
-   be deleted. */
+   remaining working child sub-trees should be presence=not-present
+   and will be deleted. */
 static svn_error_t *
-db_working_actual_remove(svn_wc__db_t *db,
-                         const char *local_abspath,
+db_working_actual_remove(svn_wc__db_pdh_t *pdh,
+                         const char *local_relpath,
                          apr_pool_t *scratch_pool)
 {
-  svn_wc__db_pdh_t *pdh;
-  const char *local_relpath;
   svn_sqlite__stmt_t *stmt;
+  apr_int64_t op_depth;
 
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
-                              local_abspath, svn_sqlite__mode_readwrite,
-                              scratch_pool, scratch_pool));
+  /* Precondition: There is a working row in NODES.
+   * Record its op_depth, which is needed for postcondition checking. */
+  {
+    svn_boolean_t have_row;
 
-  VERIFY_USABLE_PDH(pdh);
+    SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                      STMT_SELECT_WORKING_NODE));
+    SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+    SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    SVN_ERR_ASSERT(have_row);
+    op_depth = svn_sqlite__column_int64(stmt, 0);
+    SVN_ERR(svn_sqlite__reset(stmt));
+  }
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
-                                    STMT_DELETE_WORKING_NODES));
+                                    STMT_DELETE_WORKING_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
@@ -4587,7 +4667,32 @@ db_working_actual_remove(svn_wc__db_t *d
 
   SVN_ERR(delete_not_present_children(pdh, local_relpath, scratch_pool));
 
-  SVN_ERR(flush_entries(db, pdh, local_abspath, scratch_pool));
+  /* Postcondition: There are no NODES rows in this subtree, at same or
+   * greater op_depth. */
+  {
+    svn_boolean_t have_row;
+
+    SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                      STMT_SELECT_NODES_GE_OP_DEPTH_RECURSIVE));
+    SVN_ERR(svn_sqlite__bindf(stmt, "issi", pdh->wcroot->wc_id, local_relpath,
+                              construct_like_arg(local_relpath, scratch_pool),
+                              op_depth));
+    SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    SVN_ERR_ASSERT(! have_row);
+    SVN_ERR(svn_sqlite__reset(stmt));
+  }
+  /* Postcondition: There are no ACTUAL_NODE rows in this subtree. */
+  {
+    svn_boolean_t have_row;
+
+    SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                      STMT_SELECT_ACTUAL_NODE_RECURSIVE));
+    SVN_ERR(svn_sqlite__bindf(stmt, "iss", pdh->wcroot->wc_id, local_relpath,
+                              construct_like_arg(local_relpath, scratch_pool)));
+    SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    SVN_ERR_ASSERT(! have_row);
+    SVN_ERR(svn_sqlite__reset(stmt));
+  }
 
   return SVN_NO_ERROR;
 }
@@ -4598,38 +4703,40 @@ db_working_actual_remove(svn_wc__db_t *d
 /* Insert a working node for LOCAL_ABSPATH with presence=STATUS. */
 static svn_error_t *
 db_working_insert(svn_wc__db_status_t status,
-                  svn_wc__db_t *db,
-                  const char *local_abspath,
+                  svn_wc__db_pdh_t *pdh,
+                  const char *local_relpath,
                   apr_pool_t *scratch_pool)
 {
-  svn_wc__db_pdh_t *pdh;
-  const char *local_relpath;
-  insert_working_baton_t iwb;
-
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
-                              local_abspath, svn_sqlite__mode_readwrite,
-                              scratch_pool, scratch_pool));
-  VERIFY_USABLE_PDH(pdh);
-
-  /* Update WORKING_NODE and NODE_DATA transactionally */
-  blank_iwb(&iwb);
-
-  iwb.wc_id = pdh->wcroot->wc_id;
-  iwb.local_relpath = local_relpath;
-  iwb.presence = status;
+  svn_sqlite__stmt_t *stmt;
 #ifdef SVN_WC__OP_DEPTH
-  iwb.op_depth = relpath_depth(local_relpath);
+  const char *like_arg = construct_like_arg(local_relpath, scratch_pool);
+  apr_int64_t op_depth = relpath_depth(local_relpath);
 #else
-  iwb.op_depth = 2; /* ### temporary op_depth */
+  apr_int64_t op_depth = 2; /* ### temporary op_depth */
 #endif
 
-  SVN_ERR(svn_sqlite__with_transaction(pdh->wcroot->sdb,
-                                       copy_working_from_base, &iwb,
-                                       scratch_pool));
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_INSERT_WORKING_NODE_FROM_BASE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isit", pdh->wcroot->wc_id,
+                            local_relpath, op_depth, presence_map, status));
+  SVN_ERR(svn_sqlite__insert(NULL, stmt));
 
+#ifdef SVN_WC__OP_DEPTH
+  /* Need to update the op_depth of all deleted child trees -- this
+     relies on the recursion having already deleted the trees so
+     that they are all at op_depth+1.
 
-  SVN_ERR(flush_entries(db, pdh, local_abspath, scratch_pool));
+     ### Rewriting the op_depth means that the number of queries is
+     ### O(depth^2).  Fix it by implementing svn_wc__db_op_delete so
+     ### that the recursion gets moved from adm_ops.c to wc_db.c and
+     ### one transaction does the whole tree and thus each op_depth
+     ### only gets written once. */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_UPDATE_OP_DEPTH_RECURSIVE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isi",
+                            pdh->wcroot->wc_id, like_arg, op_depth));
+  SVN_ERR(svn_sqlite__update(NULL, stmt));
+#endif
 
   return SVN_NO_ERROR;
 }
@@ -4707,138 +4814,224 @@ is_add_or_root_of_copy(svn_boolean_t *ad
   return SVN_NO_ERROR;
 }
 
-
-/* Delete LOCAL_ABSPATH.  Implements the delete transition from
-   notes/wc-ng/transitions. */
-svn_error_t *
-svn_wc__db_temp_op_delete(svn_wc__db_t *db,
-                          const char *local_abspath,
-                          apr_pool_t *scratch_pool)
+/* Convert STATUS, the raw status obtained from the presence map, to
+   the status appropriate for a working (op_depth > 0) node and return
+   it in *WORKING_STATUS. */
+static svn_error_t *
+convert_to_working_status(svn_wc__db_status_t *working_status,
+                          svn_wc__db_status_t status)
 {
-  svn_wc__db_pdh_t *pdh;
-  const char *local_relpath;
-  svn_wc__db_status_t base_status, working_status, new_working_status;
-  svn_boolean_t have_base, have_work, new_have_work;
+  svn_wc__db_status_t work_status = status;
 
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+  SVN_ERR_ASSERT(work_status == svn_wc__db_status_normal
+                 || work_status == svn_wc__db_status_not_present
+                 || work_status == svn_wc__db_status_base_deleted
+                 || work_status == svn_wc__db_status_incomplete
+                 || work_status == svn_wc__db_status_excluded);
 
-  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
-                              local_abspath, svn_sqlite__mode_readonly,
-                              scratch_pool, scratch_pool));
-  VERIFY_USABLE_PDH(pdh);
+  if (work_status == svn_wc__db_status_incomplete)
+    {
+      *working_status = svn_wc__db_status_incomplete;
+    }
+  else if (work_status == svn_wc__db_status_excluded)
+    {
+      *working_status = svn_wc__db_status_excluded;
+    }
+  else if (work_status == svn_wc__db_status_not_present
+           || work_status == svn_wc__db_status_base_deleted)
+    {
+      /* The caller should scan upwards to detect whether this
+         deletion has occurred because this node has been moved
+         away, or it is a regular deletion. Also note that the
+         deletion could be of the BASE tree, or a child of
+         something that has been copied/moved here. */
 
-  SVN_ERR(read_info(&working_status, NULL, NULL, NULL, NULL, NULL,
-                    NULL, NULL, NULL, NULL, NULL, NULL,
-                    NULL, NULL, NULL, NULL, NULL, NULL,
-                    NULL, NULL, &have_base, &have_work, NULL, NULL,
-                    pdh, local_relpath,
-                    scratch_pool, scratch_pool));
-  if (working_status == svn_wc__db_status_deleted)
+      *working_status = svn_wc__db_status_deleted;
+    }
+  else /* normal */
     {
-      /* The node is already deleted.  */
-      /* ### return an error? callers should know better.  */
-      return SVN_NO_ERROR;
+      /* The caller should scan upwards to detect whether this
+         addition has occurred because of a simple addition,
+         a copy, or is the destination of a move. */
+      *working_status = svn_wc__db_status_added;
     }
 
-  if (have_base)
-    SVN_ERR(svn_wc__db_base_get_info(&base_status,
-                                     NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                                     NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                                     db, local_abspath,
-                                     scratch_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
 
-  if (have_base && (base_status == svn_wc__db_status_absent
-                    || base_status == svn_wc__db_status_excluded))
-    return SVN_NO_ERROR; /* ### should return an error.... WHICH ONE? */
+/* Return the status of the node, if any, below the "working" node.
+   Set *HAVE_BASE or *HAVE_WORK to indicate if a base node or lower
+   working node is present, and *STATUS to the status of the node.
 
-  new_have_work = have_work;
-  new_working_status = working_status;
+   This is an experimental interface.  It appears that delete only
+   needs to know whether the below node is base or not (if it is a
+   base the status is available via base_get_info).  It's possible
+   this function should be removed and read_info modified to return
+   the "lower is base".  I'll leave it for now because delete may turn
+   out to need more info. */
+static svn_error_t *
+info_below_working(svn_boolean_t *have_base,
+                   svn_boolean_t *have_work,
+                   svn_wc__db_status_t *status,
+                   svn_wc__db_pdh_t *pdh,
+                   const char *local_relpath,
+                   apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
 
-  if (working_status == svn_wc__db_status_normal
-      || working_status == svn_wc__db_status_not_present)
-    {
-      /* No structural changes (ie. no WORKING node). Mark the BASE node
-         as deleted.  */
+  *have_base = *have_work =  FALSE;
 
-      SVN_ERR_ASSERT(!have_work);
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_SELECT_NODE_INFO));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                            pdh->wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  if (have_row)
+    {
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+      if (have_row)
+        {
+          apr_int64_t op_depth = svn_sqlite__column_int64(stmt, 0);
 
-      new_have_work = TRUE;
-      new_working_status = svn_wc__db_status_base_deleted;
+          if (op_depth > 0)
+            *have_work = TRUE;
+          else
+            *have_base = TRUE;
+              
+          *status = svn_sqlite__column_token(stmt, 3, presence_map);
+          if (op_depth > 0)
+            SVN_ERR(convert_to_working_status(status, *status));
+        }
     }
-  /* ### remaining states: added, absent, excluded, incomplete
-     ### the last three have debatable schedule-delete semantics,
-     ### and this code may need to change further, but I'm not
-     ### going to worry about it now
-  */
-  else if (!have_work)
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  return SVN_NO_ERROR;
+}
+
+struct temp_op_delete_baton {
+  svn_wc__db_pdh_t *pdh;
+  const char *local_relpath;
+
+  /* The following two are only needed for svn_wc__db_temp_forget_directory */
+  svn_wc__db_t *db;
+  const char *local_abspath;
+};
+
+/* Deletes BATON->LOCAL_RELPATH using BATON->PDH. */
+static svn_error_t *
+temp_op_delete_txn(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
+{
+  struct temp_op_delete_baton *b = baton;
+  svn_wc__db_status_t status, new_working_status;
+  svn_boolean_t have_work, new_have_work;
+
+  SVN_ERR(read_info(&status,
+                    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                    &have_work,
+                    NULL, NULL,
+                    b->pdh, b->local_relpath,
+                    scratch_pool, scratch_pool));
+
+  new_have_work = have_work;
+  new_working_status = status;
+
+  if (!have_work)
     {
       /* No structural changes  */
-      if (base_status == svn_wc__db_status_normal
-          || base_status == svn_wc__db_status_incomplete
-          || base_status == svn_wc__db_status_excluded)
+      if (status == svn_wc__db_status_normal
+          || status == svn_wc__db_status_incomplete)
         {
           new_have_work = TRUE;
           new_working_status = svn_wc__db_status_base_deleted;
         }
     }
-    /* ### BH: have_base is not a safe check, because a node can
-       ### still be a child of an added node even though it replaces
-       ### a base node. */
-  else if (working_status == svn_wc__db_status_added
-           && (!have_base || base_status == svn_wc__db_status_not_present))
+  else if (status == svn_wc__db_status_added)
     {
-      /* ADD/COPY-HERE/MOVE-HERE. There is "no BASE node".  */
-
+      /* ADD/COPY-HERE/MOVE-HERE */
       svn_boolean_t add_or_root_of_copy;
 
       SVN_ERR(is_add_or_root_of_copy(&add_or_root_of_copy,
-                                     pdh, local_relpath, scratch_pool));
-      if (add_or_root_of_copy)
-        new_have_work = FALSE;
-      else
-        new_working_status = svn_wc__db_status_not_present;
-    }
-  else if (working_status == svn_wc__db_status_added)
-    {
-      /* DELETE + ADD  */
-      svn_boolean_t add_or_root_of_copy;
-      SVN_ERR(is_add_or_root_of_copy(&add_or_root_of_copy,
-                                     pdh, local_relpath, scratch_pool));
+                                     b->pdh, b->local_relpath, scratch_pool));
       if (add_or_root_of_copy)
-        new_working_status = svn_wc__db_status_base_deleted;
+        {
+          svn_boolean_t below_base, below_work;
+          svn_wc__db_status_t below_status;
+
+          SVN_ERR(info_below_working(&below_base, &below_work, &below_status,
+                                     b->pdh, b->local_relpath, scratch_pool));
+
+          if (below_base && below_status != svn_wc__db_status_not_present)
+            new_working_status = svn_wc__db_status_base_deleted;
+          else
+            new_have_work = FALSE;
+        }
       else
         new_working_status = svn_wc__db_status_not_present;
     }
-  else if (working_status == svn_wc__db_status_incomplete)
+  else if (status == svn_wc__db_status_incomplete)
     {
       svn_boolean_t add_or_root_of_copy;
       SVN_ERR(is_add_or_root_of_copy(&add_or_root_of_copy,
-                                     pdh, local_relpath, scratch_pool));
+                                     b->pdh, b->local_relpath, scratch_pool));
       if (add_or_root_of_copy)
         new_have_work = FALSE;
     }
 
   if (!new_have_work && have_work)
     {
-      SVN_ERR(db_working_actual_remove(db, local_abspath, scratch_pool));
-      /* ### Search the cached directories in db for directories below
-             local_abspath and close their handles to allow deleting
-             them from the working copy */
-      SVN_ERR(svn_wc__db_temp_forget_directory(db, local_abspath,
+      SVN_ERR(db_working_actual_remove(b->pdh, b->local_relpath, scratch_pool));
+
+      /* This is needed for access batons? */
+      SVN_ERR(svn_wc__db_temp_forget_directory(b->db, b->local_abspath,
                                                scratch_pool));
     }
   else if (new_have_work && !have_work)
-    SVN_ERR(db_working_insert(new_working_status,
-                              db, local_abspath, scratch_pool));
+    {
+      SVN_ERR(db_working_insert(new_working_status, b->pdh, b->local_relpath,
+                                scratch_pool));
+    }
   else if (new_have_work && have_work
-           && new_working_status != working_status)
-    SVN_ERR(db_working_update_presence(new_working_status,
-                                       db, local_abspath, scratch_pool));
-  /* ### else nothing to do, return an error? */
+           && new_working_status != status)
+    {
+      SVN_ERR(db_working_update_presence(new_working_status, b->pdh,
+                                         b->local_relpath, scratch_pool));
+    }
+  else
+    {
+      /* Already deleted, or absent or excluded. */
+      /* ### Nothing to do, return an error?  Which one? */
+    }
 
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_wc__db_temp_op_delete(svn_wc__db_t *db,
+                          const char *local_abspath,
+                          apr_pool_t *scratch_pool)
+{
+  struct temp_op_delete_baton b;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&b.pdh, &b.local_relpath, db,
+                              local_abspath, svn_sqlite__mode_readwrite,
+                              scratch_pool, scratch_pool));
+  VERIFY_USABLE_PDH(b.pdh);
+
+  /* These two for svn_wc__db_temp_forget_directory */
+  b.db = db; 
+  b.local_abspath = local_abspath;
+
+  SVN_ERR(svn_sqlite__with_transaction(b.pdh->wcroot->sdb, temp_op_delete_txn,
+                                       &b, scratch_pool));
+
+  SVN_ERR(flush_entries(db, b.pdh, local_abspath, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
 
 /* Like svn_wc__db_read_info(), but with PDH+LOCAL_RELPATH instead of
  * DB+LOCAL_ABSPATH.*/
@@ -4914,43 +5107,7 @@ read_info(svn_wc__db_status_t *status,
           *status = svn_sqlite__column_token(stmt_info, 3, presence_map);
 
           if (op_depth != 0) /* WORKING */
-            {
-              svn_wc__db_status_t work_status;
-
-              work_status = *status;
-              SVN_ERR_ASSERT(work_status == svn_wc__db_status_normal
-                             || work_status == svn_wc__db_status_not_present
-                             || work_status == svn_wc__db_status_base_deleted
-                             || work_status == svn_wc__db_status_incomplete
-                             || work_status == svn_wc__db_status_excluded);
-
-              if (work_status == svn_wc__db_status_incomplete)
-                {
-                  *status = svn_wc__db_status_incomplete;
-                }
-              else if (work_status == svn_wc__db_status_excluded)
-                {
-                  *status = svn_wc__db_status_excluded;
-                }
-              else if (work_status == svn_wc__db_status_not_present
-                       || work_status == svn_wc__db_status_base_deleted)
-                {
-                  /* The caller should scan upwards to detect whether this
-                     deletion has occurred because this node has been moved
-                     away, or it is a regular deletion. Also note that the
-                     deletion could be of the BASE tree, or a child of
-                     something that has been copied/moved here. */
-
-                  *status = svn_wc__db_status_deleted;
-                }
-              else /* normal */
-                {
-                  /* The caller should scan upwards to detect whether this
-                     addition has occurred because of a simple addition,
-                     a copy, or is the destination of a move. */
-                  *status = svn_wc__db_status_added;
-                }
-            }
+            SVN_ERR(convert_to_working_status(status, *status));
         }
       if (kind)
         {
@@ -5286,13 +5443,7 @@ svn_wc__db_read_children_info(apr_hash_t
 
           child->status = svn_sqlite__column_token(stmt, 3, presence_map);
           if (*op_depth != 0)
-            {
-              if (child->status == svn_wc__db_status_not_present
-                  || child->status == svn_wc__db_status_base_deleted)
-                child->status = svn_wc__db_status_deleted;
-              else if (child->status == svn_wc__db_status_normal)
-                child->status = svn_wc__db_status_added;
-            }
+            SVN_ERR(convert_to_working_status(&child->status, child->status));
 
           if (*op_depth != 0)
             child->revnum = SVN_INVALID_REVNUM;
@@ -5992,8 +6143,10 @@ commit_node(void *baton, svn_sqlite__db_
 
   if (have_work)
     {
+      /* This removes all op_depth > 0 and so does both layers of a
+         two-layer replace. */
       SVN_ERR(svn_sqlite__get_statement(&stmt, cb->pdh->wcroot->sdb,
-                                        STMT_DELETE_WORKING_NODES));
+                                        STMT_DELETE_ALL_WORKING_NODES));
       SVN_ERR(svn_sqlite__bindf(stmt, "is",
                                 cb->pdh->wcroot->wc_id, cb->local_relpath));
       SVN_ERR(svn_sqlite__step_done(stmt));
@@ -7934,24 +8087,46 @@ svn_wc__db_read_kind(svn_wc__db_kind_t *
                      svn_boolean_t allow_missing,
                      apr_pool_t *scratch_pool)
 {
-  svn_error_t *err;
+  svn_wc__db_pdh_t *pdh;
+  const char *local_relpath;
+  svn_sqlite__stmt_t *stmt_info;
+  svn_boolean_t have_info;
 
-  err = svn_wc__db_read_info(NULL, kind, 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 (!err)
-    return SVN_NO_ERROR;
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
-  if (allow_missing && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+                              local_abspath, svn_sqlite__mode_readonly,
+                              scratch_pool, scratch_pool));
+  VERIFY_USABLE_PDH(pdh);
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt_info, pdh->wcroot->sdb,
+                                    STMT_SELECT_NODE_INFO));
+  SVN_ERR(svn_sqlite__bindf(stmt_info, "is",
+                            pdh->wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&have_info, stmt_info));
+
+  if (!have_info)
     {
-      svn_error_clear(err);
-      *kind = svn_wc__db_kind_unknown;
-      return SVN_NO_ERROR;
+      if (allow_missing)
+        {
+          *kind = svn_wc__db_kind_unknown;
+          SVN_ERR(svn_sqlite__reset(stmt_info));
+          return SVN_NO_ERROR;
+        }
+      else
+        {
+          SVN_ERR(svn_sqlite__reset(stmt_info));
+          return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                                   _("The node '%s' was not found."),
+                                   path_for_error_message(pdh->wcroot,
+                                                          local_relpath,
+                                                          scratch_pool));
+        }
     }
 
-  return svn_error_return(err);
+  *kind = svn_sqlite__column_token(stmt_info, 4, kind_map);
+
+  return svn_error_return(svn_sqlite__reset(stmt_info));
 }
 
 
@@ -7998,10 +8173,10 @@ svn_wc__db_node_hidden(svn_boolean_t *hi
   SVN_ERR(svn_sqlite__reset(stmt));
 
   /* Now check the BASE node's status.  */
-  SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, NULL, NULL, NULL,
-                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                                   NULL, NULL, NULL, db, local_abspath,
-                                   scratch_pool, scratch_pool));
+  SVN_ERR(base_get_info(&base_status,
+                        NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                        NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                        pdh, local_relpath, scratch_pool, scratch_pool));
 
   *hidden = (base_status == svn_wc__db_status_absent
              || base_status == svn_wc__db_status_not_present
@@ -8564,11 +8739,11 @@ start_directory_update_txn(void *baton,
                &stmt, db,
                STMT_UPDATE_BASE_NODE_PRESENCE_REVNUM_AND_REPOS_PATH));
 
-  SVN_ERR(svn_sqlite__bindf(stmt, "istis",
+  SVN_ERR(svn_sqlite__bindf(stmt, "istrs",
                             du->wc_id,
                             du->local_relpath,
                             presence_map, svn_wc__db_status_incomplete,
-                            (apr_int64_t)du->new_rev,
+                            du->new_rev,
                             du->new_repos_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
@@ -8736,7 +8911,7 @@ make_copy_txn(void *baton,
   if (remove_working)
     {
       SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                        STMT_DELETE_WORKING_NODES));
+                                        STMT_DELETE_WORKING_NODE));
       SVN_ERR(svn_sqlite__bindf(stmt, "is",
                                 mcb->pdh->wcroot->wc_id,
                                 mcb->local_relpath));
@@ -9273,9 +9448,9 @@ set_rev_relpath_txn(void *baton,
       SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
                                         STMT_UPDATE_BASE_REVISION));
 
-      SVN_ERR(svn_sqlite__bindf(stmt, "isi", rrb->pdh->wcroot->wc_id,
+      SVN_ERR(svn_sqlite__bindf(stmt, "isr", rrb->pdh->wcroot->wc_id,
                                              rrb->local_relpath,
-                                             (apr_int64_t)rrb->rev));
+                                             rrb->rev));
 
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
@@ -9364,14 +9539,6 @@ set_new_dir_to_incomplete_txn(void *bato
   SVN_ERR(create_repos_id(&repos_id, dtb->repos_root_url, dtb->repos_uuid,
                           sdb, scratch_pool));
 
-  /* Delete the base and working node data */
-  SVN_ERR(svn_sqlite__get_statement(&stmt, dtb->pdh->wcroot->sdb,
-                                    STMT_DELETE_NODES));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", dtb->pdh->wcroot->wc_id,
-                            dtb->local_relpath));
-  SVN_ERR(svn_sqlite__step_done(stmt));
-
-  /* Insert the incomplete base node */
   SVN_ERR(svn_sqlite__get_statement(&stmt, dtb->pdh->wcroot->sdb,
                                     STMT_INSERT_NODE));
 
@@ -9393,6 +9560,10 @@ set_new_dir_to_incomplete_txn(void *bato
 
   SVN_ERR(svn_sqlite__step_done(stmt));
 
+  if (parent_relpath)
+    SVN_ERR(extend_parent_delete(dtb->pdh->wcroot->sdb, dtb->pdh->wcroot->wc_id,
+                                 dtb->local_relpath, scratch_pool));
+
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/performance/subversion/mod_authz_svn/INSTALL
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/mod_authz_svn/INSTALL?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/mod_authz_svn/INSTALL (original)
+++ subversion/branches/performance/subversion/mod_authz_svn/INSTALL Sun Nov  7 14:30:34 2010
@@ -79,6 +79,26 @@ II.   Configuration
          though AuthzSVNAnonymous was set to 'No'.  The AuthzSVNAnonymous
          directive prevents the anonymous access check from being run.
 
+      D. Example 4: Per-repository access file
+
+         This configuration allows to use SVNParentPath but have
+         different authz files per repository.
+
+         <Location /svn>
+           DAV svn
+           SVNParentPath /path/to/reposparent
+
+           AuthType Basic
+           AuthName "Subversion repository"
+           AuthUserFile /path/to/htpasswd/file
+
+           AuthzSVNReposRelativeAccessFile filename
+
+           Require valid-user
+         </Location>
+
+         NOTE: AuthzSVNReposRelativeAccessFile filename causes the authz file
+         to be read from <repo path>/conf/<filename>
 
    2. Specifying permissions
 

Modified: subversion/branches/performance/subversion/mod_authz_svn/mod_authz_svn.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/mod_authz_svn/mod_authz_svn.c?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/mod_authz_svn/mod_authz_svn.c (original)
+++ subversion/branches/performance/subversion/mod_authz_svn/mod_authz_svn.c Sun Nov  7 14:30:34 2010
@@ -52,6 +52,7 @@ typedef struct {
   int no_auth_when_anon_ok;
   const char *base_path;
   const char *access_file;
+  const char *repo_relative_access_file;
   const char *force_username_case;
 } authz_svn_config_rec;
 
@@ -76,6 +77,37 @@ create_authz_svn_dir_config(apr_pool_t *
   return conf;
 }
 
+static const char *
+AuthzSVNAccessFile_cmd(cmd_parms *cmd, void *config, const char *arg1)
+{
+  authz_svn_config_rec *conf = config;
+
+  if (conf->repo_relative_access_file != NULL)
+    return "AuthzSVNAccessFile cannot be defined at "
+           "same time as AuthzSVNReposRelativeAccessFile.";
+
+  conf->access_file = ap_server_root_relative(cmd->pool, arg1);
+
+  return NULL;
+}
+
+
+static const char *
+AuthzSVNReposRelativeAccessFile_cmd(cmd_parms *cmd,
+                                    void *config,
+                                    const char *arg1)
+{
+  authz_svn_config_rec *conf = config;
+
+  if (conf->access_file != NULL)
+    return "AuthzSVNReposRelativeAccessFile cannot be defined at "
+           "same time as AuthzSVNAccessFile.";
+
+  conf->repo_relative_access_file = arg1;
+
+  return NULL;
+}
+
 /* Implements the #cmds member of Apache's #module vtable. */
 static const command_rec authz_svn_cmds[] =
 {
@@ -84,10 +116,17 @@ static const command_rec authz_svn_cmds[
                OR_AUTHCFG,
                "Set to 'Off' to allow access control to be passed along to "
                "lower modules. (default is On.)"),
-  AP_INIT_TAKE1("AuthzSVNAccessFile", ap_set_file_slot,
-                (void *)APR_OFFSETOF(authz_svn_config_rec, access_file),
+  AP_INIT_TAKE1("AuthzSVNAccessFile", AuthzSVNAccessFile_cmd,
+                NULL,
+                OR_AUTHCFG,
+                "Path to text file containing permissions of repository "
+                "paths."),
+  AP_INIT_TAKE1("AuthzSVNReposRelativeAccessFile",
+                AuthzSVNReposRelativeAccessFile_cmd,
+                NULL,
                 OR_AUTHCFG,
-                "Text file containing permissions of repository paths."),
+                "Path (relative to repository 'conf' directory) to text "
+                "file containing permissions of repository paths. "),
   AP_INIT_FLAG("AuthzSVNAnonymous", ap_set_flag_slot,
                (void *)APR_OFFSETOF(authz_svn_config_rec, anonymous),
                OR_AUTHCFG,
@@ -119,18 +158,40 @@ static svn_authz_t *
 get_access_conf(request_rec *r, authz_svn_config_rec *conf)
 {
   const char *cache_key = NULL;
+  const char *access_file;
+  const char *repos_path;
   void *user_data = NULL;
   svn_authz_t *access_conf = NULL;
   svn_error_t *svn_err;
+  dav_error *dav_err;
   char errbuf[256];
 
+  if (conf->repo_relative_access_file) 
+    {
+      dav_err = dav_svn_get_repos_path(r, conf->base_path, &repos_path);
+      if (dav_err) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, dav_err->desc);
+        return NULL;
+      }
+      access_file = svn_dirent_join_many(r->pool, repos_path, "conf",
+                                         conf->repo_relative_access_file,
+                                         NULL);
+    } 
+  else
+    {
+      access_file = conf->access_file;
+    }
+  
+  ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+                "Path to authz file is %s", access_file);
+
   cache_key = apr_pstrcat(r->pool, "mod_authz_svn:",
-                          conf->access_file, (char *)NULL);
+                          access_file, (char *)NULL);
   apr_pool_userdata_get(&user_data, cache_key, r->connection->pool);
   access_conf = user_data;
   if (access_conf == NULL)
     {
-      svn_err = svn_repos_authz_read(&access_conf, conf->access_file,
+      svn_err = svn_repos_authz_read(&access_conf, access_file,
                                      TRUE, r->connection->pool);
       if (svn_err)
         {
@@ -516,7 +577,8 @@ subreq_bypass(request_rec *r,
   username_to_authorize = get_username_to_authorize(r, conf);
 
   /* If configured properly, this should never be true, but just in case. */
-  if (!conf->anonymous || !conf->access_file)
+  if (!conf->anonymous || !conf->access_file
+      || !conf->repo_relative_access_file)
     {
       log_access_verdict(APLOG_MARK, r, 0, repos_path, NULL);
       return HTTP_FORBIDDEN;
@@ -580,7 +642,8 @@ access_checker(request_rec *r)
   int status;
 
   /* We are not configured to run */
-  if (!conf->anonymous || !conf->access_file)
+  if (!conf->anonymous
+      || (!conf->access_file && !conf->repo_relative_access_file))
     return DECLINED;
 
   if (ap_some_auth_required(r))
@@ -638,7 +701,8 @@ check_user_id(request_rec *r)
 
   /* We are not configured to run, or, an earlier module has already
    * authenticated this request. */
-  if (!conf->access_file || !conf->no_auth_when_anon_ok || r->user)
+  if ((!conf->access_file && !conf->repo_relative_access_file)
+      || !conf->no_auth_when_anon_ok || r->user)
     return DECLINED;
 
   /* If anon access is allowed, return OK, preventing later modules
@@ -665,7 +729,7 @@ auth_checker(request_rec *r)
   int status;
 
   /* We are not configured to run */
-  if (!conf->access_file)
+  if (!conf->access_file && !conf->repo_relative_access_file)
     return DECLINED;
 
   /* Previous hook (check_user_id) already did all the work,

Modified: subversion/branches/performance/subversion/svn/export-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/export-cmd.c?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/export-cmd.c (original)
+++ subversion/branches/performance/subversion/svn/export-cmd.c Sun Nov  7 14:30:34 2010
@@ -79,10 +79,7 @@ svn_cl__export(apr_getopt_t *os,
     {
       to = APR_ARRAY_IDX(targets, 1, const char *);
 
-      /* If given the cwd, pretend we weren't given anything. */
-      if (strcmp("", to) == 0)
-        to = svn_path_uri_decode(svn_uri_basename(truefrom, pool), pool);
-      else
+      if (strcmp("", to) != 0)
         /* svn_cl__eat_peg_revisions() but only on one target */
         SVN_ERR(svn_opt__split_arg_at_peg_revision(&to, NULL, to, pool));
     }

Modified: subversion/branches/performance/subversion/svn/info-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/info-cmd.c?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/info-cmd.c (original)
+++ subversion/branches/performance/subversion/svn/info-cmd.c Sun Nov  7 14:30:34 2010
@@ -126,6 +126,11 @@ print_info_xml(void *baton,
       /* "<wc-info>" */
       svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "wc-info", NULL);
 
+      /* "<wcroot-abspath> xx </wcroot-abspath>" */
+      if (info->wcroot_abspath)
+        svn_cl__xml_tagged_cdata(&sb, pool, "wcroot-abspath",
+                                 info->wcroot_abspath);
+
       /* "<schedule> xx </schedule>" */
       svn_cl__xml_tagged_cdata(&sb, pool, "schedule",
                                schedule_str(info->schedule));
@@ -256,6 +261,11 @@ print_info(void *baton,
     SVN_ERR(svn_cmdline_printf(pool, _("Name: %s\n"),
                                svn_dirent_basename(target, pool)));
 
+  if (info->wcroot_abspath)
+    SVN_ERR(svn_cmdline_printf(pool, _("Working Copy Root Path: %s\n"),
+                               svn_dirent_local_style(info->wcroot_abspath,
+                                                      pool)));
+
   if (info->URL)
     SVN_ERR(svn_cmdline_printf(pool, _("URL: %s\n"), info->URL));
 
@@ -539,13 +549,19 @@ svn_cl__info(apr_getopt_t *os,
       SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target, subpool));
 
       /* If no peg-rev was attached to a URL target, then assume HEAD. */
-      if (svn_path_is_url(target))
+      if (svn_path_is_url(truepath))
         {
+          truepath = svn_uri_canonicalize(truepath, subpool);
+
           if (peg_revision.kind == svn_opt_revision_unspecified)
             peg_revision.kind = svn_opt_revision_head;
         }
       else
-        SVN_ERR(svn_dirent_get_absolute(&truepath, truepath, subpool));
+        {
+          truepath = svn_dirent_canonicalize(truepath, subpool);
+
+          SVN_ERR(svn_dirent_get_absolute(&truepath, truepath, subpool));
+        }
 
       err = svn_client_info3(truepath,
                              &peg_revision, &(opt_state->start_revision),

Modified: subversion/branches/performance/subversion/svn/lock-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/lock-cmd.c?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/lock-cmd.c (original)
+++ subversion/branches/performance/subversion/svn/lock-cmd.c Sun Nov  7 14:30:34 2010
@@ -89,6 +89,8 @@ svn_cl__lock(apr_getopt_t *os,
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
   apr_array_header_t *targets;
   const char *comment;
+  svn_boolean_t wc_present = FALSE, url_present = FALSE;
+  int i;
 
   SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                       opt_state->targets,
@@ -98,6 +100,22 @@ svn_cl__lock(apr_getopt_t *os,
   if (! targets->nelts)
     return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);
 
+  /* Check to see if at least one of our paths is a working copy
+   * path or a repository url. */
+  for (i = 0; i < targets->nelts; ++i)
+    {
+      const char *target = APR_ARRAY_IDX(targets, i, const char *);
+      if (! svn_path_is_url(target))
+       wc_present = TRUE;
+      else
+       url_present = TRUE;
+    }
+
+  if (url_present && wc_present)
+    return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                        _("Cannot mix repository and working copy "
+                          "targets"));
+
   /* Get comment. */
   SVN_ERR(get_comment(&comment, ctx, opt_state, pool));
 

Modified: subversion/branches/performance/subversion/svn/resolve-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/resolve-cmd.c?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/resolve-cmd.c (original)
+++ subversion/branches/performance/subversion/svn/resolve-cmd.c Sun Nov  7 14:30:34 2010
@@ -29,6 +29,7 @@
 #define APR_WANT_STDIO
 #include <apr_want.h>
 
+#include "svn_path.h"
 #include "svn_client.h"
 #include "svn_error.h"
 #include "svn_pools.h"
@@ -93,6 +94,19 @@ svn_cl__resolve(apr_getopt_t *os,
 
   SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool));
 
+  /* Don't even attempt to modify the working copy if any of the
+   * targets look like URLs. URLs are invalid input. */
+  for (i = 0; i < targets->nelts; i++)
+    {
+      const char *target = APR_ARRAY_IDX(targets, i, const char *);
+
+      if (svn_path_is_url(target))
+        return svn_error_return(svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
+                                                  NULL,
+                                                  _("'%s' is not a local path"),
+                                                  target));
+    }
+  
   iterpool = svn_pool_create(scratch_pool);
   for (i = 0; i < targets->nelts; i++)
     {

Modified: subversion/branches/performance/subversion/svn/resolved-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/resolved-cmd.c?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/resolved-cmd.c (original)
+++ subversion/branches/performance/subversion/svn/resolved-cmd.c Sun Nov  7 14:30:34 2010
@@ -29,6 +29,7 @@
 #define APR_WANT_STDIO
 #include <apr_want.h>
 
+#include "svn_path.h"
 #include "svn_client.h"
 #include "svn_error.h"
 #include "svn_pools.h"
@@ -64,6 +65,18 @@ svn_cl__resolved(apr_getopt_t *os,
 
   SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool));
 
+  /* URLs are invalid input. */
+  for (i = 0; i < targets->nelts; i++)
+    {
+      const char *target = APR_ARRAY_IDX(targets, i, const char *);
+
+      if (svn_path_is_url(target))
+        return svn_error_return(svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
+                                                  NULL,
+                                                  _("'%s' is not a local path"),
+                                                  target));
+    }
+  
   iterpool = svn_pool_create(scratch_pool);
   for (i = 0; i < targets->nelts; i++)
     {

Modified: subversion/branches/performance/subversion/svn/revert-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/revert-cmd.c?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/revert-cmd.c (original)
+++ subversion/branches/performance/subversion/svn/revert-cmd.c Sun Nov  7 14:30:34 2010
@@ -27,6 +27,7 @@
 
 /*** Includes. ***/
 
+#include "svn_path.h"
 #include "svn_client.h"
 #include "svn_error_codes.h"
 #include "svn_error.h"
@@ -47,6 +48,7 @@ svn_cl__revert(apr_getopt_t *os,
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
   apr_array_header_t *targets = NULL;
   svn_error_t *err;
+  int i;
 
   SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                       opt_state->targets,
@@ -63,9 +65,21 @@ svn_cl__revert(apr_getopt_t *os,
 
   SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool));
 
+  /* Don't even attempt to modify the working copy if any of the
+   * targets look like URLs. URLs are invalid input. */
+  for (i = 0; i < targets->nelts; i++)
+    {
+      const char *target = APR_ARRAY_IDX(targets, i, const char *);
+
+      if (svn_path_is_url(target))
+        return svn_error_return(svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
+                                                  NULL,
+                                                  _("'%s' is not a local path"),
+                                                  target));
+    }
+
   err = svn_client_revert2(targets, opt_state->depth,
                            opt_state->changelists, ctx, scratch_pool);
-
   if (err
       && (err->apr_err == SVN_ERR_WC_INVALID_OPERATION_DEPTH)
       && (! SVN_DEPTH_IS_RECURSIVE(opt_state->depth)))

Modified: subversion/branches/performance/subversion/svn/schema/info.rnc
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/schema/info.rnc?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/schema/info.rnc (original)
+++ subversion/branches/performance/subversion/svn/schema/info.rnc Sun Nov  7 14:30:34 2010
@@ -53,6 +53,7 @@ uuid = element uuid { uuid.type }
 ## Info in the working copy entry.
 wc-info =
   element wc-info {
+    wcroot-abspath?,
     schedule?,
     changelist?,
     copy-from-url?,
@@ -63,6 +64,8 @@ wc-info =
     checksum?
   }
 
+wcroot-abspath = element wcroot-abspath { string }
+
 schedule =
   element schedule { "normal" | "add" | "delete" | "replace" | "none" }
 

Modified: subversion/branches/performance/subversion/svn/status-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/status-cmd.c?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/status-cmd.c (original)
+++ subversion/branches/performance/subversion/svn/status-cmd.c Sun Nov  7 14:30:34 2010
@@ -249,6 +249,18 @@ svn_cl__status(apr_getopt_t *os,
   /* Add "." if user passed 0 arguments */
   svn_opt_push_implicit_dot_target(targets, scratch_pool);
 
+  /* URLs are invalid input. */
+  for (i = 0; i < targets->nelts; i++)
+    {
+      const char *target = APR_ARRAY_IDX(targets, i, const char *);
+
+      if (svn_path_is_url(target))
+        return svn_error_return(svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
+                                                  NULL,
+                                                  _("'%s' is not a local path"),
+                                                  target));
+    }
+
   /* We want our -u statuses to be against HEAD. */
   rev.kind = svn_opt_revision_head;
 

Modified: subversion/branches/performance/subversion/svn/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/util.c?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/util.c (original)
+++ subversion/branches/performance/subversion/svn/util.c Sun Nov  7 14:30:34 2010
@@ -826,14 +826,14 @@ svn_cl__get_log_message(const char **log
              white space as we will consider white space only as empty */
           apr_size_t len;
 
-          for (len = message->len - 1; len >= 0; len--)
+          for (len = 0; len < message->len; len++)
             {
               /* FIXME: should really use an UTF-8 whitespace test
                  rather than svn_ctype_isspace, which is ASCII only */
               if (! svn_ctype_isspace(message->data[len]))
                 break;
             }
-          if (len < 0)
+          if (len == message->len)
             message = NULL;
         }
 

Modified: subversion/branches/performance/subversion/tests/cmdline/atomic-ra-revprop-change.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/atomic-ra-revprop-change.c?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/atomic-ra-revprop-change.c (original)
+++ subversion/branches/performance/subversion/tests/cmdline/atomic-ra-revprop-change.c Sun Nov  7 14:30:34 2010
@@ -261,6 +261,5 @@ main(int argc, const char *argv[])
   svn_pool_destroy(pool);
   apr_terminate();
 
-  exit(exit_code);
   return exit_code;
 }

Modified: subversion/branches/performance/subversion/tests/cmdline/basic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/basic_tests.py?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/basic_tests.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/basic_tests.py Sun Nov  7 14:30:34 2010
@@ -2500,9 +2500,9 @@ def delete_from_url_with_spaces(sbox):
   "delete a directory with ' ' using its url"
   
   sbox.build()
-  sbox.simple_mkdir(os.path.join(sbox.wc_dir, 'Dir With Spaces'))
-  sbox.simple_mkdir(os.path.join(sbox.wc_dir, 'Dir With'))
-  sbox.simple_mkdir(os.path.join(sbox.wc_dir, 'Dir With/Spaces'))
+  sbox.simple_mkdir('Dir With Spaces')
+  sbox.simple_mkdir('Dir With')
+  sbox.simple_mkdir('Dir With/Spaces')
 
   svntest.actions.run_and_verify_svn(None, None, [],
                                       'ci', sbox.wc_dir, '-m', 'Added dir')
@@ -2647,6 +2647,29 @@ def basic_relocate(sbox):
   ### TODO: When testing ra_dav or ra_svn, do relocations between
   ### those and ra_local URLs.
 
+#----------------------------------------------------------------------
+
+def delete_urls_with_spaces(sbox):
+  "delete multiple targets with spaces"
+  sbox.build(create_wc = False)
+  
+  # Create three directories with a space in their name  
+  svntest.actions.run_and_verify_svn(None, None, [], 'mkdir',
+                                     sbox.repo_url + '/A spaced',
+                                     sbox.repo_url + '/B spaced',
+                                     sbox.repo_url + '/C spaced',
+                                     '-m', 'Created dirs')
+
+  # Try to delete the first                                     
+  svntest.actions.run_and_verify_svn(None, None, [], 'rm',
+                                     sbox.repo_url + '/A spaced',
+                                     '-m', 'Deleted A') 
+
+  # And then two at once
+  svntest.actions.run_and_verify_svn(None, None, [], 'rm',
+                                     sbox.repo_url + '/B spaced',
+                                     sbox.repo_url + '/C spaced',
+                                     '-m', 'Deleted B and C') 
 
 ########################################################################
 # Run the tests
@@ -2708,6 +2731,7 @@ test_list = [ None,
               delete_and_add_same_file,
               delete_child_parent_update,
               basic_relocate,
+              delete_urls_with_spaces,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/performance/subversion/tests/cmdline/blame_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/blame_tests.py?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/blame_tests.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/blame_tests.py Sun Nov  7 14:30:34 2010
@@ -462,10 +462,10 @@ def blame_merge_info(sbox):
 
   wc_dir = sbox.wc_dir
   iota_path = os.path.join(wc_dir, 'trunk', 'iota')
+  mu_path = os.path.join(wc_dir, 'trunk', 'A', 'mu')
 
   exit_code, output, error = svntest.actions.run_and_verify_svn(
-    None, None, [],
-    'blame', '-g', iota_path)
+    None, None, [], 'blame', '-g', iota_path)
 
   expected_blame = [
       { 'revision' : 2,
@@ -481,6 +481,45 @@ def blame_merge_info(sbox):
     ]
   parse_and_verify_blame(output, expected_blame, 1)
 
+  exit_code, output, error = svntest.actions.run_and_verify_svn(
+    None, None, [], 'blame', '-g', '-r10:11', iota_path)
+
+  expected_blame = [
+      { 'revision' : None,
+        'author' : None,
+        'text' : "This is the file 'iota'.\n",
+        'merged' : 0,
+      },
+      { 'revision' : None,
+        'author' : None,
+        'text' : "'A' has changed a bit.\n",
+        'merged' : 0,
+      },
+    ]
+  parse_and_verify_blame(output, expected_blame, 1)
+
+  exit_code, output, error = svntest.actions.run_and_verify_svn(
+    None, None, [], 'blame', '-g', '-r16:17', mu_path)
+
+  expected_blame = [
+      { 'revision' : None,
+        'author' : None,
+        'text' : "This is the file 'mu'.\n",
+        'merged' : 0,
+      },
+      { 'revision' : 16,
+        'author' : 'jrandom',
+        'text' : "Don't forget to look at 'upsilon', as well.\n",
+        'merged' : 1,
+      },
+      { 'revision' : 16,
+        'author' : 'jrandom',
+        'text' : "This is yet more content in 'mu'.\n",
+        'merged' : 1,
+      },
+    ]
+  parse_and_verify_blame(output, expected_blame, 1)
+
 
 def blame_merge_out_of_range(sbox):
   "don't look for merged files out of range"

Modified: subversion/branches/performance/subversion/tests/cmdline/copy_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/copy_tests.py?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/copy_tests.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/copy_tests.py Sun Nov  7 14:30:34 2010
@@ -4588,7 +4588,7 @@ def changed_data_should_match_checkout(s
 
   svntest.actions.run_and_verify_svn(None, None, [], 'copy', A_B_E, E_new)
 
-  sbox.simple_commit(wc_dir)
+  sbox.simple_commit()
 
   svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
 
@@ -4618,7 +4618,7 @@ def changed_dir_data_should_match_checko
 
   svntest.actions.run_and_verify_svn(None, None, [], 'copy', A_B, B_new)
 
-  sbox.simple_commit(wc_dir)
+  sbox.simple_commit()
 
   svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
 
@@ -4835,6 +4835,92 @@ def delete_replace_delete(sbox):
   # Currently fails because pi, rho, tau get left behind
   svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
+A_B_children = ['A/B/lambda', 'A/B/F', 'A/B/E/alpha', 'A/B/E/beta', 'A/B/E']
+A_D_children = ['A/D/gamma', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau',
+                'A/D/H', 'A/D/H/chi', 'A/D/H/psi', 'A/D/H/omega']
+
+def copy_repos_over_deleted_same_kind(sbox):
+  "copy repos node over deleted node, same kind"
+  sbox.build(read_only = True)
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+
+  # Set up some deleted paths
+  sbox.simple_rm('iota', 'A/B')
+  for path in ['iota', 'A/B'] + A_B_children:
+    expected_status.tweak(path, status='D ')
+
+  # Test copying
+  main.run_svn(None, 'cp', sbox.repo_url + '/A/mu', sbox.ospath('iota'))
+  expected_status.tweak('iota', status='R ', wc_rev='-', copied='+')
+  main.run_svn(None, 'cp', sbox.repo_url + '/A/D', sbox.ospath('A/B'))
+  expected_status.tweak('A/B', status='R ', wc_rev='-', copied='+')
+  for child in A_D_children:
+    expected_status.add({ child.replace('A/D', 'A/B'):
+                          Item(status='  ', wc_rev='-', copied='+')})
+  svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status)
+
+def copy_repos_over_deleted_other_kind(sbox):
+  "copy repos node over deleted node, other kind"
+  sbox.build(read_only = True)
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+
+  # Set up some deleted paths
+  sbox.simple_rm('iota', 'A/B')
+  for path in ['iota', 'A/B'] + A_B_children:
+    expected_status.tweak(path, status='D ')
+
+  # Test copying
+  main.run_svn(None, 'cp', sbox.repo_url + '/iota', sbox.ospath('A/B'))
+  expected_status.tweak('A/B', status='R ', wc_rev='-', copied='+')
+  expected_status.remove(*A_B_children)
+  main.run_svn(None, 'cp', sbox.repo_url + '/A/B', sbox.ospath('iota'))
+  expected_status.tweak('iota', status='R ', wc_rev='-', copied='+')
+  for child in A_B_children:
+    expected_status.add({ child.replace('A/B', 'iota'):
+                          Item(status='  ', wc_rev='-', copied='+')})
+  svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status)
+
+def copy_wc_over_deleted_same_kind(sbox):
+  "copy WC node over a deleted node, same kind"
+  sbox.build(read_only = True)
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+
+  # Set up some deleted paths
+  sbox.simple_rm('iota', 'A/B')
+  for path in ['iota', 'A/B'] + A_B_children:
+    expected_status.tweak(path, status='D ')
+
+  # Test copying
+  main.run_svn(None, 'cp', sbox.ospath('A/mu'), sbox.ospath('iota'))
+  expected_status.tweak('iota', status='R ', wc_rev='-', copied='+')
+  main.run_svn(None, 'cp', sbox.ospath('A/D'), sbox.ospath('A/B'))
+  expected_status.tweak('A/B', status='R ', wc_rev='-', copied='+')
+  for child in A_D_children:
+    expected_status.add({ child.replace('A/D', 'A/B'):
+                          Item(status='  ', wc_rev='-', copied='+')})
+  svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status)
+
+def copy_wc_over_deleted_other_kind(sbox):
+  "copy WC node over deleted node, other kind"
+  sbox.build(read_only = True)
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+
+  # Set up some deleted paths
+  sbox.simple_rm('iota', 'A/B')
+  for path in ['iota', 'A/B'] + A_B_children:
+    expected_status.tweak(path, status='D ')
+
+  # Test copying
+  main.run_svn(None, 'cp', sbox.ospath('A/mu'), sbox.ospath('A/B'))
+  expected_status.tweak('A/B', status='R ', wc_rev='-', copied='+')
+  expected_status.remove(*A_B_children)
+  main.run_svn(None, 'cp', sbox.ospath('A/D'), sbox.ospath('iota'))
+  expected_status.tweak('iota', status='R ', wc_rev='-', copied='+')
+  for child in A_D_children:
+    expected_status.add({ child.replace('A/D', 'iota'):
+                          Item(status='  ', wc_rev='-', copied='+')})
+  svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status)
+
 
 ########################################################################
 # Run the tests
@@ -4934,6 +5020,10 @@ test_list = [ None,
               copy_delete_delete,
               XFail(copy_delete_revert),
               delete_replace_delete,
+              copy_repos_over_deleted_same_kind,
+              copy_repos_over_deleted_other_kind,
+              copy_wc_over_deleted_same_kind,
+              copy_wc_over_deleted_other_kind,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/performance/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/diff_tests.py?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/diff_tests.py Sun Nov  7 14:30:34 2010
@@ -2585,9 +2585,9 @@ def basic_diff_summarize(sbox):
 
   # Add props to some items that will be deleted, and commit.
   sbox.simple_propset('prop', 'val',
-                      p('A/C'),
-                      p('A/D/gamma'),
-                      p('A/D/H/chi'))
+                      'A/C',
+                      'A/D/gamma',
+                      'A/D/H/chi')
   sbox.simple_commit() # r2
   sbox.simple_update()
 
@@ -2595,37 +2595,37 @@ def basic_diff_summarize(sbox):
   svntest.main.file_append(p('A/mu'), 'new text\n')
 
   # Prop modification.
-  sbox.simple_propset('prop', 'val', p('iota'))
+  sbox.simple_propset('prop', 'val', 'iota')
 
   # Both content and prop mods.
   svntest.main.file_append(p('A/D/G/tau'), 'new text\n')
-  sbox.simple_propset('prop', 'val', p('A/D/G/tau'))
+  sbox.simple_propset('prop', 'val', 'A/D/G/tau')
 
   # File addition.
   svntest.main.file_append(p('newfile'), 'new text\n')
   svntest.main.file_append(p('newfile2'), 'new text\n')
-  sbox.simple_add(p('newfile'),
-                  p('newfile2'))
-  sbox.simple_propset('prop', 'val', p('newfile'))
+  sbox.simple_add('newfile',
+                  'newfile2')
+  sbox.simple_propset('prop', 'val', 'newfile')
 
   # File deletion.
-  sbox.simple_rm(p('A/B/lambda'),
-                 p('A/D/gamma'))
-                 
+  sbox.simple_rm('A/B/lambda',
+                 'A/D/gamma')
+
   # Directory addition.
   os.makedirs(p('P'))
   os.makedirs(p('Q/R'))
   svntest.main.file_append(p('Q/newfile'), 'new text\n')
   svntest.main.file_append(p('Q/R/newfile'), 'new text\n')
-  sbox.simple_add(p('P'),
-                  p('Q'))
+  sbox.simple_add('P',
+                  'Q')
   sbox.simple_propset('prop', 'val',
-                      p('P'),
-                      p('Q/newfile'))
+                      'P',
+                      'Q/newfile')
 
   # Directory deletion.
-  sbox.simple_rm(p('A/D/H'),
-                 p('A/C'))
+  sbox.simple_rm('A/D/H',
+                 'A/C')
  
   # Commit, because diff-summarize handles repos-repos only.
   #svntest.main.run_svn(False, 'st', wc_dir)

Modified: subversion/branches/performance/subversion/tests/cmdline/export_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/export_tests.py?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/export_tests.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/export_tests.py Sun Nov  7 14:30:34 2010
@@ -680,7 +680,7 @@ test_list = [ None,
               export_with_url_unsafe_characters,
               XFail(export_working_copy_with_depths),
               export_externals_with_native_eol,
-              XFail(export_to_current_dir),
+              export_to_current_dir,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/performance/subversion/tests/cmdline/info_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/info_tests.py?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/info_tests.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/info_tests.py Sun Nov  7 14:30:34 2010
@@ -285,6 +285,39 @@ def info_on_mkdir(sbox):
                        ('depth',    {}, 'infinity'),
                        ('schedule', {}, 'add')])
 
+def info_wcroot_abspaths(sbox):
+  """wc root paths in 'svn info' output"""
+
+  def check_wcroot_paths(lines, wcroot_abspath):
+    "check that paths found on input lines beginning 'Path: ' are as expected"
+    path = None
+    target = None
+    for line in lines:
+      if line.startswith('Path: '):
+        target = line[6:].rstrip()
+      if line.startswith('Working Copy Root Path: '):
+        path = line[24:].rstrip()
+      if target is not None and path is not None:
+        break
+
+    if target is None:
+      target = "(UNKNOWN)"
+      
+    if path is None:
+      print "No WC root path for '%s'" % (target)
+      raise svntest.Failure
+    
+    if path != wcroot_abspath:
+      print("For target '%s'..." % (target))
+      print("   Reported WC root path: %s" % (path))
+      print("   Expected WC root path: %s" % (wcroot_abspath))
+      raise svntest.Failure
+
+  sbox.build(read_only=True)
+  exit_code, output, errput = svntest.main.run_svn(None, 'info', '-R', sbox.wc_dir)
+  check_wcroot_paths(output, os.path.abspath(sbox.wc_dir))
+
+
 ########################################################################
 # Run the tests
 
@@ -293,6 +326,7 @@ test_list = [ None,
               info_with_tree_conflicts,
               info_on_added_file,
               info_on_mkdir,
+              info_wcroot_abspaths,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/performance/subversion/tests/cmdline/input_validation_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/input_validation_tests.py?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/input_validation_tests.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/input_validation_tests.py Sun Nov  7 14:30:34 2010
@@ -173,6 +173,40 @@ def invalid_wcpath_upgrade(sbox):
     run_and_verify_svn_in_wc(sbox, "svn:.*is not a local path", 'upgrade',
                              target, target)
 
+def invalid_resolve_targets(sbox):
+  "non-working copy paths for 'resolve'"
+  sbox.build(read_only=True)
+  for target in _invalid_wc_path_targets:
+    run_and_verify_svn_in_wc(sbox, "svn:.*is not a local path", 'resolve',
+                             '--accept', 'base', target)
+
+def invalid_resolved_targets(sbox):
+  "non-working copy paths for 'resolved'"
+  sbox.build(read_only=True)
+  for target in _invalid_wc_path_targets:
+    run_and_verify_svn_in_wc(sbox, "svn:.*is not a local path", 'resolved',
+                             target)
+
+def invalid_revert_targets(sbox):
+  "non-working copy paths for 'revert'"
+  sbox.build(read_only=True)
+  for target in _invalid_wc_path_targets:
+    run_and_verify_svn_in_wc(sbox, "svn:.*is not a local path", 'revert',
+                             target)
+
+def invalid_lock_targets(sbox):
+  "wc paths and repo URL target mixture for 'lock'"
+  sbox.build(read_only=True)
+  for (target1, target2) in [("iota", "^/"), ("file://", "iota")]:
+    run_and_verify_svn_in_wc(sbox, "svn: Cannot mix repository and working "
+                             "copy targets", 'lock', target1, target2)
+
+def invalid_status_targets(sbox):
+  "non-working copy paths for 'status'"
+  sbox.build(read_only=True)
+  for target in _invalid_wc_path_targets:
+    run_and_verify_svn_in_wc(sbox, "svn:.*is not a local path", 'status',
+                             target)
 
 ########################################################################
 # Run the tests
@@ -192,6 +226,11 @@ test_list = [ None,
               invalid_log_targets,
               invalid_merge_args,
               invalid_wcpath_upgrade,
+              invalid_resolve_targets,
+              invalid_resolved_targets,
+              invalid_revert_targets,
+              invalid_lock_targets,
+              invalid_status_targets,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/performance/subversion/tests/cmdline/lock_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/cmdline/lock_tests.py?rev=1032285&r1=1032284&r2=1032285&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/cmdline/lock_tests.py (original)
+++ subversion/branches/performance/subversion/tests/cmdline/lock_tests.py Sun Nov  7 14:30:34 2010
@@ -1606,16 +1606,16 @@ def cp_isnt_ro(sbox):
   open(kappa_path, 'w').write("This is the file 'kappa'.\n")
 
   ## added file
-  sbox.simple_add(kappa_path)
+  sbox.simple_add('kappa')
   svntest.actions.set_prop('svn:needs-lock', 'yes', kappa_path)
   is_writable(kappa_path)
-  sbox.simple_commit(kappa_path)
+  sbox.simple_commit('kappa')
   is_readonly(kappa_path)
 
   ## versioned file
   svntest.actions.set_prop('svn:needs-lock', 'yes', mu_path)
   is_writable(mu_path)
-  sbox.simple_commit(mu_path)
+  sbox.simple_commit('A/mu')
   is_readonly(mu_path)
 
   # At this point, mu has 'svn:needs-lock' set
@@ -1623,13 +1623,13 @@ def cp_isnt_ro(sbox):
   ## wc->wc copied file
   svntest.main.run_svn(None, 'copy', mu_path, mu2_path)
   is_writable(mu2_path)
-  sbox.simple_commit(mu2_path)
+  sbox.simple_commit('A/mu2')
   is_readonly(mu2_path)
 
   ## URL->wc copied file
   svntest.main.run_svn(None, 'copy', mu_URL, mu3_path)
   is_writable(mu3_path)
-  sbox.simple_commit(mu3_path)
+  sbox.simple_commit('A/mu3')
   is_readonly(mu3_path)