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/12/02 21:55:18 UTC

svn commit: r1041580 [7/35] - in /subversion/branches/gpg-agent-password-store: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/hook-scripts/ contrib/server-side/ notes/http-and-webdav/ notes/wc-ng/ subversio...

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/tree.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/tree.c Thu Dec  2 20:55:08 2010
@@ -486,7 +486,7 @@ parent_path_path(parent_path_t *parent_p
   if (parent_path->parent)
     path_so_far = parent_path_path(parent_path->parent, pool);
   return parent_path->entry
-    ? svn_uri_join(path_so_far, parent_path->entry, pool)
+    ? svn_fspath__join(path_so_far, parent_path->entry, pool)
          : path_so_far;
 }
 
@@ -693,7 +693,7 @@ open_path(parent_path_t **parent_path_p,
       entry = svn_fs__next_entry_name(&next, rest, pool);
 
       /* Calculate the path traversed thus far. */
-      path_so_far = svn_uri_join(path_so_far, entry, pool);
+      path_so_far = svn_fspath__join(path_so_far, entry, pool);
 
       if (*entry == '\0')
         {
@@ -1727,7 +1727,7 @@ deltify_mutable(svn_fs_t *fs,
           apr_hash_this(hi, &key, NULL, &val);
           entry = val;
           SVN_ERR(deltify_mutable(fs, root,
-                                  svn_uri_join(path, key, subpool),
+                                  svn_fspath__join(path, key, subpool),
                                   entry->id, entry->kind, txn_id, subpool));
         }
 
@@ -2271,7 +2271,7 @@ merge(svn_stringbuf_t *conflict_p,
              a modification. In any of these cases, flag a conflict. */
           if (s_entry == NULL || t_entry == NULL)
             return conflict_err(conflict_p,
-                                svn_uri_join(target_path,
+                                svn_fspath__join(target_path,
                                                 a_entry->name,
                                                 iterpool));
 
@@ -2286,7 +2286,7 @@ merge(svn_stringbuf_t *conflict_p,
               || strcmp(svn_fs_base__id_copy_id(t_entry->id),
                         svn_fs_base__id_copy_id(a_entry->id)) != 0)
             return conflict_err(conflict_p,
-                                svn_uri_join(target_path,
+                                svn_fspath__join(target_path,
                                                 a_entry->name,
                                                 iterpool));
 
@@ -2303,14 +2303,14 @@ merge(svn_stringbuf_t *conflict_p,
               || (svn_fs_base__dag_node_kind(t_ent_node) == svn_node_file)
               || (svn_fs_base__dag_node_kind(a_ent_node) == svn_node_file))
             return conflict_err(conflict_p,
-                                svn_uri_join(target_path,
+                                svn_fspath__join(target_path,
                                                 a_entry->name,
                                                 iterpool));
 
           /* Direct modifications were made to the directory
              ANCESTOR-ENTRY in both SOURCE and TARGET.  Recursively
              merge these modifications. */
-          new_tpath = svn_uri_join(target_path, t_entry->name, iterpool);
+          new_tpath = svn_fspath__join(target_path, t_entry->name, iterpool);
           SVN_ERR(merge(conflict_p, new_tpath,
                         t_ent_node, s_ent_node, a_ent_node,
                         txn_id, &sub_mergeinfo_increment, trail, iterpool));
@@ -2346,7 +2346,7 @@ merge(svn_stringbuf_t *conflict_p,
       /* If NAME exists in TARGET, declare a conflict. */
       if (t_entry)
         return conflict_err(conflict_p,
-                            svn_uri_join(target_path,
+                            svn_fspath__join(target_path,
                                             t_entry->name,
                                             iterpool));
 
@@ -2522,7 +2522,7 @@ verify_locks(const char *txn_name,
       /* If this path has already been verified as part of a recursive
          check of one of its parents, no need to do it again.  */
       if (last_recursed
-          && svn_uri_is_child(last_recursed->data, path, subpool))
+          && svn_fspath__is_child(last_recursed->data, path, subpool))
         continue;
 
       /* Fetch the change associated with our path.  */
@@ -4488,7 +4488,7 @@ txn_body_history_prev(void *baton, trail
       if (strcmp(path, copy_dst) == 0)
         remainder = "";
       else
-        remainder = svn_uri_is_child(copy_dst, path, trail->pool);
+        remainder = svn_fspath__is_child(copy_dst, path, trail->pool);
 
       if (remainder)
         {
@@ -4501,7 +4501,7 @@ txn_body_history_prev(void *baton, trail
                   (&dst_rev, fs,
                    svn_fs_base__id_txn_id(copy->dst_noderev_id),
                    trail, trail->pool));
-          src_path = svn_uri_join(copy->src_path, remainder,
+          src_path = svn_fspath__join(copy->src_path, remainder,
                                      trail->pool);
           if (copy->kind == copy_kind_soft)
             retry = TRUE;
@@ -4911,8 +4911,8 @@ prev_location(const char **prev_path,
   SVN_ERR(base_copied_from(&copy_src_rev, &copy_src_path,
                            copy_root, copy_path, pool));
   if (! strcmp(copy_path, path) == 0)
-    remainder = svn_uri_is_child(copy_path, path, pool);
-  *prev_path = svn_uri_join(copy_src_path, remainder, pool);
+    remainder = svn_fspath__is_child(copy_path, path, pool);
+  *prev_path = svn_fspath__join(copy_src_path, remainder, pool);
   *prev_rev = copy_src_rev;
   return SVN_NO_ERROR;
 }
@@ -5090,6 +5090,129 @@ base_node_origin_rev(svn_revnum_t *revis
 
 /* Mergeinfo Queries */
 
+
+/* Implements svn_fs_validate_mergeinfo. */
+svn_error_t *
+svn_fs_base__validate_mergeinfo(svn_mergeinfo_t *validated_mergeinfo,
+                                svn_fs_t *fs,
+                                svn_mergeinfo_t mergeinfo,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool)
+{
+  svn_mergeinfo_t filtered_mergeinfo;
+  apr_hash_t *rev_to_sources;
+  apr_hash_index_t *hi;
+  apr_pool_t *iterpool;
+
+  /* A couple easy outs. */
+  if (mergeinfo == NULL)
+    {
+      *validated_mergeinfo = NULL;
+      return SVN_NO_ERROR;
+    }
+  else if (apr_hash_count(mergeinfo) == 0)
+    {
+      *validated_mergeinfo = apr_hash_make(result_pool);
+      return SVN_NO_ERROR;
+    }
+
+  filtered_mergeinfo = apr_hash_make(scratch_pool);
+  rev_to_sources = apr_hash_make(scratch_pool);
+
+  /* Since svn_fs_check_path needs an svn_fs_root_t based on a revision,
+     we convert MERGEINFO into a mapping of revisions to a hash of source
+     paths for efficiency. */
+  for (hi = apr_hash_first(scratch_pool, mergeinfo);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *path = svn__apr_hash_index_key(hi);
+      apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+      int i;
+
+      for (i = 0; i < rangelist->nelts; i++)
+        {
+          svn_merge_range_t *range =
+            APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
+          svn_revnum_t j;
+
+          for (j = range->start + 1; j <= range->end; j++)
+            {
+              apr_hash_t *paths_for_rev =
+                apr_hash_get(rev_to_sources, &j, sizeof(svn_revnum_t));
+
+              /* No hash associated with this rev yet? */
+              if (!paths_for_rev)
+                {
+                  svn_revnum_t *rev = apr_palloc(scratch_pool, sizeof(*rev));
+
+                  *rev = j;
+                  paths_for_rev = apr_hash_make(scratch_pool);
+                  apr_hash_set(rev_to_sources, rev,
+                               sizeof(svn_revnum_t), paths_for_rev);
+                }
+
+              apr_hash_set(paths_for_rev, path, APR_HASH_KEY_STRING, path);
+            }
+        }
+    }
+
+  iterpool = svn_pool_create(scratch_pool);
+
+  /* Validate the rev->source MERGEINFO equivalent hash, building the
+     validated mergeinfo as we go. */
+  for (hi = apr_hash_first(scratch_pool, rev_to_sources);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const svn_revnum_t *rev = svn__apr_hash_index_key(hi);
+      apr_hash_t *paths = svn__apr_hash_index_val(hi);
+      apr_pool_t *inner_iterpool;
+      apr_hash_index_t *hi2;
+      svn_node_kind_t kind;
+      svn_fs_root_t *mergeinfo_rev_root;
+
+      svn_pool_clear(iterpool);
+      inner_iterpool = svn_pool_create(iterpool);
+
+      SVN_ERR(svn_fs_base__revision_root(&mergeinfo_rev_root, fs,
+                                         *rev, iterpool));
+
+       for (hi2 = apr_hash_first(iterpool, paths);
+            hi2;
+            hi2 = apr_hash_next(hi2))
+         {
+            const char *path = svn__apr_hash_index_key(hi2);
+ 
+            svn_pool_clear(inner_iterpool);
+            SVN_ERR(base_check_path(&kind, mergeinfo_rev_root,
+                                    path, inner_iterpool));
+            if (kind == svn_node_none)
+              {
+                apr_hash_set(paths, path, APR_HASH_KEY_STRING, NULL);
+              }
+            else
+              {
+                svn_mergeinfo_t good_mergeinfo_fragment;
+                const char *mergeinfo_str =
+                  apr_psprintf(inner_iterpool, "%s:%ld", path, *rev);
+
+                SVN_ERR(svn_mergeinfo_parse(&good_mergeinfo_fragment,
+                                            mergeinfo_str, scratch_pool));
+                SVN_ERR(svn_mergeinfo_merge(filtered_mergeinfo,
+                                            good_mergeinfo_fragment,
+                                            scratch_pool));
+              }
+         }
+      svn_pool_destroy(inner_iterpool);
+    }
+
+  svn_pool_destroy(iterpool);
+  *validated_mergeinfo = svn_mergeinfo_dup(filtered_mergeinfo, result_pool);
+  return SVN_NO_ERROR;
+}
+
+
 /* Examine directory NODE's immediately children for mergeinfo.
 
    For those which have explicit mergeinfo, add their mergeinfo to
@@ -5173,7 +5296,7 @@ txn_body_get_mergeinfo_data_and_entries(
           SVN_ERR(svn_mergeinfo_parse(&child_mergeinfo, pval->data,
                                       result_pool));
           apr_hash_set(args->result_catalog,
-                       svn_uri_join(args->node_path, dirent->name,
+                       svn_fspath__join(args->node_path, dirent->name,
                                        result_pool),
                        APR_HASH_KEY_STRING,
                        child_mergeinfo);
@@ -5243,7 +5366,7 @@ crawl_directory_for_mergeinfo(svn_fs_t *
       svn_pool_clear(iterpool);
       apr_hash_this(hi, &key, NULL, &val);
       crawl_directory_for_mergeinfo(fs, val,
-                                    svn_uri_join(node_path, key, iterpool),
+                                    svn_fspath__join(node_path, key, iterpool),
                                     result_catalog, iterpool);
     }
   svn_pool_destroy(iterpool);
@@ -5269,7 +5392,7 @@ append_to_merged_froms(svn_mergeinfo_t *
       const void *key;
       void *val;
       apr_hash_this(hi, &key, NULL, &val);
-      apr_hash_set(*output, svn_uri_join(key, rel_path, pool),
+      apr_hash_set(*output, svn_fspath__join(key, rel_path, pool),
                    APR_HASH_KEY_STRING, svn_rangelist_dup(val, pool));
     }
   return SVN_NO_ERROR;
@@ -5278,12 +5401,14 @@ append_to_merged_froms(svn_mergeinfo_t *
 
 /* Calculate the mergeinfo for PATH under revision ROOT using
    inheritance type INHERIT.  Set *MERGEINFO to the mergeinfo, or to
-   NULL if there is none.  Results are allocated in POOL; TRAIL->pool
+   NULL if there is none.  If *MERGEINFO is inherited set *INHERITED
+   to true, false otherwise.  Results are allocated in POOL; TRAIL->POOL
    is used for temporary allocations.  */
 
 struct get_mergeinfo_for_path_baton
 {
   svn_mergeinfo_t *mergeinfo;
+  svn_boolean_t *inherited;
   svn_fs_root_t *root;
   const char *path;
   svn_mergeinfo_inheritance_t inherit;
@@ -5301,6 +5426,7 @@ txn_body_get_mergeinfo_for_path(void *ba
   dag_node_t *node = NULL;
 
   *(args->mergeinfo) = NULL;
+  *(args->inherited) = FALSE;
 
   SVN_ERR(open_path(&parent_path, args->root, args->path, 0,
                     NULL, trail, trail->pool));
@@ -5382,6 +5508,7 @@ txn_body_get_mergeinfo_for_path(void *ba
                                                          nearest_ancestor,
                                                          trail->pool),
                                      args->pool));
+      *(args->inherited) = TRUE;
     }
   return SVN_NO_ERROR;
 }
@@ -5413,14 +5540,17 @@ txn_body_get_node_mergeinfo_stats(void *
 }
 
 
-/* Get the mergeinfo for a set of paths, returned in
-   *MERGEINFO_CATALOG.  Returned values are allocated in POOL, while
-   temporary values are allocated in a sub-pool. */
+/* Get the mergeinfo for a set of paths, returned in *MERGEINFO_CATALOG.
+   If the mergeinfo for any path is inherited and VALIDATE_INHERITED_MERGEINFO
+   is true, then the mergeinfo for that path in *MERGEINFO_CATALOG will only
+   contain path-revs that actually exist in repository.  Returned values are
+   allocated in POOL, while temporary values are allocated in a sub-pool. */
 static svn_error_t *
 get_mergeinfos_for_paths(svn_fs_root_t *root,
                          svn_mergeinfo_catalog_t *mergeinfo_catalog,
                          const apr_array_header_t *paths,
                          svn_mergeinfo_inheritance_t inherit,
+                         svn_boolean_t validate_inherited_mergeinfo,
                          svn_boolean_t include_descendants,
                          apr_pool_t *pool)
 {
@@ -5431,6 +5561,7 @@ get_mergeinfos_for_paths(svn_fs_root_t *
   for (i = 0; i < paths->nelts; i++)
     {
       svn_mergeinfo_t path_mergeinfo;
+      svn_boolean_t inherited;
       struct get_mergeinfo_for_path_baton gmfp_args;
       const char *path = APR_ARRAY_IDX(paths, i, const char *);
 
@@ -5440,6 +5571,7 @@ get_mergeinfos_for_paths(svn_fs_root_t *
 
       /* Get the mergeinfo for PATH itself. */
       gmfp_args.mergeinfo = &path_mergeinfo;
+      gmfp_args.inherited = &inherited;
       gmfp_args.root = root;
       gmfp_args.path = path;
       gmfp_args.inherit = inherit;
@@ -5448,9 +5580,16 @@ get_mergeinfos_for_paths(svn_fs_root_t *
                                      txn_body_get_mergeinfo_for_path,
                                      &gmfp_args, FALSE, iterpool));
       if (path_mergeinfo)
-        apr_hash_set(result_catalog, apr_pstrdup(pool, path),
-                     APR_HASH_KEY_STRING,
-                     path_mergeinfo);
+        {
+          if (inherited && validate_inherited_mergeinfo)
+            SVN_ERR(svn_fs_base__validate_mergeinfo(&path_mergeinfo, root->fs,
+                                                    path_mergeinfo, pool,
+                                                    iterpool));
+
+          apr_hash_set(result_catalog, apr_pstrdup(pool, path),
+                       APR_HASH_KEY_STRING,
+                       path_mergeinfo);
+        }
 
       /* If we're including descendants, do so. */
       if (include_descendants)
@@ -5493,6 +5632,7 @@ base_get_mergeinfo(svn_mergeinfo_catalog
                    svn_fs_root_t *root,
                    const apr_array_header_t *paths,
                    svn_mergeinfo_inheritance_t inherit,
+                   svn_boolean_t validate_inherited_mergeinfo,
                    svn_boolean_t include_descendants,
                    apr_pool_t *pool)
 {
@@ -5506,10 +5646,11 @@ base_get_mergeinfo(svn_mergeinfo_catalog
 
   /* Retrieve a path -> mergeinfo mapping. */
   return get_mergeinfos_for_paths(root, catalog, paths,
-                                  inherit, include_descendants,
-                                  pool);
+                                  inherit, validate_inherited_mergeinfo,
+                                  include_descendants, pool);
 }
 
+
 
 /* Creating root objects.  */
 

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/tree.h
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/tree.h?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/tree.h (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_base/tree.h Thu Dec  2 20:55:08 2010
@@ -95,6 +95,14 @@ svn_error_t *svn_fs_base__get_path_creat
                                                trail_t *trail,
                                                apr_pool_t *pool);
 
+/* Implements svn_fs_validate_mergeinfo. */
+svn_error_t *
+svn_fs_base__validate_mergeinfo(svn_mergeinfo_t *validated_mergeinfo,
+                                svn_fs_t *fs,
+                                svn_mergeinfo_t mergeinfo,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool);
+
 /* ### Experimental obliterate-like-deltify - see implementation. */
 svn_error_t *
 svn_fs_base__obliterate_rep(svn_fs_t *fs,

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/caching.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/caching.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/caching.c Thu Dec  2 20:55:08 2010
@@ -119,7 +119,7 @@ manifest_serialize(char **data,
 {
   apr_array_header_t *manifest = in;
 
-  *data_len = sizeof(apr_off_t) *manifest->nelts;
+  *data_len = sizeof(apr_off_t) * manifest->nelts;
   *data = apr_palloc(pool, *data_len);
   memcpy(*data, manifest->elts, *data_len);
 
@@ -134,10 +134,10 @@ manifest_deserialize(void **out,
                      apr_pool_t *pool)
 {
   apr_array_header_t *manifest = apr_array_make(pool,
-                                                data_len / sizeof(apr_off_t),
-                                                sizeof(apr_off_t));
+                                       (int) (data_len / sizeof(apr_off_t)),
+                                       sizeof(apr_off_t));
   memcpy(manifest->elts, data, data_len);
-  manifest->nelts = data_len / sizeof(apr_off_t);
+  manifest->nelts = (int) (data_len / sizeof(apr_off_t));
   *out = manifest;
 
   return SVN_NO_ERROR;

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/dag.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/dag.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/dag.c Thu Dec  2 20:55:08 2010
@@ -29,7 +29,6 @@
 #include "svn_pools.h"
 
 #include "dag.h"
-#include "err.h"
 #include "fs.h"
 #include "key-gen.h"
 #include "fs_fs.h"
@@ -395,7 +394,7 @@ make_entry(dag_node_t **child_p,
   /* Create the new node's NODE-REVISION */
   memset(&new_noderev, 0, sizeof(new_noderev));
   new_noderev.kind = is_dir ? svn_node_dir : svn_node_file;
-  new_noderev.created_path = svn_uri_join(parent_path, name, pool);
+  new_noderev.created_path = svn_fspath__join(parent_path, name, pool);
 
   SVN_ERR(get_node_revision(&parent_noderev, parent, pool));
   new_noderev.copyroot_path = apr_pstrdup(pool,
@@ -688,7 +687,7 @@ svn_fs_fs__dag_clone_child(dag_node_t **
       noderev->predecessor_id = svn_fs_fs__id_copy(cur_entry->id, pool);
       if (noderev->predecessor_count != -1)
         noderev->predecessor_count++;
-      noderev->created_path = svn_uri_join(parent_path, name, pool);
+      noderev->created_path = svn_fspath__join(parent_path, name, pool);
 
       SVN_ERR(svn_fs_fs__create_successor(&new_node_id, fs, cur_entry->id,
                                           noderev, copy_id, txn_id, pool));
@@ -1257,7 +1256,7 @@ svn_fs_fs__dag_copy(dag_node_t *to_node,
       if (to_noderev->predecessor_count != -1)
         to_noderev->predecessor_count++;
       to_noderev->created_path =
-        svn_uri_join(svn_fs_fs__dag_get_created_path(to_node), entry,
+        svn_fspath__join(svn_fs_fs__dag_get_created_path(to_node), entry,
                      pool);
       to_noderev->copyfrom_path = apr_pstrdup(pool, from_path);
       to_noderev->copyfrom_rev = from_rev;

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs.c Thu Dec  2 20:55:08 2010
@@ -34,7 +34,6 @@
 #include "svn_version.h"
 #include "svn_pools.h"
 #include "fs.h"
-#include "err.h"
 #include "fs_fs.h"
 #include "tree.h"
 #include "lock.h"
@@ -160,7 +159,8 @@ static fs_vtable_t fs_vtable = {
   svn_fs_fs__unlock,
   svn_fs_fs__get_lock,
   svn_fs_fs__get_locks,
-  fs_set_errcall
+  fs_set_errcall,
+  svn_fs_fs__validate_mergeinfo,
 };
 
 

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs.h?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs.h Thu Dec  2 20:55:08 2010
@@ -132,7 +132,6 @@ extern "C" {
    relate to a particular transaction in a filesystem (as identified
    by transaction id and filesystem UUID).  Objects of this type are
    allocated in their own subpool of the common pool. */
-struct fs_fs_shared_txn_data_t;
 typedef struct fs_fs_shared_txn_data_t
 {
   /* The next transaction in the list, or NULL if there is no following
@@ -171,7 +170,7 @@ typedef struct fs_fs_shared_txn_data_t
 /* Private FSFS-specific data shared between all svn_fs_t objects that
    relate to a particular filesystem, as identified by filesystem UUID.
    Objects of this type are allocated in the common pool. */
-typedef struct
+typedef struct fs_fs_shared_data_t
 {
   /* A list of shared transaction objects for each transaction that is
      currently active, or NULL if none are.  All access to this list,
@@ -203,7 +202,7 @@ typedef struct
 } fs_fs_shared_data_t;
 
 /* Private (non-shared) FSFS-specific data for each svn_fs_t object. */
-typedef struct
+typedef struct fs_fs_data_t
 {
   /* The format number of this FS. */
   int format;
@@ -268,7 +267,7 @@ typedef struct
 
 
 /*** Filesystem Transaction ***/
-typedef struct
+typedef struct transaction_t
 {
   /* property list (const char * name, svn_string_t * value).
      may be NULL if there are no properties.  */
@@ -291,7 +290,7 @@ typedef struct
 /*** Representation ***/
 /* If you add fields to this, check to see if you need to change
  * svn_fs_fs__rep_copy. */
-typedef struct
+typedef struct representation_t
 {
   /* Checksums for the contents produced by this representation.
      This checksum is for the contents the rep shows to consumers,
@@ -338,7 +337,7 @@ typedef struct
 /*** Node-Revision ***/
 /* If you add fields to this, check to see if you need to change
  * copy_node_revision in dag.c. */
-typedef struct
+typedef struct node_revision_t
 {
   /* node kind */
   svn_node_kind_t kind;
@@ -388,7 +387,7 @@ typedef struct
 
 
 /*** Change ***/
-typedef struct
+typedef struct change_t
 {
   /* Path of the change. */
   const char *path;

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs_fs.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs_fs.c Thu Dec  2 20:55:08 2010
@@ -51,7 +51,6 @@
 #include "svn_ctype.h"
 
 #include "fs.h"
-#include "err.h"
 #include "tree.h"
 #include "lock.h"
 #include "key-gen.h"
@@ -1214,6 +1213,28 @@ update_min_unpacked_revprop(svn_fs_t *fs
                                pool);
 }
 
+/* Create a new SQLite database for storing the revprops in filesystem FS.
+ * Leave the DB open and set *SDB to its handle.  Also create the "min
+ * unpacked revprop" file. */
+static svn_error_t *
+create_packed_revprops_db(svn_sqlite__db_t **sdb,
+                          svn_fs_t *fs,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
+{
+  SVN_ERR(svn_io_file_create(path_min_unpacked_revprop(fs, scratch_pool),
+                             "0\n", scratch_pool));
+  SVN_ERR(svn_sqlite__open(sdb,
+                           svn_dirent_join_many(scratch_pool, fs->path,
+                                                PATH_REVPROPS_DIR,
+                                                PATH_REVPROPS_DB,
+                                                NULL),
+                           svn_sqlite__mode_rwcreate, statements,
+                           0, NULL, result_pool, scratch_pool));
+  SVN_ERR(svn_sqlite__exec_statements(*sdb, STMT_CREATE_SCHEMA));
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 get_youngest(svn_revnum_t *youngest_p, const char *fs_path, apr_pool_t *pool);
 
@@ -1310,13 +1331,11 @@ upgrade_body(void *baton, apr_pool_t *po
     case svn_node_file:
       break;
     default:
-      return svn_error_return(svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
-                                                _("'%s' is not a regular file."
-                                                  " Please move it out of "
-                                                  "the way and try again"),
-                                                svn_dirent_join(fs->path,
-                                                                PATH_CONFIG,
-                                                                pool)));
+      return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
+                               _("'%s' is not a regular file."
+                                 " Please move it out of "
+                                 "the way and try again"),
+                               svn_dirent_join(fs->path, PATH_CONFIG, pool));
     }
 
   /* If we're already up-to-date, there's nothing else to be done here. */
@@ -1351,19 +1370,7 @@ upgrade_body(void *baton, apr_pool_t *po
      and create the database. */
   if (format < SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT)
     {
-      SVN_ERR(svn_io_file_create(path_min_unpacked_revprop(fs, pool), "0\n",
-                                 pool));
-
-      SVN_ERR(svn_sqlite__open(&ffd->revprop_db, svn_dirent_join_many(
-                                                          pool, fs->path,
-                                                          PATH_REVPROPS_DIR,
-                                                          PATH_REVPROPS_DB,
-                                                          NULL),
-                               svn_sqlite__mode_rwcreate, statements,
-                               0, NULL,
-                               fs->pool, pool));
-      SVN_ERR(svn_sqlite__exec_statements(ffd->revprop_db,
-                                          STMT_CREATE_SCHEMA));
+      SVN_ERR(create_packed_revprops_db(&ffd->revprop_db, fs, fs->pool, pool));
     }
 
   /* Bump the format file. */
@@ -1894,23 +1901,46 @@ open_pack_or_rev_file(apr_file_t **file,
                       svn_revnum_t rev,
                       apr_pool_t *pool)
 {
+  fs_fs_data_t *ffd = fs->fsap_data;
   svn_error_t *err;
   const char *path;
+  svn_boolean_t retry = FALSE;
 
-  err = svn_fs_fs__path_rev_absolute(&path, fs, rev, pool);
+  do
+    {
+      err = svn_fs_fs__path_rev_absolute(&path, fs, rev, pool);
 
-  if (! err)
-    err = svn_io_file_open(file, path,
-                           APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool);
+      /* open the revision file in buffered r/o mode */
+      if (! err)
+        err = svn_io_file_open(file, path,
+                              APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool);
 
-  if (err && APR_STATUS_IS_ENOENT(err->apr_err))
-    {
-      svn_error_clear(err);
-      return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
-                               _("No such revision %ld"), rev);
+      if (err && APR_STATUS_IS_ENOENT(err->apr_err)
+      	  && ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)
+        {
+          /* Could not open the file. This may happen if the
+           * file once existed but got packed later. */
+          svn_error_clear(err);
+
+          /* if that was our 2nd attempt, leave it at that. */
+          if (retry)
+            return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+                                    _("No such revision %ld"), rev);
+
+          /* We failed for the first time. Refresh cache & retry. */
+          SVN_ERR(update_min_unpacked_rev(fs, pool));
+
+          retry = TRUE;
+        }
+      else
+        {
+          /* the file exists but something prevented us from opnening it */
+          return svn_error_return(err);
+        }
     }
+  while (err);
 
-  return svn_error_return(err);
+  return SVN_NO_ERROR;
 }
 
 /* Given REV in FS, set *REV_OFFSET to REV's offset in the packed file.
@@ -2142,6 +2172,16 @@ read_rep_offsets(representation_t **rep_
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+err_dangling_id(svn_fs_t *fs, const svn_fs_id_t *id)
+{
+  svn_string_t *id_str = svn_fs_fs__id_unparse(id, fs->pool);
+  return svn_error_createf
+    (SVN_ERR_FS_ID_NOT_FOUND, 0,
+     _("Reference to non-existent node '%s' in filesystem '%s'"),
+     id_str->data, fs->path);
+}
+
 /* Get the node-revision for the node ID in FS.
    Set *NODEREV_P to the new node-revision structure, allocated in POOL.
    See svn_fs_fs__get_node_revision, which wraps this and adds another
@@ -2175,7 +2215,7 @@ get_node_revision_body(node_revision_t *
       if (APR_STATUS_IS_ENOENT(err->apr_err))
         {
           svn_error_clear(err);
-          return svn_fs_fs__err_dangling_id(fs, id);
+          return svn_error_return(err_dangling_id(fs, id));
         }
 
       return svn_error_return(err);
@@ -6496,6 +6536,7 @@ svn_fs_fs__create(svn_fs_t *fs,
                                                         pool),
                                         pool));
 
+  /* Create the revprops directory. */
   if (ffd->max_files_per_dir)
     SVN_ERR(svn_io_make_dir_recursively(path_revprops_shard(fs, 0, pool),
                                         pool));
@@ -6505,21 +6546,10 @@ svn_fs_fs__create(svn_fs_t *fs,
                                                         pool),
                                         pool));
 
-  /* Create the revprops directory. */
+  /* Write the min unpacked revprop file, and create the database. */
   if (format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT)
     {
-      SVN_ERR(svn_io_file_create(path_min_unpacked_revprop(fs, pool), "0\n",
-                                 pool));
-      SVN_ERR(svn_sqlite__open(&ffd->revprop_db, svn_dirent_join_many(
-                                                    pool, path,
-                                                    PATH_REVPROPS_DIR,
-                                                    PATH_REVPROPS_DB,
-                                                    NULL),
-                               svn_sqlite__mode_rwcreate, statements,
-                               0, NULL,
-                               fs->pool, pool));
-      SVN_ERR(svn_sqlite__exec_statements(ffd->revprop_db,
-                                          STMT_CREATE_SCHEMA));
+      SVN_ERR(create_packed_revprops_db(&ffd->revprop_db, fs, fs->pool, pool));
     }
 
   /* Create the transaction directory. */
@@ -6924,15 +6954,41 @@ recover_body(void *baton, apr_pool_t *po
   SVN_ERR(svn_io_check_path(path_revprops(fs, max_rev, pool),
                             &youngest_revprops_kind, pool));
   if (youngest_revprops_kind == svn_node_none)
-    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                             _("Revision %ld has a revs file but no "
-                               "revprops file"),
-                             max_rev);
+    {
+      svn_boolean_t uhohs = TRUE;
+
+      /* No file?  Hrm... maybe that's because this repository is
+         packed and the youngest revision is in the revprops.db
+         file?  We can at least see if that's a possibility.
+
+         ### TODO: Could we check for revprops in the revprops.db?
+         ###       What if rNNN legitimately has no revprops? */
+      if (ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT)
+        {
+          svn_revnum_t min_unpacked_revprop;
+          const char *min_unpacked_revprop_path =
+            svn_dirent_join(fs->path, PATH_MIN_UNPACKED_REVPROP, pool);
+
+          SVN_ERR(read_min_unpacked_rev(&min_unpacked_revprop,
+                                        min_unpacked_revprop_path, pool));
+          if (min_unpacked_revprop == (max_rev + 1))
+            uhohs = FALSE;
+        }
+      if (uhohs)
+        {
+          return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                                   _("Revision %ld has a revs file but no "
+                                     "revprops file"),
+                                   max_rev);
+        }
+    }
   else if (youngest_revprops_kind != svn_node_file)
-    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                             _("Revision %ld has a non-file where its "
-                               "revprops file should be"),
-                             max_rev);
+    {
+      return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                               _("Revision %ld has a non-file where its "
+                                 "revprops file should be"),
+                               max_rev);
+    }
 
   /* Now store the discovered youngest revision, and the next IDs if
      relevant, in a new 'current' file. */
@@ -7009,7 +7065,7 @@ svn_fs_fs__set_uuid(svn_fs_t *fs,
    permissions as FS->path.*/
 svn_error_t *
 svn_fs_fs__ensure_dir_exists(const char *path,
-                             svn_fs_t *fs,
+                             const char *fs_path,
                              apr_pool_t *pool)
 {
   svn_error_t *err = svn_io_dir_make(path, APR_OS_DEFAULT, pool);
@@ -7022,7 +7078,7 @@ svn_fs_fs__ensure_dir_exists(const char 
 
   /* We successfully created a new directory.  Dup the permissions
      from FS->path. */
-  return svn_io_copy_perms(path, fs->path, pool);
+  return svn_io_copy_perms(path, fs_path, pool);
 }
 
 /* Set *NODE_ORIGINS to a hash mapping 'const char *' node IDs to
@@ -7094,7 +7150,7 @@ set_node_origins_for_file(svn_fs_t *fs,
   SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_dirent_join(fs->path,
                                                        PATH_NODE_ORIGINS_DIR,
                                                        pool),
-                                       fs, pool));
+                                       fs->path, pool));
 
   /* Read the previously existing origins (if any), and merge our
      update with it. */
@@ -7550,8 +7606,8 @@ pack_shard(const char *revs_dir,
   SVN_ERR(svn_io_set_file_read_only(manifest_file_path, FALSE, pool));
 
   /* Update the min-unpacked-rev file to reflect our newly packed shard.
-   * (ffd->min_unpacked_rev will be updated by open_pack_or_rev_file().)
-   */
+   * (This doesn't update ffd->min_unpacked_rev.  That will be updated by
+   * update_min_unpacked_rev() when necessary.) */
   final_path = svn_dirent_join(fs_path, PATH_MIN_UNPACKED_REV, iterpool);
   SVN_ERR(svn_stream_open_unique(&tmp_stream, &tmp_path, fs_path,
                                    svn_io_file_del_none, iterpool, iterpool));
@@ -7618,9 +7674,8 @@ pack_revprop_shard(svn_fs_t *fs,
       SVN_ERR(svn_sqlite__insert(NULL, stmt));
     }
 
-  /* Update the min-unpacked-rev file to reflect our newly packed shard.
-   * (ffd->min_unpacked_rev will be updated by open_pack_or_rev_file().)
-   */
+  /* Update the min-unpacked-revprop file to reflect our newly packed shard.
+   * (This doesn't update ffd->min_unpacked_revprop.) */
   final_path = svn_dirent_join(fs_path, PATH_MIN_UNPACKED_REVPROP, iterpool);
   SVN_ERR(svn_stream_open_unique(&tmp_stream, &tmp_path, fs_path,
                                  svn_io_file_del_none, iterpool, iterpool));

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs_fs.h?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/fs_fs.h Thu Dec  2 20:55:08 2010
@@ -26,7 +26,10 @@
 #include "fs.h"
 
 /* Open the fsfs filesystem pointed to by PATH and associate it with
-   filesystem object FS.  Use POOL for temporary allocations. */
+   filesystem object FS.  Use POOL for temporary allocations.
+
+   ### Some parts of *FS must have been initialized beforehand; some parts
+       (including FS->path) are initialized by this function. */
 svn_error_t *svn_fs_fs__open(svn_fs_t *fs,
                              const char *path,
                              apr_pool_t *pool);
@@ -336,7 +339,10 @@ svn_error_t *svn_fs_fs__reserve_copy_id(
                                         apr_pool_t *pool);
 
 /* Create a fs_fs fileysystem referenced by FS at path PATH.  Get any
-   temporary allocations from POOL. */
+   temporary allocations from POOL.
+
+   ### Some parts of *FS must have been initialized beforehand; some parts
+       (including FS->path) are initialized by this function. */
 svn_error_t *svn_fs_fs__create(svn_fs_t *fs,
                                const char *path,
                                apr_pool_t *pool);
@@ -401,8 +407,12 @@ svn_error_t *svn_fs_fs__move_into_place(
                                         const char *perms_reference,
                                         apr_pool_t *pool);
 
-/* Sets *PATH to the path of REV in FS, whether in a pack file or not.
-   Allocate in POOL. */
+/* Set *PATH to the path of REV in FS, whether in a pack file or not.
+   Allocate *PATH in POOL.
+
+   Note: If the caller does not have the write lock on FS, then the path is
+   not guaranteed to remain correct after the function returns, because the
+   revision might become packed just after this call. */
 svn_error_t *
 svn_fs_fs__path_rev_absolute(const char **path,
                              svn_fs_t *fs,
@@ -486,9 +496,9 @@ svn_error_t *svn_fs_fs__txn_prop(svn_str
                                  const char *propname, apr_pool_t *pool);
 
 /* If directory PATH does not exist, create it and give it the same
-   permissions as FS->path.*/
+   permissions as FS_PATH.*/
 svn_error_t *svn_fs_fs__ensure_dir_exists(const char *path,
-                                          svn_fs_t *fs,
+                                          const char *fs_path,
                                           apr_pool_t *pool);
 
 /* Update the node origin index for FS, recording the mapping from

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/lock.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/lock.c Thu Dec  2 20:55:08 2010
@@ -36,7 +36,6 @@
 
 #include "lock.h"
 #include "tree.h"
-#include "err.h"
 #include "fs_fs.h"
 #include "../libsvn_fs/fs-loader.h"
 
@@ -108,17 +107,28 @@ hash_fetch(apr_hash_t *hash,
 }
 
 
+/* SVN_ERR_FS_CORRUPT: the lockfile for PATH in FS is corrupt.  */
+static svn_error_t *
+err_corrupt_lockfile(const char *fs_path, const char *path)
+{
+  return
+    svn_error_createf(
+     SVN_ERR_FS_CORRUPT, 0,
+     _("Corrupt lockfile for path '%s' in filesystem '%s'"),
+     path, fs_path);
+}
+
 
 /*** Digest file handling functions. ***/
 
 /* Return the path of the lock/entries file for which DIGEST is the
    hashed repository relative path. */
 static const char *
-digest_path_from_digest(svn_fs_t *fs,
+digest_path_from_digest(const char *fs_path,
                         const char *digest,
                         apr_pool_t *pool)
 {
-  return svn_dirent_join_many(pool, fs->path, PATH_LOCKS_DIR,
+  return svn_dirent_join_many(pool, fs_path, PATH_LOCKS_DIR,
                               apr_pstrmemdup(pool, digest, DIGEST_SUBDIR_LEN),
                               digest, NULL);
 }
@@ -128,12 +138,12 @@ digest_path_from_digest(svn_fs_t *fs,
    PATH, where PATH is the path to the lock file or lock entries file
    in FS. */
 static const char *
-digest_path_from_path(svn_fs_t *fs,
+digest_path_from_path(const char *fs_path,
                       const char *path,
                       apr_pool_t *pool)
 {
   const char *digest = make_digest(path, pool);
-  return svn_dirent_join_many(pool, fs->path, PATH_LOCKS_DIR,
+  return svn_dirent_join_many(pool, fs_path, PATH_LOCKS_DIR,
                               apr_pstrmemdup(pool, digest, DIGEST_SUBDIR_LEN),
                               digest, NULL);
 }
@@ -142,12 +152,15 @@ digest_path_from_path(svn_fs_t *fs,
 /* Write to DIGEST_PATH a representation of CHILDREN (which may be
    empty, if the versioned path in FS represented by DIGEST_PATH has
    no children) and LOCK (which may be NULL if that versioned path is
-   lock itself locked).  Use POOL for all allocations. */
+   lock itself locked).  Set the permissions of DIGEST_PATH to those of
+   PERMS_REFERENCE.  Use POOL for all allocations.
+ */
 static svn_error_t *
 write_digest_file(apr_hash_t *children,
                   svn_lock_t *lock,
-                  svn_fs_t *fs,
+                  const char *fs_path,
                   const char *digest_path,
+                  const char *perms_reference,
                   apr_pool_t *pool)
 {
   svn_error_t *err = SVN_NO_ERROR;
@@ -155,12 +168,11 @@ write_digest_file(apr_hash_t *children,
   apr_hash_index_t *hi;
   apr_hash_t *hash = apr_hash_make(pool);
   const char *tmp_path;
-  const char *rev_0_path;
 
-  SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_dirent_join(fs->path, PATH_LOCKS_DIR,
-                                                       pool), fs, pool));
+  SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_dirent_join(fs_path, PATH_LOCKS_DIR,
+                                                       pool), fs_path, pool));
   SVN_ERR(svn_fs_fs__ensure_dir_exists(svn_dirent_dirname(digest_path, pool),
-                                       fs, pool));
+                                       fs_path, pool));
 
   if (lock)
     {
@@ -212,8 +224,8 @@ write_digest_file(apr_hash_t *children,
 
   SVN_ERR(svn_stream_close(stream));
   SVN_ERR(svn_io_file_rename(tmp_path, digest_path, pool));
-  SVN_ERR(svn_fs_fs__path_rev_absolute(&rev_0_path, fs, 0, pool));
-  return svn_io_copy_perms(rev_0_path, digest_path, pool);
+  SVN_ERR(svn_io_copy_perms(perms_reference, digest_path, pool));
+  return SVN_NO_ERROR;
 }
 
 
@@ -224,7 +236,7 @@ write_digest_file(apr_hash_t *children,
 static svn_error_t *
 read_digest_file(apr_hash_t **children_p,
                  svn_lock_t **lock_p,
-                 svn_fs_t *fs,
+                 const char *fs_path,
                  const char *digest_path,
                  apr_pool_t *pool)
 {
@@ -275,17 +287,17 @@ read_digest_file(apr_hash_t **children_p
       lock->path = path;
 
       if (! ((lock->token = hash_fetch(hash, TOKEN_KEY, pool))))
-        return svn_fs_fs__err_corrupt_lockfile(fs, path);
+        return svn_error_return(err_corrupt_lockfile(fs_path, path));
 
       if (! ((lock->owner = hash_fetch(hash, OWNER_KEY, pool))))
-        return svn_fs_fs__err_corrupt_lockfile(fs, path);
+        return svn_error_return(err_corrupt_lockfile(fs_path, path));
 
       if (! ((val = hash_fetch(hash, IS_DAV_COMMENT_KEY, pool))))
-        return svn_fs_fs__err_corrupt_lockfile(fs, path);
+        return svn_error_return(err_corrupt_lockfile(fs_path, path));
       lock->is_dav_comment = (val[0] == '1');
 
       if (! ((val = hash_fetch(hash, CREATION_DATE_KEY, pool))))
-        return svn_fs_fs__err_corrupt_lockfile(fs, path);
+        return svn_error_return(err_corrupt_lockfile(fs_path, path));
       SVN_ERR(svn_time_from_cstring(&(lock->creation_date), val, pool));
 
       if ((val = hash_fetch(hash, EXPIRATION_DATE_KEY, pool)))
@@ -318,10 +330,16 @@ read_digest_file(apr_hash_t **children_p
      schema-supporting paths) ***/
 
 
-/* Write LOCK in FS to the actual OS filesystem. */
+/* Write LOCK in FS to the actual OS filesystem.
+
+   Use PERMS_REFERENCE for the permissions of any digest files.
+   
+   Note: this takes an FS_PATH because it's called from the hotcopy logic.
+ */
 static svn_error_t *
-set_lock(svn_fs_t *fs,
+set_lock(const char *fs_path,
          svn_lock_t *lock,
+         const char *perms_reference,
          apr_pool_t *pool)
 {
   svn_stringbuf_t *this_path = svn_stringbuf_create(lock->path, pool);
@@ -344,10 +362,10 @@ set_lock(svn_fs_t *fs,
 
       /* Calculate the DIGEST_PATH for the currently FS path, and then
          get its DIGEST_FILE basename. */
-      digest_path = digest_path_from_path(fs, this_path->data, subpool);
+      digest_path = digest_path_from_path(fs_path, this_path->data, subpool);
       digest_file = svn_dirent_basename(digest_path, subpool);
 
-      SVN_ERR(read_digest_file(&this_children, &this_lock, fs,
+      SVN_ERR(read_digest_file(&this_children, &this_lock, fs_path,
                                digest_path, subpool));
 
       /* We're either writing a new lock (first time through only) or
@@ -367,8 +385,8 @@ set_lock(svn_fs_t *fs,
           apr_hash_set(this_children, lock_digest_path,
                        APR_HASH_KEY_STRING, (void *)1);
         }
-      SVN_ERR(write_digest_file(this_children, this_lock, fs,
-                                digest_path, subpool));
+      SVN_ERR(write_digest_file(this_children, this_lock, fs_path,
+                                digest_path, perms_reference, subpool));
 
       /* Prep for next iteration, or bail if we're done. */
       if (svn_dirent_is_root(this_path->data, this_path->len))
@@ -406,10 +424,10 @@ delete_lock(svn_fs_t *fs,
 
       /* Calculate the DIGEST_PATH for the currently FS path, and then
          get its DIGEST_FILE basename. */
-      digest_path = digest_path_from_path(fs, this_path->data, subpool);
+      digest_path = digest_path_from_path(fs->path, this_path->data, subpool);
       digest_file = svn_dirent_basename(digest_path, subpool);
 
-      SVN_ERR(read_digest_file(&this_children, &this_lock, fs,
+      SVN_ERR(read_digest_file(&this_children, &this_lock, fs->path,
                                digest_path, subpool));
 
       /* Delete the lock (first time through only). */
@@ -431,8 +449,10 @@ delete_lock(svn_fs_t *fs,
         }
       else
         {
-          SVN_ERR(write_digest_file(this_children, this_lock, fs,
-                                    digest_path, subpool));
+          const char *rev_0_path;
+          SVN_ERR(svn_fs_fs__path_rev_absolute(&rev_0_path, fs, 0, pool));
+          SVN_ERR(write_digest_file(this_children, this_lock, fs->path,
+                                    digest_path, rev_0_path, subpool));
         }
 
       /* Prep for next iteration, or bail if we're done. */
@@ -458,9 +478,9 @@ get_lock(svn_lock_t **lock_p,
          apr_pool_t *pool)
 {
   svn_lock_t *lock;
-  const char *digest_path = digest_path_from_path(fs, path, pool);
+  const char *digest_path = digest_path_from_path(fs->path, path, pool);
 
-  SVN_ERR(read_digest_file(NULL, &lock, fs, digest_path, pool));
+  SVN_ERR(read_digest_file(NULL, &lock, fs->path, digest_path, pool));
   if (! lock)
     return SVN_FS__ERR_NO_SUCH_LOCK(fs, path, pool);
 
@@ -513,43 +533,82 @@ get_lock_helper(svn_fs_t *fs,
 }
 
 
-/* A recursive function that calls GET_LOCKS_FUNC/GET_LOCKS_BATON for
-   all locks in and under PATH in FS.
-   HAVE_WRITE_LOCK should be true if the caller (directly or indirectly)
-   has the FS write lock. */
+/* Baton for locks_walker(). */
+struct walk_locks_baton {
+  svn_fs_get_locks_callback_t get_locks_func;
+  void *get_locks_baton;
+  svn_fs_t *fs;
+};
+
+/* Implements walk_digests_callback_t. */
 static svn_error_t *
-walk_digest_files(svn_fs_t *fs,
-                  const char *digest_path,
-                  svn_fs_get_locks_callback_t get_locks_func,
-                  void *get_locks_baton,
-                  svn_boolean_t have_write_lock,
-                  apr_pool_t *pool)
+locks_walker(void *baton,
+             const char *fs_path,
+             const char *digest_path,
+             apr_hash_t *children,
+             svn_lock_t *lock,
+             svn_boolean_t have_write_lock,
+             apr_pool_t *pool)
 {
-  apr_hash_t *children;
-  svn_lock_t *lock;
-  apr_hash_index_t *hi;
-  apr_pool_t *subpool;
+  struct walk_locks_baton *wlb = baton;
 
-  /* First, send up any locks in the current digest file. */
-  SVN_ERR(read_digest_file(&children, &lock, fs, digest_path, pool));
   if (lock)
     {
       /* Don't report an expired lock. */
       if (lock->expiration_date == 0
           || (apr_time_now() <= lock->expiration_date))
         {
-          if (get_locks_func)
-            SVN_ERR(get_locks_func(get_locks_baton, lock, pool));
+          if (wlb->get_locks_func)
+            SVN_ERR(wlb->get_locks_func(wlb->get_locks_baton, lock, pool));
         }
       else
         {
           /* Only remove the lock if we have the write lock.
              Read operations shouldn't change the filesystem. */
           if (have_write_lock)
-            SVN_ERR(delete_lock(fs, lock, pool));
+            SVN_ERR(delete_lock(wlb->fs, lock, pool));
         }
     }
 
+  return SVN_NO_ERROR;
+}
+
+/* Callback type for walk_digest_files().
+ * 
+ * CHILDREN and LOCK come from a read_digest_file(digest_path) call.
+ */
+typedef svn_error_t *(*walk_digests_callback_t)(void *baton,
+                                                const char *fs_path,
+                                                const char *digest_path,
+                                                apr_hash_t *children,
+                                                svn_lock_t *lock,
+                                                svn_boolean_t have_write_lock,
+                                                apr_pool_t *pool);
+
+/* A recursive function that calls WALK_DIGESTS_FUNC/WALK_DIGESTS_BATON for
+   all lock digest files in and under PATH in FS.
+   HAVE_WRITE_LOCK should be true if the caller (directly or indirectly)
+   has the FS write lock. */
+static svn_error_t *
+walk_digest_files(const char *fs_path,
+                  const char *digest_path,
+                  walk_digests_callback_t walk_digests_func,
+                  void *walk_digests_baton,
+                  svn_boolean_t have_write_lock,
+                  apr_pool_t *pool) 
+{
+  apr_hash_index_t *hi;
+  apr_hash_t *children;
+  apr_pool_t *subpool;
+  svn_lock_t *lock;
+
+  /* First, send up any locks in the current digest file. */
+  SVN_ERR(read_digest_file(&children, &lock, fs_path, digest_path, pool));
+
+  SVN_ERR(walk_digests_func(walk_digests_baton, fs_path, digest_path,
+                            children, lock,
+                            have_write_lock, pool));
+
   /* Now, recurse on this thing's child entries (if any; bail otherwise). */
   if (! apr_hash_count(children))
     return SVN_NO_ERROR;
@@ -559,13 +618,31 @@ walk_digest_files(svn_fs_t *fs,
       const char *digest = svn__apr_hash_index_key(hi);
       svn_pool_clear(subpool);
       SVN_ERR(walk_digest_files
-              (fs, digest_path_from_digest(fs, digest, subpool),
-               get_locks_func, get_locks_baton, have_write_lock, subpool));
+              (fs_path, digest_path_from_digest(fs_path, digest, subpool),
+               walk_digests_func, walk_digests_baton, have_write_lock, subpool));
     }
   svn_pool_destroy(subpool);
   return SVN_NO_ERROR;
 }
 
+/* A recursive function that calls GET_LOCKS_FUNC/GET_LOCKS_BATON for
+   all locks in and under PATH in FS.
+   HAVE_WRITE_LOCK should be true if the caller (directly or indirectly)
+   has the FS write lock. */
+static svn_error_t *
+walk_locks(svn_fs_t *fs,
+           const char *digest_path,
+           svn_fs_get_locks_callback_t get_locks_func,
+           void *get_locks_baton,
+           svn_boolean_t have_write_lock,
+           apr_pool_t *pool)
+{
+  struct walk_locks_baton wlb = { get_locks_func, get_locks_baton, fs };
+  SVN_ERR(walk_digest_files(fs->path, digest_path, locks_walker, &wlb,
+                            have_write_lock, pool));
+  return SVN_NO_ERROR;
+}
+
 
 /* Utility function:  verify that a lock can be used.  Interesting
    errors returned from this function:
@@ -625,9 +702,9 @@ svn_fs_fs__allow_locked_operation(const 
   if (recurse)
     {
       /* Discover all locks at or below the path. */
-      const char *digest_path = digest_path_from_path(fs, path, pool);
-      SVN_ERR(walk_digest_files(fs, digest_path, get_locks_callback,
-                                fs, have_write_lock, pool));
+      const char *digest_path = digest_path_from_path(fs->path, path, pool);
+      SVN_ERR(walk_locks(fs, digest_path, get_locks_callback,
+                         fs, have_write_lock, pool));
     }
   else
     {
@@ -667,6 +744,7 @@ lock_body(void *baton, apr_pool_t *pool)
   svn_lock_t *lock;
   svn_fs_root_t *root;
   svn_revnum_t youngest;
+  const char *rev_0_path;
 
   /* Until we implement directory locks someday, we only allow locks
      on files or non-existent paths. */
@@ -766,7 +844,8 @@ lock_body(void *baton, apr_pool_t *pool)
   lock->is_dav_comment = lb->is_dav_comment;
   lock->creation_date = apr_time_now();
   lock->expiration_date = lb->expiration_date;
-  SVN_ERR(set_lock(lb->fs, lock, pool));
+  SVN_ERR(svn_fs_fs__path_rev_absolute(&rev_0_path, lb->fs, 0, pool));
+  SVN_ERR(set_lock(lb->fs->path, lock, rev_0_path, pool));
   *lb->lock_p = lock;
 
   return SVN_NO_ERROR;
@@ -945,7 +1024,7 @@ get_locks_filter_func(void *baton,
   else if ((b->requested_depth == svn_depth_files) ||
            (b->requested_depth == svn_depth_immediates))
     {
-      const char *rel_uri = svn_uri_is_child(b->path, lock->path, pool);
+      const char *rel_uri = svn_fspath__is_child(b->path, lock->path, pool);
       if (rel_uri && (svn_path_component_count(rel_uri) == 1))
         SVN_ERR(b->get_locks_func(b->get_locks_baton, lock, pool));
     }
@@ -973,7 +1052,8 @@ svn_fs_fs__get_locks(svn_fs_t *fs,
   glfb.get_locks_baton = get_locks_baton;
 
   /* Get the top digest path in our tree of interest, and then walk it. */
-  digest_path = digest_path_from_path(fs, path, pool);
-  return walk_digest_files(fs, digest_path, get_locks_filter_func, &glfb,
-                           FALSE, pool);
+  digest_path = digest_path_from_path(fs->path, path, pool);
+  SVN_ERR(walk_locks(fs, digest_path, get_locks_filter_func, &glfb,
+                     FALSE, pool));
+  return SVN_NO_ERROR;
 }

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/tree.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/tree.c Thu Dec  2 20:55:08 2010
@@ -51,7 +51,6 @@
 #include "svn_props.h"
 
 #include "fs.h"
-#include "err.h"
 #include "key-gen.h"
 #include "dag.h"
 #include "lock.h"
@@ -413,7 +412,7 @@ parent_path_path(parent_path_t *parent_p
   if (parent_path->parent)
     path_so_far = parent_path_path(parent_path->parent, pool);
   return parent_path->entry
-    ? svn_uri_join(path_so_far, parent_path->entry, pool)
+    ? svn_fspath__join(path_so_far, parent_path->entry, pool)
     : path_so_far;
 }
 
@@ -618,7 +617,7 @@ open_path(parent_path_t **parent_path_p,
       entry = svn_fs__next_entry_name(&next, rest, pool);
 
       /* Calculate the path traversed thus far. */
-      path_so_far = svn_uri_join(path_so_far, entry, pool);
+      path_so_far = svn_fspath__join(path_so_far, entry, pool);
 
       if (*entry == '\0')
         {
@@ -802,8 +801,8 @@ make_path_mutable(svn_fs_root_t *root,
 
 
 /* Open the node identified by PATH in ROOT.  Set DAG_NODE_P to the
- *node we find, allocated in POOL.  Return the error
- *SVN_ERR_FS_NOT_FOUND if this node doesn't exist. */
+   node we find, allocated in POOL.  Return the error
+   SVN_ERR_FS_NOT_FOUND if this node doesn't exist. */
 static svn_error_t *
 get_dag(dag_node_t **dag_node_p,
         svn_fs_root_t *root,
@@ -1134,7 +1133,7 @@ fs_props_changed(svn_boolean_t *changed_
 
 /* Merges and commits. */
 
-/* Set ARGS->node to the root node of ARGS->root.  */
+/* Set *NODE to the root node of ROOT.  */
 static svn_error_t *
 get_root(dag_node_t **node, svn_fs_root_t *root, apr_pool_t *pool)
 {
@@ -1556,13 +1555,16 @@ merge(svn_stringbuf_t *conflict_p,
   return SVN_NO_ERROR;
 }
 
-/* Merge changes between an ancestor and BATON->source_node into
-   BATON->txn.  The ancestor is either BATON->ancestor_node, or if
-   that is null, BATON->txn's base node.
-
-   If the merge is successful, BATON->txn's base will become
-   BATON->source_node, and its root node will have a new ID, a
-   successor of BATON->source_node. */
+/* Merge changes between an ancestor and SOURCE_NODE into
+   TXN.  The ancestor is either ANCESTOR_NODE, or if
+   that is null, TXN's base node.
+
+   If the merge is successful, TXN's base will become
+   SOURCE_NODE, and its root node will have a new ID, a
+   successor of SOURCE_NODE.
+
+   If a conflict results, update *CONFLICT to the path in the txn that
+   conflicted; see the CONFLICT_P parameter of merge() for details. */
 static svn_error_t *
 merge_changes(dag_node_t *ancestor_node,
               dag_node_t *source_node,
@@ -1586,13 +1588,8 @@ merge_changes(dag_node_t *ancestor_node,
                        svn_fs_fs__dag_get_id(txn_root_node)))
     {
       /* If no changes have been made in TXN since its current base,
-         then it can't conflict with any changes since that base.  So
-         we just set *both* its base and root to source, making TXN
-         in effect a repeat of source. */
-
-      /* ### kff todo: this would, of course, be a mighty silly thing
-         for the caller to do, and we might want to consider whether
-         this response is really appropriate. */
+         then it can't conflict with any changes since that base.
+         The caller isn't supposed to call us in that case. */
       SVN_ERR_MALFUNCTION();
     }
   else
@@ -2981,7 +2978,7 @@ prev_location(const char **prev_path,
                          copy_root, copy_path, pool));
   if (strcmp(copy_path, path) != 0)
     remainder = svn_relpath_is_child(copy_path, path, pool);
-  *prev_path = svn_uri_join(copy_src_path, remainder, pool);
+  *prev_path = svn_fspath__join(copy_src_path, remainder, pool);
   *prev_rev = copy_src_rev;
   return SVN_NO_ERROR;
 }
@@ -3241,7 +3238,7 @@ history_prev(void *baton, apr_pool_t *po
           SVN_ERR(svn_fs_fs__dag_get_copyfrom_path(&copy_src, node, pool));
 
           dst_rev = copyroot_rev;
-          src_path = svn_uri_join(copy_src, remainder, pool);
+          src_path = svn_fspath__join(copy_src, remainder, pool);
         }
     }
 
@@ -3375,6 +3372,128 @@ assemble_history(svn_fs_t *fs,
 
 /* mergeinfo queries */
 
+
+/* Implements svn_fs_validate_mergeinfo. */
+svn_error_t *
+svn_fs_fs__validate_mergeinfo(svn_mergeinfo_t *validated_mergeinfo,
+                              svn_fs_t *fs,
+                              svn_mergeinfo_t mergeinfo,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool)
+{
+  svn_mergeinfo_t filtered_mergeinfo;
+  apr_hash_t *rev_to_sources;
+  apr_hash_index_t *hi;
+  apr_pool_t *iterpool;
+
+  /* A couple easy outs. */
+  if (mergeinfo == NULL)
+    {
+      *validated_mergeinfo = NULL;
+      return SVN_NO_ERROR;
+    }
+  else if (apr_hash_count(mergeinfo) == 0)
+    {
+      *validated_mergeinfo = apr_hash_make(result_pool);
+      return SVN_NO_ERROR;
+    }
+
+  filtered_mergeinfo = apr_hash_make(scratch_pool);
+  rev_to_sources = apr_hash_make(scratch_pool);
+
+  /* Since svn_fs_check_path needs an svn_fs_root_t based on a revision,
+     we convert MERGEINFO into a mapping of revisions to a hash of source
+     paths for efficiency. */
+  for (hi = apr_hash_first(scratch_pool, mergeinfo);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *path = svn__apr_hash_index_key(hi);
+      apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+      int i;
+
+      for (i = 0; i < rangelist->nelts; i++)
+        {
+          svn_merge_range_t *range =
+            APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
+          svn_revnum_t j;
+
+          for (j = range->start + 1; j <= range->end; j++)
+            {
+              apr_hash_t *paths_for_rev =
+                apr_hash_get(rev_to_sources, &j, sizeof(svn_revnum_t));
+
+              /* No hash associated with this rev yet? */
+              if (!paths_for_rev)
+                {
+                  svn_revnum_t *rev = apr_palloc(scratch_pool, sizeof(*rev));
+
+                  *rev = j;
+                  paths_for_rev = apr_hash_make(scratch_pool);
+                  apr_hash_set(rev_to_sources, rev,
+                               sizeof(svn_revnum_t), paths_for_rev);
+                }
+
+              apr_hash_set(paths_for_rev, path, APR_HASH_KEY_STRING, path);
+            }
+        }
+    }
+
+  iterpool = svn_pool_create(scratch_pool);
+
+  /* Validate the rev->source MERGEINFO equivalent hash, building the
+     validated mergeinfo as we go. */
+  for (hi = apr_hash_first(scratch_pool, rev_to_sources);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const svn_revnum_t *rev = svn__apr_hash_index_key(hi);
+      apr_hash_t *paths = svn__apr_hash_index_val(hi);
+      apr_pool_t *inner_iterpool;
+      apr_hash_index_t *hi2;
+      svn_node_kind_t kind;
+      svn_fs_root_t *mergeinfo_rev_root;
+
+      svn_pool_clear(iterpool);
+      inner_iterpool = svn_pool_create(iterpool);
+
+      SVN_ERR(svn_fs_fs__revision_root(&mergeinfo_rev_root, fs,
+                                       *rev, iterpool));
+
+       for (hi2 = apr_hash_first(iterpool, paths);
+            hi2;
+            hi2 = apr_hash_next(hi2))
+         {
+            const char *path = svn__apr_hash_index_key(hi2);
+ 
+            svn_pool_clear(inner_iterpool);
+            SVN_ERR(svn_fs_fs__check_path(&kind, mergeinfo_rev_root,
+                                          path, inner_iterpool));
+            if (kind == svn_node_none)
+              {
+                apr_hash_set(paths, path, APR_HASH_KEY_STRING, NULL);
+              }
+            else
+              {
+                svn_mergeinfo_t good_mergeinfo_fragment;
+                const char *mergeinfo_str =
+                  apr_psprintf(inner_iterpool, "%s:%ld", path, *rev);
+
+                SVN_ERR(svn_mergeinfo_parse(&good_mergeinfo_fragment,
+                                            mergeinfo_str, scratch_pool));
+                SVN_ERR(svn_mergeinfo_merge(filtered_mergeinfo,
+                                            good_mergeinfo_fragment,
+                                            scratch_pool));
+              }
+         }
+      svn_pool_destroy(inner_iterpool);
+    }
+
+  svn_pool_destroy(iterpool);
+  *validated_mergeinfo = svn_mergeinfo_dup(filtered_mergeinfo, result_pool);
+  return SVN_NO_ERROR;
+}
+
 /* DIR_DAG is a directory DAG node which has mergeinfo in its
    descendants.  This function iterates over its children.  For each
    child with immediate mergeinfo, it adds its mergeinfo to
@@ -3411,7 +3530,7 @@ crawl_directory_dag_for_mergeinfo(svn_fs
 
       svn_pool_clear(iterpool);
 
-      kid_path = svn_uri_join(this_path, dirent->name, iterpool);
+      kid_path = svn_fspath__join(this_path, dirent->name, iterpool);
       SVN_ERR(get_dag(&kid_dag, root, kid_path, iterpool));
 
       SVN_ERR(svn_fs_fs__dag_has_mergeinfo(&has_mergeinfo, kid_dag, iterpool));
@@ -3480,7 +3599,7 @@ append_to_merged_froms(svn_mergeinfo_t *
       apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
       char *newpath;
 
-      newpath = svn_uri_join(path, path_piece, pool);
+      newpath = svn_fspath__join(path, path_piece, pool);
       apr_hash_set(*output, newpath, APR_HASH_KEY_STRING,
                    svn_rangelist_dup(rangelist, pool));
     }
@@ -3490,14 +3609,17 @@ append_to_merged_froms(svn_mergeinfo_t *
 
 /* Calculates the mergeinfo for PATH under REV_ROOT using inheritance
    type INHERIT.  Returns it in *MERGEINFO, or NULL if there is none.
-   The result is allocated in RESULT_POOL; POOL is used for temporary
-   allocations.
+   If *MERGEINFO is inherited and VALIDATE_INHERITED_MERGEINFO is true,
+   then *MERGEINFO will only contain path-revs that actually exist in
+   repository.  The result is allocated in RESULT_POOL; POOL is used for
+   temporary allocations.
  */
 static svn_error_t *
 get_mergeinfo_for_path(svn_mergeinfo_t *mergeinfo,
                        svn_fs_root_t *rev_root,
                        const char *path,
                        svn_mergeinfo_inheritance_t inherit,
+                       svn_boolean_t validate_inherited_mergeinfo,
                        apr_pool_t *pool,
                        apr_pool_t *result_pool)
 {
@@ -3547,7 +3669,6 @@ get_mergeinfo_for_path(svn_mergeinfo_t *
           return SVN_NO_ERROR;
         }
     }
-  svn_pool_destroy(iterpool);
 
   SVN_ERR(svn_fs_fs__dag_get_proplist(&proplist, nearest_ancestor->node, pool));
   mergeinfo_string = apr_hash_get(proplist, SVN_PROP_MERGEINFO,
@@ -3561,6 +3682,7 @@ get_mergeinfo_for_path(svn_mergeinfo_t *
   if (nearest_ancestor == parent_path)
     {
       /* We can return this directly. */
+      svn_pool_destroy(iterpool);
       return svn_mergeinfo_parse(mergeinfo,
                                  mergeinfo_string->data,
                                  result_pool);
@@ -3582,12 +3704,18 @@ get_mergeinfo_for_path(svn_mergeinfo_t *
                                         NULL, SVN_INVALID_REVNUM,
                                         SVN_INVALID_REVNUM, pool));
 
-      return append_to_merged_froms(mergeinfo,
-                                    temp_mergeinfo,
-                                    parent_path_relpath(parent_path,
-                                                        nearest_ancestor,
-                                                        pool),
-                                    result_pool);
+      SVN_ERR(append_to_merged_froms(mergeinfo,
+                                     temp_mergeinfo,
+                                     parent_path_relpath(parent_path,
+                                                         nearest_ancestor,
+                                                         pool),
+                                     result_pool));
+
+      if (validate_inherited_mergeinfo)
+        SVN_ERR(svn_fs_fs__validate_mergeinfo(mergeinfo, rev_root->fs,
+                                              *mergeinfo, pool, iterpool));
+      svn_pool_destroy(iterpool);
+      return SVN_NO_ERROR;
     }
 }
 
@@ -3620,13 +3748,17 @@ add_descendant_mergeinfo(svn_mergeinfo_c
 
 
 /* Get the mergeinfo for a set of paths, returned in
-   *MERGEINFO_CATALOG.  Returned values are allocated in POOL, while
-   temporary values are allocated in a sub-pool. */
+   *MERGEINFO_CATALOG.  If the mergeinfo for any path is inherited
+   and VALIDATE_INHERITED_MERGEINFO is true, then the mergeinfo for
+   that path in *MERGEINFO_CATALOG will only contain path-revs that
+   actually exist in repository.  Returned values are allocated in
+   POOL, while temporary values are allocated in a sub-pool. */
 static svn_error_t *
 get_mergeinfos_for_paths(svn_fs_root_t *root,
                          svn_mergeinfo_catalog_t *mergeinfo_catalog,
                          const apr_array_header_t *paths,
                          svn_mergeinfo_inheritance_t inherit,
+                         svn_boolean_t validate_inherited_mergeinfo,
                          svn_boolean_t include_descendants,
                          apr_pool_t *pool)
 {
@@ -3642,7 +3774,8 @@ get_mergeinfos_for_paths(svn_fs_root_t *
       svn_pool_clear(iterpool);
 
       SVN_ERR(get_mergeinfo_for_path(&path_mergeinfo, root, path,
-                                     inherit, iterpool, pool));
+                                     inherit, validate_inherited_mergeinfo,
+                                     iterpool, pool));
       if (path_mergeinfo)
         apr_hash_set(result_catalog, path, APR_HASH_KEY_STRING,
                      path_mergeinfo);
@@ -3663,6 +3796,7 @@ fs_get_mergeinfo(svn_mergeinfo_catalog_t
                  svn_fs_root_t *root,
                  const apr_array_header_t *paths,
                  svn_mergeinfo_inheritance_t inherit,
+                 svn_boolean_t validate_inherited_mergeinfo,
                  svn_boolean_t include_descendants,
                  apr_pool_t *pool)
 {
@@ -3682,10 +3816,11 @@ fs_get_mergeinfo(svn_mergeinfo_catalog_t
 
   /* Retrieve a path -> mergeinfo hash mapping. */
   return get_mergeinfos_for_paths(root, catalog, paths,
-                                  inherit, include_descendants,
-                                  pool);
+                                  inherit, validate_inherited_mergeinfo,
+                                  include_descendants, pool);
 }
 
+
 /* The vtable associated with root objects. */
 static root_vtable_t root_vtable = {
   fs_paths_changed,
@@ -3715,7 +3850,7 @@ static root_vtable_t root_vtable = {
   fs_contents_changed,
   fs_get_file_delta_stream,
   fs_merge,
-  fs_get_mergeinfo
+  fs_get_mergeinfo,
 };
 
 /* Construct a new root object in FS, allocated from POOL.  */

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/tree.h
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/tree.h?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/tree.h (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_fs/tree.h Thu Dec  2 20:55:08 2010
@@ -58,6 +58,7 @@ svn_error_t *svn_fs_fs__commit_obliterat
 svn_error_t *svn_fs_fs__txn_root(svn_fs_root_t **root_p, svn_fs_txn_t *txn,
                                  apr_pool_t *pool);
 
+
 /* Set KIND_P to the node kind of the node at PATH in ROOT.
    Allocate the structure in POOL. */
 svn_error_t *
@@ -76,6 +77,14 @@ svn_fs_fs__node_created_rev(svn_revnum_t
                             const char *path,
                             apr_pool_t *pool);
 
+/* Implements svn_fs_validate_mergeinfo. */
+svn_error_t *
+svn_fs_fs__validate_mergeinfo(svn_mergeinfo_t *validated_mergeinfo,
+                              svn_fs_t *fs,
+                              svn_mergeinfo_t mergeinfo,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_ra/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_ra/deprecated.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_ra/deprecated.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_ra/deprecated.c Thu Dec  2 20:55:08 2010
@@ -418,3 +418,18 @@ svn_error_t *svn_ra_do_status(svn_ra_ses
                                     status_editor, status_baton, pool);
 }
 
+svn_error_t *svn_ra_get_mergeinfo(svn_ra_session_t *session,
+                                  svn_mergeinfo_catalog_t *catalog,
+                                  const apr_array_header_t *paths,
+                                  svn_revnum_t revision,
+                                  svn_mergeinfo_inheritance_t inherit,
+                                  svn_boolean_t include_descendants,
+                                  apr_pool_t *pool)
+{
+  svn_boolean_t validate_inherited_mergeinfo = FALSE;
+
+  return svn_error_return(svn_ra_get_mergeinfo2(session, catalog, paths,
+                          revision, inherit, &validate_inherited_mergeinfo,
+                          include_descendants, pool));
+}
+

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_ra/ra_loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_ra/ra_loader.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_ra/ra_loader.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_ra/ra_loader.c Thu Dec  2 20:55:08 2010
@@ -753,13 +753,14 @@ svn_error_t *svn_ra_get_dir2(svn_ra_sess
                                   path, revision, dirent_fields, pool);
 }
 
-svn_error_t *svn_ra_get_mergeinfo(svn_ra_session_t *session,
-                                  svn_mergeinfo_catalog_t *catalog,
-                                  const apr_array_header_t *paths,
-                                  svn_revnum_t revision,
-                                  svn_mergeinfo_inheritance_t inherit,
-                                  svn_boolean_t include_descendants,
-                                  apr_pool_t *pool)
+svn_error_t *svn_ra_get_mergeinfo2(svn_ra_session_t *session,
+                                   svn_mergeinfo_catalog_t *catalog,
+                                   const apr_array_header_t *paths,
+                                   svn_revnum_t revision,
+                                   svn_mergeinfo_inheritance_t inherit,
+                                   svn_boolean_t *validate_inherited_mergeinfo,
+                                   svn_boolean_t include_descendants,
+                                   apr_pool_t *pool)
 {
   svn_error_t *err;
   int i;
@@ -781,6 +782,7 @@ svn_error_t *svn_ra_get_mergeinfo(svn_ra
 
   return session->vtable->get_mergeinfo(session, catalog, paths,
                                         revision, inherit,
+                                        validate_inherited_mergeinfo,
                                         include_descendants, pool);
 }
 

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_ra/ra_loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_ra/ra_loader.h?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_ra/ra_loader.h (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_ra/ra_loader.h Thu Dec  2 20:55:08 2010
@@ -119,6 +119,7 @@ typedef struct svn_ra__vtable_t {
                                 const apr_array_header_t *paths,
                                 svn_revnum_t revision,
                                 svn_mergeinfo_inheritance_t inherit,
+                                svn_boolean_t *validate_inherited_mergeinfo,
                                 svn_boolean_t include_merged_revisions,
                                 apr_pool_t *pool);
   svn_error_t *(*do_update)(svn_ra_session_t *session,

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_local/ra_plugin.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_local/ra_plugin.c Thu Dec  2 20:55:08 2010
@@ -693,6 +693,7 @@ svn_ra_local__get_mergeinfo(svn_ra_sessi
                             const apr_array_header_t *paths,
                             svn_revnum_t revision,
                             svn_mergeinfo_inheritance_t inherit,
+                            svn_boolean_t *validate_inherited_mergeinfo,
                             svn_boolean_t include_descendants,
                             apr_pool_t *pool)
 {
@@ -709,9 +710,11 @@ svn_ra_local__get_mergeinfo(svn_ra_sessi
         svn_dirent_join(sess->fs_path->data, relative_path, pool);
     }
 
-  SVN_ERR(svn_repos_fs_get_mergeinfo(&tmp_catalog, sess->repos, abs_paths,
-                                     revision, inherit, include_descendants,
-                                     NULL, NULL, pool));
+  SVN_ERR(svn_repos_fs_get_mergeinfo2(&tmp_catalog, sess->repos, abs_paths,
+                                      revision, inherit,
+                                      *validate_inherited_mergeinfo,
+                                      include_descendants,
+                                      NULL, NULL, pool));
   if (apr_hash_count(tmp_catalog) > 0)
     SVN_ERR(svn_mergeinfo__remove_prefix_from_catalog(catalog,
                                                       tmp_catalog,
@@ -925,7 +928,7 @@ svn_ra_local__do_check_path(svn_ra_sessi
 {
   svn_ra_local__session_baton_t *sess = session->priv;
   svn_fs_root_t *root;
-  const char *abs_path = svn_uri_join(sess->fs_path->data, path, pool);
+  const char *abs_path = svn_fspath__join(sess->fs_path->data, path, pool);
 
   if (! SVN_IS_VALID_REVNUM(revision))
     SVN_ERR(svn_fs_youngest_rev(&revision, sess->fs, pool));

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_neon/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_neon/mergeinfo.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_neon/mergeinfo.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_neon/mergeinfo.c Thu Dec  2 20:55:08 2010
@@ -51,6 +51,7 @@ struct mergeinfo_baton
   svn_stringbuf_t *curr_path;
   svn_stringbuf_t *curr_info;
   svn_mergeinfo_catalog_t catalog;
+  svn_boolean_t validated_inherited_mergeinfo;
   svn_error_t *err;
 };
 
@@ -62,6 +63,8 @@ static const svn_ra_neon__xml_elm_t merg
       SVN_RA_NEON__XML_CDATA },
     { SVN_XML_NAMESPACE, SVN_DAV__MERGEINFO_INFO, ELEM_mergeinfo_info,
       SVN_RA_NEON__XML_CDATA },
+    { SVN_XML_NAMESPACE, SVN_DAV__VALIDATE_INHERITED,
+      ELEM_validate_inherited_mergeinfo, SVN_RA_NEON__XML_CDATA },
     { NULL }
   };
 
@@ -93,6 +96,10 @@ start_element(int *elem, void *baton, in
       svn_stringbuf_setempty(mb->curr_info);
       svn_stringbuf_setempty(mb->curr_path);
     }
+  else if (elm->id == ELEM_validate_inherited_mergeinfo)
+    {
+      mb->validated_inherited_mergeinfo = TRUE;
+    }
 
   SVN_ERR(mb->err);
 
@@ -163,6 +170,7 @@ svn_ra_neon__get_mergeinfo(svn_ra_sessio
                            const apr_array_header_t *paths,
                            svn_revnum_t revision,
                            svn_mergeinfo_inheritance_t inherit,
+                           svn_boolean_t *validate_inherited_mergeinfo,
                            svn_boolean_t include_descendants,
                            apr_pool_t *pool)
 {
@@ -194,6 +202,14 @@ svn_ra_neon__get_mergeinfo(svn_ra_sessio
                                         "</S:inherit>",
                                         svn_inheritance_to_word(inherit)));
 
+  if (*validate_inherited_mergeinfo)
+    {
+      /* Send it only if true; server will default to "no". */
+      svn_stringbuf_appendcstr(request_body,
+                               "<S:" SVN_DAV__VALIDATE_INHERITED ">yes"
+                               "</S:" SVN_DAV__VALIDATE_INHERITED ">");
+    }
+
   if (include_descendants)
     {
       /* Send it only if true; server will default to "no". */
@@ -224,6 +240,7 @@ svn_ra_neon__get_mergeinfo(svn_ra_sessio
   mb.curr_path = svn_stringbuf_create("", pool);
   mb.curr_info = svn_stringbuf_create("", pool);
   mb.catalog = apr_hash_make(pool);
+  mb.validated_inherited_mergeinfo = FALSE;
   mb.err = SVN_NO_ERROR;
 
   /* ras's URL may not exist in HEAD, and thus it's not safe to send
@@ -253,5 +270,7 @@ svn_ra_neon__get_mergeinfo(svn_ra_sessio
   if (mb.err == SVN_NO_ERROR && apr_hash_count(mb.catalog))
     *catalog = mb.catalog;
 
+  *validate_inherited_mergeinfo = mb.validated_inherited_mergeinfo;
+
   return mb.err;
 }

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_neon/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_neon/options.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_neon/options.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_neon/options.c Thu Dec  2 20:55:08 2010
@@ -395,12 +395,15 @@ svn_ra_neon__has_capability(svn_ra_sessi
              support mergeinfo. */
           svn_mergeinfo_catalog_t ignored;
           svn_error_t *err;
+          svn_boolean_t validate_inherited_mergeinfo = FALSE;
           apr_array_header_t *paths = apr_array_make(pool, 1,
                                                      sizeof(char *));
           APR_ARRAY_PUSH(paths, const char *) = "";
 
           err = svn_ra_neon__get_mergeinfo(session, &ignored, paths, 0,
-                                           FALSE, FALSE, pool);
+                                           FALSE,
+                                           &validate_inherited_mergeinfo,
+                                           FALSE, pool);
 
           if (err)
             {

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_neon/ra_neon.h
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_neon/ra_neon.h?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_neon/ra_neon.h (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_neon/ra_neon.h Thu Dec  2 20:55:08 2010
@@ -299,13 +299,15 @@ svn_error_t *svn_ra_neon__get_dir(svn_ra
 svn_error_t * svn_ra_neon__abort_commit(void *session_baton,
                                         void *edit_baton);
 
-svn_error_t * svn_ra_neon__get_mergeinfo(svn_ra_session_t *session,
-                                         apr_hash_t **mergeinfo,
-                                         const apr_array_header_t *paths,
-                                         svn_revnum_t revision,
-                                         svn_mergeinfo_inheritance_t inherit,
-                                         svn_boolean_t include_descendants,
-                                         apr_pool_t *pool);
+svn_error_t * svn_ra_neon__get_mergeinfo(
+  svn_ra_session_t *session,
+  apr_hash_t **mergeinfo,
+  const apr_array_header_t *paths,
+  svn_revnum_t revision,
+  svn_mergeinfo_inheritance_t inherit,
+  svn_boolean_t *validate_inherited_mergeinfo,
+  svn_boolean_t include_descendants,
+  apr_pool_t *pool);
 
 svn_error_t * svn_ra_neon__do_update(svn_ra_session_t *session,
                                      const svn_ra_reporter3_t **reporter,
@@ -859,7 +861,8 @@ enum {
   ELEM_mergeinfo_info,
   ELEM_has_children,
   ELEM_merged_revision,
-  ELEM_deleted_rev_report
+  ELEM_deleted_rev_report,
+  ELEM_validate_inherited_mergeinfo
 };
 
 /* ### docco */

Modified: subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_serf/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_serf/mergeinfo.c?rev=1041580&r1=1041579&r2=1041580&view=diff
==============================================================================
--- subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_serf/mergeinfo.c (original)
+++ subversion/branches/gpg-agent-password-store/subversion/libsvn_ra_serf/mergeinfo.c Thu Dec  2 20:55:08 2010
@@ -45,7 +45,8 @@ typedef enum {
   MERGEINFO_REPORT,
   MERGEINFO_ITEM,
   MERGEINFO_PATH,
-  MERGEINFO_INFO
+  MERGEINFO_INFO,
+  MERGEINFO_VALIDATED
 } mergeinfo_state_e;
 
 /* Baton for accumulating mergeinfo.  RESULT_CATALOG stores the final
@@ -62,6 +63,8 @@ typedef struct {
   const apr_array_header_t *paths;
   svn_revnum_t revision;
   svn_mergeinfo_inheritance_t inherit;
+  svn_boolean_t validate_inherited_mergeinfo;
+  svn_boolean_t validated_inherited_mergeinfo;
   svn_boolean_t include_descendants;
 } mergeinfo_context_t;
 
@@ -80,6 +83,11 @@ start_element(svn_ra_serf__xml_parser_t 
       svn_ra_serf__xml_push_state(parser, MERGEINFO_REPORT);
     }
   else if (state == MERGEINFO_REPORT &&
+           strcmp(name.name, SVN_DAV__VALIDATE_INHERITED) == 0)
+    {
+      svn_ra_serf__xml_push_state(parser, MERGEINFO_VALIDATED);
+    }
+  else if (state == MERGEINFO_REPORT &&
            strcmp(name.name, SVN_DAV__MERGEINFO_ITEM) == 0)
     {
       svn_ra_serf__xml_push_state(parser, MERGEINFO_ITEM);
@@ -169,6 +177,11 @@ cdata_handler(svn_ra_serf__xml_parser_t 
         svn_stringbuf_appendbytes(mergeinfo_ctx->curr_info, data, len);
       break;
 
+    case MERGEINFO_VALIDATED:
+      if (strncmp(data, "yes", 3) == 0)
+        mergeinfo_ctx->validated_inherited_mergeinfo = TRUE;
+      break;
+
     default:
       break;
     }
@@ -206,6 +219,13 @@ create_mergeinfo_body(serf_bucket_t **bk
                                    "yes", alloc);
     }
 
+  if (mergeinfo_ctx->validate_inherited_mergeinfo)
+    {
+      svn_ra_serf__add_tag_buckets(body_bkt, "S:"
+                                   SVN_DAV__VALIDATE_INHERITED,
+                                   "yes", alloc);
+    }
+
   if (mergeinfo_ctx->paths)
     {
       int i;
@@ -235,6 +255,7 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
                            const apr_array_header_t *paths,
                            svn_revnum_t revision,
                            svn_mergeinfo_inheritance_t inherit,
+                           svn_boolean_t *validate_inherited_mergeinfo,
                            svn_boolean_t include_descendants,
                            apr_pool_t *pool)
 {
@@ -264,6 +285,8 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
   mergeinfo_ctx->paths = paths;
   mergeinfo_ctx->revision = revision;
   mergeinfo_ctx->inherit = inherit;
+  mergeinfo_ctx->validate_inherited_mergeinfo = *validate_inherited_mergeinfo;
+  mergeinfo_ctx->validated_inherited_mergeinfo = FALSE;
   mergeinfo_ctx->include_descendants = include_descendants;
 
   handler = apr_pcalloc(pool, sizeof(*handler));
@@ -303,6 +326,9 @@ svn_ra_serf__get_mergeinfo(svn_ra_sessio
 
   SVN_ERR(err);
 
+  *validate_inherited_mergeinfo =
+    mergeinfo_ctx->validated_inherited_mergeinfo;
+
   if (mergeinfo_ctx->done && apr_hash_count(mergeinfo_ctx->result_catalog))
     *catalog = mergeinfo_ctx->result_catalog;