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 2013/11/27 12:52:46 UTC
svn commit: r1546002 [17/39] - in /subversion/branches/verify-keep-going: ./
build/ build/ac-macros/ build/generator/ build/generator/swig/
build/generator/templates/ build/win32/ contrib/client-side/emacs/
contrib/server-side/ contrib/server-side/svnc...
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/authz.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/authz.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/authz.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/authz.c Wed Nov 27 11:52:35 2013
@@ -26,6 +26,7 @@
#include <apr_pools.h>
#include <apr_file_io.h>
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_pools.h"
#include "svn_error.h"
@@ -35,6 +36,7 @@
#include "svn_config.h"
#include "svn_ctype.h"
#include "private/svn_fspath.h"
+#include "private/svn_repos_private.h"
#include "repos.h"
@@ -76,8 +78,8 @@ struct authz_validate_baton {
enumerator, if any. */
};
-/* Currently this structure is just a wrapper around a
- svn_config_t. */
+/* Currently this structure is just a wrapper around a svn_config_t.
+ Please update authz_pool if you modify this structure. */
struct svn_authz_t
{
svn_config_t *cfg;
@@ -351,7 +353,7 @@ authz_get_path_access(svn_config_t *cfg,
baton.user = user;
/* Try to locate a repository-specific block first. */
- qualified_path = apr_pstrcat(pool, repos_name, ":", path, (char *)NULL);
+ qualified_path = apr_pstrcat(pool, repos_name, ":", path, SVN_VA_NULL);
svn_config_enumerate2(cfg, qualified_path,
authz_parse_line, &baton, pool);
@@ -394,7 +396,7 @@ authz_get_tree_access(svn_config_t *cfg,
baton.required_access = required_access;
baton.repos_path = path;
baton.qualified_repos_path = apr_pstrcat(pool, repos_name,
- ":", path, (char *)NULL);
+ ":", path, SVN_VA_NULL);
/* Default to access granted if no rules say otherwise. */
baton.access = TRUE;
@@ -453,7 +455,7 @@ authz_get_any_access(svn_config_t *cfg,
baton.access = FALSE; /* Deny access by default. */
baton.repos_path = "/";
baton.qualified_repos_path = apr_pstrcat(pool, repos_name,
- ":/", (char *)NULL);
+ ":/", SVN_VA_NULL);
/* We could have used svn_config_enumerate2 for "repos_name:/".
* However, this requires access for root explicitly (which the user
@@ -748,9 +750,8 @@ static svn_boolean_t authz_validate_sect
}
-/* Walk the configuration in AUTHZ looking for any errors. */
-static svn_error_t *
-authz_validate(svn_authz_t *authz, apr_pool_t *pool)
+svn_error_t *
+svn_repos__authz_validate(svn_authz_t *authz, apr_pool_t *pool)
{
struct authz_validate_baton baton = { 0 };
@@ -771,13 +772,17 @@ authz_validate(svn_authz_t *authz, apr_p
*
* If DIRENT cannot be parsed as a config file then an error is returned. The
* contents of CFG_P is then undefined. If MUST_EXIST is TRUE, a missing
- * authz file is also an error.
+ * authz file is also an error. The CASE_SENSITIVE controls the lookup
+ * behavior for section and option names alike.
*
* SCRATCH_POOL will be used for temporary allocations. */
static svn_error_t *
-authz_retrieve_config_repo(svn_config_t **cfg_p, const char *dirent,
- svn_boolean_t must_exist,
- apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+authz_retrieve_config_repo(svn_config_t **cfg_p,
+ const char *dirent,
+ svn_boolean_t must_exist,
+ svn_boolean_t case_sensitive,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_error_t *err;
svn_repos_t *repos;
@@ -824,7 +829,8 @@ authz_retrieve_config_repo(svn_config_t
{
if (!must_exist)
{
- SVN_ERR(svn_config_create2(cfg_p, TRUE, TRUE, result_pool));
+ SVN_ERR(svn_config_create2(cfg_p, case_sensitive, case_sensitive,
+ result_pool));
return SVN_NO_ERROR;
}
else
@@ -842,7 +848,8 @@ authz_retrieve_config_repo(svn_config_t
}
SVN_ERR(svn_fs_file_contents(&contents, root, fs_path, scratch_pool));
- err = svn_config_parse(cfg_p, contents, TRUE, TRUE, result_pool);
+ err = svn_config_parse(cfg_p, contents, case_sensitive, case_sensitive,
+ result_pool);
/* Add the URL to the error stack since the parser doesn't have it. */
if (err != SVN_NO_ERROR)
@@ -853,23 +860,12 @@ authz_retrieve_config_repo(svn_config_t
return SVN_NO_ERROR;
}
-/* Given a PATH which might be a relative repo URL (^/), an absolute
- * local repo URL (file://), an absolute path outside of the repo
- * or a location in the Windows registry.
- *
- * Retrieve the configuration data that PATH points at and parse it into
- * CFG_P allocated in POOL.
- *
- * If PATH cannot be parsed as a config file then an error is returned. The
- * contents of CFG_P is then undefined. If MUST_EXIST is TRUE, a missing
- * authz file is also an error.
- *
- * REPOS_ROOT points at the root of the repos you are
- * going to apply the authz against, can be NULL if you are sure that you
- * don't have a repos relative URL in PATH. */
-static svn_error_t *
-authz_retrieve_config(svn_config_t **cfg_p, const char *path,
- svn_boolean_t must_exist, apr_pool_t *pool)
+svn_error_t *
+svn_repos__retrieve_config(svn_config_t **cfg_p,
+ const char *path,
+ svn_boolean_t must_exist,
+ svn_boolean_t case_sensitive,
+ apr_pool_t *pool)
{
if (svn_path_is_url(path))
{
@@ -880,8 +876,8 @@ authz_retrieve_config(svn_config_t **cfg
err = svn_uri_get_dirent_from_file_url(&dirent, path, scratch_pool);
if (err == SVN_NO_ERROR)
- err = authz_retrieve_config_repo(cfg_p, dirent, must_exist, pool,
- scratch_pool);
+ err = authz_retrieve_config_repo(cfg_p, dirent, must_exist,
+ case_sensitive, pool, scratch_pool);
/* Close the repos and streams we opened. */
svn_pool_destroy(scratch_pool);
@@ -891,7 +887,8 @@ authz_retrieve_config(svn_config_t **cfg
else
{
/* Outside of repo file or Windows registry*/
- SVN_ERR(svn_config_read3(cfg_p, path, must_exist, TRUE, TRUE, pool));
+ SVN_ERR(svn_config_read3(cfg_p, path, must_exist, case_sensitive,
+ case_sensitive, pool));
}
return SVN_NO_ERROR;
@@ -942,9 +939,11 @@ svn_repos__authz_read(svn_authz_t **auth
/* Load the authz file */
if (accept_urls)
- SVN_ERR(authz_retrieve_config(&authz->cfg, path, must_exist, pool));
+ SVN_ERR(svn_repos__retrieve_config(&authz->cfg, path, must_exist, TRUE,
+ pool));
else
- SVN_ERR(svn_config_read3(&authz->cfg, path, must_exist, TRUE, TRUE, pool));
+ SVN_ERR(svn_config_read3(&authz->cfg, path, must_exist, TRUE, TRUE,
+ pool));
if (groups_path)
{
@@ -953,8 +952,8 @@ svn_repos__authz_read(svn_authz_t **auth
/* Load the groups file */
if (accept_urls)
- SVN_ERR(authz_retrieve_config(&groups_cfg, groups_path, must_exist,
- pool));
+ SVN_ERR(svn_repos__retrieve_config(&groups_cfg, groups_path,
+ must_exist, TRUE, pool));
else
SVN_ERR(svn_config_read3(&groups_cfg, groups_path, must_exist,
TRUE, TRUE, pool));
@@ -971,7 +970,7 @@ svn_repos__authz_read(svn_authz_t **auth
}
/* Make sure there are no errors in the configuration. */
- SVN_ERR(authz_validate(authz, pool));
+ SVN_ERR(svn_repos__authz_validate(authz, pool));
*authz_p = authz;
return SVN_NO_ERROR;
@@ -1011,7 +1010,7 @@ svn_repos_authz_parse(svn_authz_t **auth
}
/* Make sure there are no errors in the configuration. */
- SVN_ERR(authz_validate(authz, pool));
+ SVN_ERR(svn_repos__authz_validate(authz, pool));
*authz_p = authz;
return SVN_NO_ERROR;
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/commit.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/commit.c Wed Nov 27 11:52:35 2013
@@ -26,6 +26,7 @@
#include <apr_pools.h>
#include <apr_file_io.h>
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_compat.h"
#include "svn_pools.h"
@@ -39,7 +40,6 @@
#include "svn_ctype.h"
#include "svn_props.h"
#include "svn_mergeinfo.h"
-#include "svn_private_config.h"
#include "repos.h"
@@ -1013,7 +1013,7 @@ ev2_check_authz(const struct ev2_baton *
return SVN_NO_ERROR;
if (relpath)
- fspath = apr_pstrcat(scratch_pool, "/", relpath, NULL);
+ fspath = apr_pstrcat(scratch_pool, "/", relpath, SVN_VA_NULL);
else
fspath = NULL;
@@ -1198,20 +1198,6 @@ move_cb(void *baton,
}
-/* This implements svn_editor_cb_rotate_t */
-static svn_error_t *
-rotate_cb(void *baton,
- const apr_array_header_t *relpaths,
- const apr_array_header_t *revisions,
- apr_pool_t *scratch_pool)
-{
- struct ev2_baton *eb = baton;
-
- SVN_ERR(svn_editor_rotate(eb->inner, relpaths, revisions));
- return SVN_NO_ERROR;
-}
-
-
/* This implements svn_editor_cb_complete_t */
static svn_error_t *
complete_cb(void *baton,
@@ -1333,7 +1319,6 @@ svn_repos__get_commit_ev2(svn_editor_t *
delete_cb,
copy_cb,
move_cb,
- rotate_cb,
complete_cb,
abort_cb
};
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/delta.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/delta.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/delta.c Wed Nov 27 11:52:35 2013
@@ -24,6 +24,7 @@
#include <apr_hash.h>
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_types.h"
#include "svn_delta.h"
@@ -33,7 +34,6 @@
#include "svn_repos.h"
#include "svn_pools.h"
#include "svn_props.h"
-#include "svn_private_config.h"
#include "repos.h"
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/deprecated.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/deprecated.c Wed Nov 27 11:52:35 2013
@@ -26,13 +26,12 @@
deprecated functions in this file. */
#define SVN_DEPRECATED
+#include "svn_private_config.h"
#include "svn_repos.h"
#include "svn_compat.h"
#include "svn_hash.h"
#include "svn_props.h"
-#include "svn_private_config.h"
-
#include "repos.h"
@@ -473,6 +472,30 @@ svn_repos_fs_get_locks(apr_hash_t **lock
/*** From logs.c ***/
svn_error_t *
+svn_repos_get_logs4(svn_repos_t *repos,
+ const apr_array_header_t *paths,
+ svn_revnum_t start,
+ svn_revnum_t end,
+ int limit,
+ svn_boolean_t discover_changed_paths,
+ svn_boolean_t strict_node_history,
+ svn_boolean_t include_merged_revisions,
+ const apr_array_header_t *revprops,
+ svn_repos_authz_func_t authz_read_func,
+ void *authz_read_baton,
+ svn_log_entry_receiver_t receiver,
+ void *receiver_baton,
+ apr_pool_t *pool)
+{
+ return svn_repos_get_logs5(repos, paths, start, end, limit,
+ discover_changed_paths, strict_node_history,
+ include_merged_revisions,
+ svn_move_behavior_no_moves, revprops,
+ authz_read_func, authz_read_baton,
+ receiver, receiver_baton, pool);
+}
+
+svn_error_t *
svn_repos_get_logs3(svn_repos_t *repos,
const apr_array_header_t *paths,
svn_revnum_t start,
@@ -740,6 +763,7 @@ svn_repos_verify_fs2(svn_repos_t *repos,
start_rev,
end_rev,
FALSE,
+ FALSE,
notify_func,
notify_baton,
cancel_func,
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/dump.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/dump.c Wed Nov 27 11:52:35 2013
@@ -38,12 +38,277 @@
#include "private/svn_mergeinfo_private.h"
#include "private/svn_fs_private.h"
+#include "private/svn_utf_private.h"
+#include "private/svn_cache.h"
#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
/*----------------------------------------------------------------------*/
+/* To be able to check whether a path exists in the current revision
+ (as changes come in), we need to track the relevant tree changes.
+
+ In particular, we remember deletions, additions and copies including
+ their copy-from info. Since the dump performs a pre-order tree walk,
+ we only need to store the data for the stack of parent folders.
+
+ The problem that we are trying to solve is that the dump receives
+ transforming operations whose validity depends on previous operations
+ in the same revision but cannot be checked against the final state
+ as stored in the repository as that is the state *after* we applied
+ the respective tree changes.
+
+ Note that the tracker functions don't perform any sanity or validity
+ checks. Those higher-level tests have to be done in the calling code.
+ However, there is no way to corrupt the data structure using the
+ provided functions.
+ */
+
+/* Single entry in the path tracker. Not all levels along the path
+ hierarchy do need to have an instance of this struct but only those
+ that got changed by a tree modification.
+
+ Please note that the path info in this struct is stored in re-usable
+ stringbuf objects such that we don't need to allocate more memory than
+ the longest path we encounter.
+ */
+typedef struct path_tracker_entry_t
+{
+ /* path in the current tree */
+ svn_stringbuf_t *path;
+
+ /* copy-from path (must be empty if COPYFROM_REV is SVN_INVALID_REVNUM) */
+ svn_stringbuf_t *copyfrom_path;
+
+ /* copy-from revision (SVN_INVALID_REVNUM for additions / replacements
+ that don't copy history, i.e. with no sub-tree) */
+ svn_revnum_t copyfrom_rev;
+
+ /* if FALSE, PATH has been deleted */
+ svn_boolean_t exists;
+} path_tracker_entry_t;
+
+/* Tracks all tree modifications above the current path.
+ */
+typedef struct path_tracker_t
+{
+ /* Container for all relevant tree changes in depth order.
+ May contain more entries than DEPTH to allow for reusing memory.
+ Only entries 0 .. DEPTH-1 are valid.
+ */
+ apr_array_header_t *stack;
+
+ /* Number of relevant entries in STACK. May be 0 */
+ int depth;
+
+ /* Revision that we current track. If DEPTH is 0, paths are exist in
+ REVISION exactly when they exist in REVISION-1. This applies only
+ to the current state of our tree walk.
+ */
+ svn_revnum_t revision;
+
+ /* Allocate container entries here. */
+ apr_pool_t *pool;
+} path_tracker_t;
+
+/* Return a new path tracker object for REVISION, allocated in POOL.
+ */
+static path_tracker_t *
+tracker_create(svn_revnum_t revision,
+ apr_pool_t *pool)
+{
+ path_tracker_t *result = apr_pcalloc(pool, sizeof(*result));
+ result->stack = apr_array_make(pool, 16, sizeof(path_tracker_entry_t));
+ result->revision = revision;
+ result->pool = pool;
+
+ return result;
+}
+
+/* Remove all entries from TRACKER that are not relevant to PATH anymore.
+ * If ALLOW_EXACT_MATCH is FALSE, keep only entries that pertain to
+ * parent folders but not to PATH itself.
+ *
+ * This internal function implicitly updates the tracker state during the
+ * tree by removing "past" entries. Other functions will add entries when
+ * we encounter a new tree change.
+ */
+static void
+tracker_trim(path_tracker_t *tracker,
+ const char *path,
+ svn_boolean_t allow_exact_match)
+{
+ /* remove everything that is unrelated to PATH.
+ Note that TRACKER->STACK is depth-ordered,
+ i.e. stack[N] is a (maybe indirect) parent of stack[N+1]
+ for N+1 < DEPTH.
+ */
+ for (; tracker->depth; --tracker->depth)
+ {
+ path_tracker_entry_t *parent = &APR_ARRAY_IDX(tracker->stack,
+ tracker->depth - 1,
+ path_tracker_entry_t);
+ const char *rel_path
+ = svn_dirent_skip_ancestor(parent->path->data, path);
+
+ /* always keep parents. Keep exact matches when allowed. */
+ if (rel_path && (allow_exact_match || *rel_path != '\0'))
+ break;
+ }
+}
+
+/* Using TRACKER, check what path at what revision in the repository must
+ be checked to decide that whether PATH exists. Return the info in
+ *ORIG_PATH and *ORIG_REV, respectively.
+
+ If the path is known to not exist, *ORIG_PATH will be NULL and *ORIG_REV
+ will be SVN_INVALID_REVNUM. If *ORIG_REV is SVN_INVALID_REVNUM, PATH
+ has just been added in the revision currently being tracked.
+
+ Use POOL for allocations. Note that *ORIG_PATH may be allocated in POOL,
+ a reference to internal data with the same lifetime as TRACKER or just
+ PATH.
+ */
+static void
+tracker_lookup(const char **orig_path,
+ svn_revnum_t *orig_rev,
+ path_tracker_t *tracker,
+ const char *path,
+ apr_pool_t *pool)
+{
+ tracker_trim(tracker, path, TRUE);
+ if (tracker->depth == 0)
+ {
+ /* no tree changes -> paths are the same as in the previous rev. */
+ *orig_path = path;
+ *orig_rev = tracker->revision - 1;
+ }
+ else
+ {
+ path_tracker_entry_t *parent = &APR_ARRAY_IDX(tracker->stack,
+ tracker->depth - 1,
+ path_tracker_entry_t);
+ if (parent->exists)
+ {
+ const char *rel_path
+ = svn_dirent_skip_ancestor(parent->path->data, path);
+
+ if (parent->copyfrom_rev != SVN_INVALID_REVNUM)
+ {
+ /* parent is a copy with history. Translate path. */
+ *orig_path = svn_dirent_join(parent->copyfrom_path->data,
+ rel_path, pool);
+ *orig_rev = parent->copyfrom_rev;
+ }
+ else if (*rel_path == '\0')
+ {
+ /* added in this revision with no history */
+ *orig_path = path;
+ *orig_rev = tracker->revision;
+ }
+ else
+ {
+ /* parent got added but not this path */
+ *orig_path = NULL;
+ *orig_rev = SVN_INVALID_REVNUM;
+ }
+ }
+ else
+ {
+ /* (maybe parent) path has been deleted */
+ *orig_path = NULL;
+ *orig_rev = SVN_INVALID_REVNUM;
+ }
+ }
+}
+
+/* Return a reference to the stack entry in TRACKER for PATH. If no
+ suitable entry exists, add one. Implicitly updates the tracked tree
+ location.
+
+ Only the PATH member of the result is being updated. All other members
+ will have undefined values.
+ */
+static path_tracker_entry_t *
+tracker_add_entry(path_tracker_t *tracker,
+ const char *path)
+{
+ path_tracker_entry_t *entry;
+ tracker_trim(tracker, path, FALSE);
+
+ if (tracker->depth == tracker->stack->nelts)
+ {
+ entry = apr_array_push(tracker->stack);
+ entry->path = svn_stringbuf_create_empty(tracker->pool);
+ entry->copyfrom_path = svn_stringbuf_create_empty(tracker->pool);
+ }
+ else
+ {
+ entry = &APR_ARRAY_IDX(tracker->stack, tracker->depth,
+ path_tracker_entry_t);
+ }
+
+ svn_stringbuf_set(entry->path, path);
+ ++tracker->depth;
+
+ return entry;
+}
+
+/* Update the TRACKER with a copy from COPYFROM_PATH@COPYFROM_REV to
+ PATH in the tracked revision.
+ */
+static void
+tracker_path_copy(path_tracker_t *tracker,
+ const char *path,
+ const char *copyfrom_path,
+ svn_revnum_t copyfrom_rev)
+{
+ path_tracker_entry_t *entry = tracker_add_entry(tracker, path);
+
+ svn_stringbuf_set(entry->copyfrom_path, copyfrom_path);
+ entry->copyfrom_rev = copyfrom_rev;
+ entry->exists = TRUE;
+}
+
+/* Update the TRACKER with a plain addition of PATH (without history).
+ */
+static void
+tracker_path_add(path_tracker_t *tracker,
+ const char *path)
+{
+ path_tracker_entry_t *entry = tracker_add_entry(tracker, path);
+
+ svn_stringbuf_setempty(entry->copyfrom_path);
+ entry->copyfrom_rev = SVN_INVALID_REVNUM;
+ entry->exists = TRUE;
+}
+
+/* Update the TRACKER with a replacement of PATH with a plain addition
+ (without history).
+ */
+static void
+tracker_path_replace(path_tracker_t *tracker,
+ const char *path)
+{
+ /* this will implicitly purge all previous sub-tree info from STACK.
+ Thus, no need to tack the deletion explicitly. */
+ tracker_path_add(tracker, path);
+}
+
+/* Update the TRACKER with a deletion of PATH.
+ */
+static void
+tracker_path_delete(path_tracker_t *tracker,
+ const char *path)
+{
+ path_tracker_entry_t *entry = tracker_add_entry(tracker, path);
+
+ svn_stringbuf_setempty(entry->copyfrom_path);
+ entry->copyfrom_rev = SVN_INVALID_REVNUM;
+ entry->exists = FALSE;
+}
+
/* Compute the delta between OLDROOT/OLDPATH and NEWROOT/NEWPATH and
store it into a new temporary file *TEMPFILE. OLDROOT may be NULL,
@@ -116,6 +381,9 @@ struct edit_baton
/* True if this "dump" is in fact a verify. */
svn_boolean_t verify;
+ /* True if checking UCS normalization during a verify. */
+ svn_boolean_t check_ucs_norm;
+
/* The first revision dumped in this dumpstream. */
svn_revnum_t oldest_dumped_rev;
@@ -130,6 +398,17 @@ struct edit_baton
/* reusable buffer for writing file contents */
char buffer[SVN__STREAM_CHUNK_SIZE];
apr_size_t bufsize;
+
+ /* map nodeID -> node kind. May be NULL.
+ The key is the string representation of the node ID given in
+ directory entries. If we find an entry in this cache, the
+ respective node has already been verified as readable and being
+ of the type stored as value in the cache. */
+ svn_cache__t *verified_dirents_cache;
+
+ /* Structure allows us to verify the paths currently being dumped.
+ If NULL, validity checks are being skipped. */
+ path_tracker_t *path_tracker;
};
struct dir_baton
@@ -159,6 +438,12 @@ struct dir_baton
really, they're all within this directory.) */
apr_hash_t *deleted_entries;
+ /* A flag indicating that new entries have been added to this
+ directory in this revision. Used to optimize detection of UCS
+ representation collisions; we will only check for that in
+ revisions where new names appear in the directory. */
+ svn_boolean_t check_name_collision;
+
/* pool to be used for deleting the hash items */
apr_pool_t *pool;
};
@@ -211,11 +496,199 @@ make_dir_baton(const char *path,
new_db->added = added;
new_db->written_out = FALSE;
new_db->deleted_entries = apr_hash_make(pool);
+ new_db->check_name_collision = FALSE;
new_db->pool = pool;
return new_db;
}
+static svn_error_t *
+fetch_kind_func(svn_node_kind_t *kind,
+ void *baton,
+ const char *path,
+ svn_revnum_t base_revision,
+ apr_pool_t *scratch_pool);
+
+/* Return an error when PATH in REVISION does not exist or is of a
+ different kind than EXPECTED_KIND. If the latter is svn_node_unknown,
+ skip that check. Use EB for context information. If REVISION is the
+ current revision, use EB's path tracker to follow renames, deletions,
+ etc.
+
+ Use SCRATCH_POOL for temporary allocations.
+ No-op if EB's path tracker has not been initialized.
+ */
+static svn_error_t *
+node_must_exist(struct edit_baton *eb,
+ const char *path,
+ svn_revnum_t revision,
+ svn_node_kind_t expected_kind,
+ apr_pool_t *scratch_pool)
+{
+ svn_node_kind_t kind = svn_node_none;
+
+ /* in case the caller is trying something stupid ... */
+ if (eb->path_tracker == NULL)
+ return SVN_NO_ERROR;
+
+ /* paths pertaining to the revision currently being processed must
+ be translated / checked using our path tracker. */
+ if (revision == eb->path_tracker->revision)
+ tracker_lookup(&path, &revision, eb->path_tracker, path, scratch_pool);
+
+ /* determine the node type (default: no such node) */
+ if (path)
+ SVN_ERR(fetch_kind_func(&kind, eb, path, revision, scratch_pool));
+
+ /* check results */
+ if (kind == svn_node_none)
+ return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
+ _("Path '%s' not found in r%ld."),
+ path, revision);
+
+ if (expected_kind != kind && expected_kind != svn_node_unknown)
+ return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+ _("Unexpected node kind %d for '%s' at r%ld. "
+ "Expected kind was %d."),
+ kind, path, revision, expected_kind);
+
+ return SVN_NO_ERROR;
+}
+
+/* Return an error when PATH exists in REVISION. Use EB for context
+ information. If REVISION is the current revision, use EB's path
+ tracker to follow renames, deletions, etc.
+
+ Use SCRATCH_POOL for temporary allocations.
+ No-op if EB's path tracker has not been initialized.
+ */
+static svn_error_t *
+node_must_not_exist(struct edit_baton *eb,
+ const char *path,
+ svn_revnum_t revision,
+ apr_pool_t *scratch_pool)
+{
+ svn_node_kind_t kind = svn_node_none;
+
+ /* in case the caller is trying something stupid ... */
+ if (eb->path_tracker == NULL)
+ return SVN_NO_ERROR;
+
+ /* paths pertaining to the revision currently being processed must
+ be translated / checked using our path tracker. */
+ if (revision == eb->path_tracker->revision)
+ tracker_lookup(&path, &revision, eb->path_tracker, path, scratch_pool);
+
+ /* determine the node type (default: no such node) */
+ if (path)
+ SVN_ERR(fetch_kind_func(&kind, eb, path, revision, scratch_pool));
+
+ /* check results */
+ if (kind != svn_node_none)
+ return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
+ _("Path '%s' exists in r%ld."),
+ path, revision);
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+check_ucs_normalization(const char *path,
+ svn_node_kind_t kind,
+ svn_repos_notify_func_t notify_func,
+ void *notify_baton,
+ apr_pool_t *scratch_pool)
+{
+ const char *const name = svn_relpath_basename(path, scratch_pool);
+ if (!svn_utf__is_normalized(name, scratch_pool))
+ {
+ svn_repos_notify_t *const notify =
+ svn_repos_notify_create(svn_repos_notify_warning, scratch_pool);
+ notify->warning = svn_repos_notify_warning_denormalized_name;
+ switch (kind)
+ {
+ case svn_node_dir:
+ notify->warning_str = apr_psprintf(
+ scratch_pool, _("Denormalized directory name '%s'"), path);
+ break;
+ case svn_node_file:
+ notify->warning_str = apr_psprintf(
+ scratch_pool, _("Denormalized file name '%s'"), path);
+ break;
+ default:
+ notify->warning_str = apr_psprintf(
+ scratch_pool, _("Denormalized entry name '%s'"), path);
+ }
+ notify_func(notify_baton, notify, scratch_pool);
+ }
+ return SVN_NO_ERROR;
+}
+
+
+/* Baton used by the check_mergeinfo_normalization hash iterator. */
+struct check_mergeinfo_normalization_baton
+{
+ const char* path;
+ apr_hash_t *normalized;
+ svn_membuf_t buffer;
+ svn_repos_notify_func_t notify_func;
+ void *notify_baton;
+};
+
+/* Hash iterator that verifies normalization and collision of paths in
+ an svn:mergeinfo property. */
+static svn_error_t *
+check_mergeinfo_normalization(void *baton, const void *key, apr_ssize_t klen,
+ void *val, apr_pool_t *pool)
+{
+ static const char unique[] = "unique";
+ static const char collision[] = "collision";
+
+ struct check_mergeinfo_normalization_baton *const check_baton = baton;
+
+ const char *const path = key;
+ const char *normpath;
+ const char *found;
+
+ SVN_ERR(svn_utf__normalize(&normpath, path, klen, &check_baton->buffer));
+
+ found = svn_hash_gets(check_baton->normalized, normpath);
+ if (!found)
+ {
+ if (0 != strcmp(path, normpath))
+ {
+ /* Report denormlized mergeinfo path */
+ svn_repos_notify_t *const notify =
+ svn_repos_notify_create(svn_repos_notify_warning, pool);
+ notify->warning = svn_repos_notify_warning_denormalized_mergeinfo;
+ notify->warning_str = apr_psprintf(
+ pool, _("Denormalized path '%s' in %s property of '%s'"),
+ path, SVN_PROP_MERGEINFO, check_baton->path);
+ check_baton->notify_func(check_baton->notify_baton, notify, pool);
+ }
+ svn_hash_sets(check_baton->normalized,
+ apr_pstrdup(pool, normpath), unique);
+ }
+ else if (found == collision)
+ /* Skip already reported collision */;
+ else
+ {
+ /* Report path collision in mergeinfo */
+ svn_repos_notify_t *const notify =
+ svn_repos_notify_create(svn_repos_notify_warning, pool);
+ notify->warning = svn_repos_notify_warning_mergeinfo_collision;
+ notify->warning_str = apr_psprintf(
+ pool, _("Duplicate representation of path '%s'"
+ " in %s property of '%s'"),
+ normpath, SVN_PROP_MERGEINFO, check_baton->path);
+ check_baton->notify_func(check_baton->notify_baton, notify, pool);
+ svn_hash_sets(check_baton->normalized,
+ apr_pstrdup(pool, normpath), collision);
+ }
+ return SVN_NO_ERROR;
+}
+
/* This helper is the main "meat" of the editor -- it does all the
work of writing a node record.
@@ -303,6 +776,11 @@ dump_node(struct edit_baton *eb,
if (action == svn_node_action_change)
{
+ if (eb->path_tracker)
+ SVN_ERR_W(node_must_exist(eb, path, eb->current_rev, kind, pool),
+ apr_psprintf(pool, _("Change invalid path '%s' in r%ld"),
+ path, eb->current_rev));
+
SVN_ERR(svn_stream_puts(eb->stream,
SVN_REPOS_DUMPFILE_NODE_ACTION ": change\n"));
@@ -321,8 +799,18 @@ dump_node(struct edit_baton *eb,
}
else if (action == svn_node_action_replace)
{
+ if (eb->path_tracker)
+ SVN_ERR_W(node_must_exist(eb, path, eb->current_rev,
+ svn_node_unknown, pool),
+ apr_psprintf(pool,
+ _("Replacing non-existent path '%s' in r%ld"),
+ path, eb->current_rev));
+
if (! is_copy)
{
+ if (eb->path_tracker)
+ tracker_path_replace(eb->path_tracker, path);
+
/* a simple delete+add, implied by a single 'replace' action. */
SVN_ERR(svn_stream_puts(eb->stream,
SVN_REPOS_DUMPFILE_NODE_ACTION
@@ -335,6 +823,20 @@ dump_node(struct edit_baton *eb,
}
else
{
+ if (eb->path_tracker)
+ {
+ SVN_ERR_W(node_must_exist(eb, compare_path, compare_rev,
+ kind, pool),
+ apr_psprintf(pool,
+ _("Replacing path '%s' in r%ld "
+ "with invalid path"),
+ path, eb->current_rev));
+
+ /* we will call dump_node again with an addition further
+ down the road */
+ tracker_path_delete(eb->path_tracker, path);
+ }
+
/* more complex: delete original, then add-with-history. */
/* the path & kind headers have already been printed; just
@@ -355,6 +857,14 @@ dump_node(struct edit_baton *eb,
}
else if (action == svn_node_action_delete)
{
+ if (eb->path_tracker)
+ {
+ SVN_ERR_W(node_must_exist(eb, path, eb->current_rev, kind, pool),
+ apr_psprintf(pool, _("Deleting invalid path '%s' in r%ld"),
+ path, eb->current_rev));
+ tracker_path_delete(eb->path_tracker, path);
+ }
+
SVN_ERR(svn_stream_puts(eb->stream,
SVN_REPOS_DUMPFILE_NODE_ACTION ": delete\n"));
@@ -365,11 +875,20 @@ dump_node(struct edit_baton *eb,
}
else if (action == svn_node_action_add)
{
+ if (eb->path_tracker)
+ SVN_ERR_W(node_must_not_exist(eb, path, eb->current_rev, pool),
+ apr_psprintf(pool,
+ _("Adding already existing path '%s' in r%ld"),
+ path, eb->current_rev));
+
SVN_ERR(svn_stream_puts(eb->stream,
SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
if (! is_copy)
{
+ if (eb->path_tracker)
+ tracker_path_add(eb->path_tracker, path);
+
/* Dump all contents for a simple 'add'. */
if (kind == svn_node_file)
must_dump_text = TRUE;
@@ -377,6 +896,18 @@ dump_node(struct edit_baton *eb,
}
else
{
+ if (eb->path_tracker)
+ {
+ SVN_ERR_W(node_must_exist(eb, compare_path, compare_rev,
+ kind, pool),
+ apr_psprintf(pool,
+ _("Copying from invalid path to "
+ "'%s' in r%ld"),
+ path, eb->current_rev));
+ tracker_path_copy(eb->path_tracker, path, compare_path,
+ compare_rev);
+ }
+
if (!eb->verify && cmp_rev < eb->oldest_dumped_rev
&& eb->notify_func)
{
@@ -504,6 +1035,33 @@ dump_node(struct edit_baton *eb,
}
}
+ /* If we're checking UCS normalization, also parse any changed
+ mergeinfo and warn about denormalized paths and name
+ collisions there. */
+ if (eb->verify && eb->check_ucs_norm && eb->notify_func)
+ {
+ /* N.B.: This hash lookup happens only once; the conditions
+ for verifying historic mergeinfo references and checking
+ UCS normalization are mutually exclusive. */
+ svn_string_t *mergeinfo_str = svn_hash_gets(prophash,
+ SVN_PROP_MERGEINFO);
+ if (mergeinfo_str)
+ {
+ svn_mergeinfo_t mergeinfo;
+ struct check_mergeinfo_normalization_baton check_baton;
+ check_baton.path = path;
+ check_baton.normalized = apr_hash_make(pool);
+ svn_membuf__create(&check_baton.buffer, 0, pool);
+ check_baton.notify_func = eb->notify_func;
+ check_baton.notify_baton = eb->notify_baton;
+ SVN_ERR(svn_mergeinfo_parse(&mergeinfo,
+ mergeinfo_str->data, pool));
+ SVN_ERR(svn_iter_apr_hash(NULL, mergeinfo,
+ check_mergeinfo_normalization,
+ &check_baton, pool));
+ }
+ }
+
if (eb->use_deltas && compare_root)
{
/* Fetch the old property hash to diff against and output a header
@@ -694,6 +1252,16 @@ add_directory(const char *path,
/* Delete the path, it's now been dumped. */
svn_hash_sets(pb->deleted_entries, path, NULL);
+ /* Check for UCS normalization and name clashes, but only if this is
+ actually a new name in the parent, not a replacement. */
+ if (!val && eb->verify && eb->check_ucs_norm && eb->notify_func)
+ {
+ pb->check_name_collision = TRUE;
+ SVN_ERR(check_ucs_normalization(
+ path, svn_node_dir,
+ eb->notify_func, eb->notify_baton, pool));
+ }
+
new_db->written_out = TRUE;
*child_baton = new_db;
@@ -793,6 +1361,16 @@ add_file(const char *path,
is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
pool));
+ /* Check for UCS normalization and name clashes, but only if this is
+ actually a new name in the parent, not a replacement. */
+ if (!val && eb->verify && eb->check_ucs_norm && eb->notify_func)
+ {
+ pb->check_name_collision = TRUE;
+ SVN_ERR(check_ucs_normalization(
+ path, svn_node_file,
+ eb->notify_func, eb->notify_baton, pool));
+ }
+
if (val)
/* delete the path, it's now been dumped. */
svn_hash_sets(pb->deleted_entries, path, NULL);
@@ -960,6 +1538,8 @@ get_dump_editor(const svn_delta_editor_t
svn_revnum_t oldest_dumped_rev,
svn_boolean_t use_deltas,
svn_boolean_t verify,
+ svn_boolean_t check_ucs_norm,
+ svn_cache__t *verified_dirents_cache,
apr_pool_t *pool)
{
/* Allocate an edit baton to be stored in every directory baton.
@@ -982,8 +1562,18 @@ get_dump_editor(const svn_delta_editor_t
eb->current_rev = to_rev;
eb->use_deltas = use_deltas;
eb->verify = verify;
+ eb->check_ucs_norm = check_ucs_norm;
eb->found_old_reference = found_old_reference;
eb->found_old_mergeinfo = found_old_mergeinfo;
+ eb->verified_dirents_cache = verified_dirents_cache;
+
+ /* In non-verification mode, we will allow anything to be dumped because
+ it might be an incremental dump with possible manual intervention.
+ Also, this might be the last resort when it comes to data recovery.
+
+ Else, make sure that all paths exists at their respective revisions.
+ */
+ eb->path_tracker = verify ? tracker_create(to_rev, pool) : NULL;
/* Set up the editor. */
dump_editor->open_root = open_root;
@@ -1180,7 +1770,8 @@ svn_repos_dump_fs3(svn_repos_t *repos,
"", stream, &found_old_reference,
&found_old_mergeinfo, NULL,
notify_func, notify_baton,
- start_rev, use_deltas_for_rev, FALSE, subpool));
+ start_rev, use_deltas_for_rev, FALSE, FALSE,
+ NULL, subpool));
/* Drive the editor in one way or another. */
SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, subpool));
@@ -1292,9 +1883,42 @@ verify_directory_entry(void *baton, cons
{
struct dir_baton *db = baton;
svn_fs_dirent_t *dirent = (svn_fs_dirent_t *)val;
- char *path = svn_relpath_join(db->path, (const char *)key, pool);
+ char *path;
apr_hash_t *dirents;
svn_filesize_t len;
+ svn_string_t *unparsed_id;
+
+ /* most directory entries will be unchanged from previous revs.
+ We should find those in the cache and they must match the
+ type defined in the DIRENT. */
+ if (db->edit_baton->verified_dirents_cache)
+ {
+ svn_node_kind_t *kind;
+ svn_boolean_t found;
+ unparsed_id = svn_fs_unparse_id(dirent->id, pool);
+
+ SVN_ERR(svn_cache__get((void **)&kind, &found,
+ db->edit_baton->verified_dirents_cache,
+ unparsed_id->data, pool));
+
+ if (found)
+ {
+ if (*kind == dirent->kind)
+ return SVN_NO_ERROR;
+ else
+ {
+ path = svn_relpath_join(db->path, (const char *)key, pool);
+
+ return
+ svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+ _("Unexpected node kind %d for '%s'. "
+ "Expected kind was %d."),
+ dirent->kind, path, *kind);
+ }
+ }
+ }
+
+ path = svn_relpath_join(db->path, (const char *)key, pool);
/* since we can't access the directory entries directly by their ID,
we need to navigate from the FS_ROOT to them (relatively expensive
@@ -1316,12 +1940,67 @@ verify_directory_entry(void *baton, cons
dirent->kind, path);
}
+ /* remember ID, kind pair */
+ if (db->edit_baton->verified_dirents_cache)
+ SVN_ERR(svn_cache__set(db->edit_baton->verified_dirents_cache,
+ unparsed_id->data, &dirent->kind, pool));
+
return SVN_NO_ERROR;
}
+/* Baton used by the check_name_collision hash iterator. */
+struct check_name_collision_baton
+{
+ struct dir_baton *dir_baton;
+ apr_hash_t *normalized;
+ svn_membuf_t buffer;
+};
+
+/* Scan the directory and report all entry names that differ only in
+ Unicode character representaiton. */
static svn_error_t *
-verify_close_directory(void *dir_baton,
- apr_pool_t *pool)
+check_name_collision(void *baton, const void *key, apr_ssize_t klen,
+ void *val, apr_pool_t *pool)
+{
+ static const char unique[] = "unique";
+ static const char collision[] = "collision";
+
+ struct check_name_collision_baton *const check_baton = baton;
+ const char *name;
+ const char *found;
+
+ SVN_ERR(svn_utf__normalize(&name, key, klen, &check_baton->buffer));
+
+ found = svn_hash_gets(check_baton->normalized, name);
+ if (!found)
+ svn_hash_sets(check_baton->normalized,
+ apr_pstrdup(pool, name), unique);
+ else if (found == collision)
+ /* Skip already reported collision */;
+ else
+ {
+ struct dir_baton *const db = check_baton->dir_baton;
+ struct edit_baton *const eb = db->edit_baton;
+ svn_repos_notify_t *notify;
+ const char* normpath;
+
+ svn_hash_sets(check_baton->normalized,
+ apr_pstrdup(pool, name), collision);
+ SVN_ERR(svn_utf__normalize(
+ &normpath, svn_relpath_join(db->path, name, pool),
+ SVN_UTF__UNKNOWN_LENGTH, &check_baton->buffer));
+ notify = svn_repos_notify_create(svn_repos_notify_warning, pool);
+ notify->warning = svn_repos_notify_warning_name_collision;
+ notify->warning_str = apr_psprintf(
+ pool, _("Duplicate representation of path '%s'"), normpath);
+ eb->notify_func(eb->notify_baton, notify, pool);
+ }
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+verify_close_directory(void *dir_baton, apr_pool_t *pool)
{
struct dir_baton *db = dir_baton;
apr_hash_t *dirents;
@@ -1329,6 +2008,17 @@ verify_close_directory(void *dir_baton,
db->path, pool));
SVN_ERR(svn_iter_apr_hash(NULL, dirents, verify_directory_entry,
dir_baton, pool));
+
+ if (db->check_name_collision)
+ {
+ struct check_name_collision_baton check_baton;
+ check_baton.dir_baton = db;
+ check_baton.normalized = apr_hash_make(pool);
+ svn_membuf__create(&check_baton.buffer, 0, pool);
+ SVN_ERR(svn_iter_apr_hash(NULL, dirents, check_name_collision,
+ &check_baton, pool));
+ }
+
return close_directory(dir_baton, pool);
}
@@ -1399,8 +2089,10 @@ verify_one_revision(svn_fs_t *fs,
svn_repos_notify_func_t notify_func,
void *notify_baton,
svn_revnum_t start_rev,
+ svn_boolean_t check_ucs_norm,
svn_cancel_func_t cancel_func,
void *cancel_baton,
+ svn_cache__t *verified_dirents_cache,
apr_pool_t *scratch_pool)
{
const svn_delta_editor_t *dump_editor;
@@ -1419,6 +2111,8 @@ verify_one_revision(svn_fs_t *fs,
notify_func, notify_baton,
start_rev,
FALSE, TRUE, /* use_deltas, verify */
+ check_ucs_norm,
+ verified_dirents_cache,
scratch_pool));
SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
dump_editor, dump_edit_baton,
@@ -1426,6 +2120,7 @@ verify_one_revision(svn_fs_t *fs,
&cancel_edit_baton,
scratch_pool));
SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, scratch_pool));
+ SVN_ERR(svn_fs_verify_root(to_root, scratch_pool));
SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
cancel_editor, cancel_edit_baton,
NULL, NULL, scratch_pool));
@@ -1497,11 +2192,36 @@ populate_summary(apr_array_header_t **er
APR_ARRAY_PUSH(*error_summary, struct error_list *) = el;
}
+/* cache entry (de-)serialization support for svn_node_kind_t. */
+static svn_error_t *
+serialize_node_kind(void **data,
+ apr_size_t *data_len,
+ void *in,
+ apr_pool_t *pool)
+{
+ *data_len = sizeof(svn_node_kind_t);
+ *data = in;
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+deserialize_node_kind(void **out,
+ void *data,
+ apr_size_t data_len,
+ apr_pool_t *pool)
+{
+ *out = data;
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_repos_verify_fs3(svn_repos_t *repos,
svn_revnum_t start_rev,
svn_revnum_t end_rev,
svn_boolean_t keep_going,
+ svn_boolean_t check_ucs_norm,
svn_repos_notify_func_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
@@ -1519,6 +2239,7 @@ svn_repos_verify_fs3(svn_repos_t *repos,
apr_array_header_t *error_summary;
int i;
svn_boolean_t found_corruption = FALSE;
+ svn_cache__t *verified_dirents_cache = NULL;
/* Determine the current youngest revision of the filesystem. */
SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));
@@ -1580,6 +2301,18 @@ svn_repos_verify_fs3(svn_repos_t *repos,
svn_error_clear(err);
}
+ if (svn_cache__get_global_membuffer_cache())
+ SVN_ERR(svn_cache__create_membuffer_cache
+ (&verified_dirents_cache,
+ svn_cache__get_global_membuffer_cache(),
+ serialize_node_kind,
+ deserialize_node_kind,
+ APR_HASH_KEY_STRING,
+ svn_uuid_generate(pool),
+ SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+ FALSE,
+ pool));
+
error_summary = apr_array_make(pool, 0, sizeof(struct error_list *));
for (rev = start_rev; rev <= end_rev; rev++)
@@ -1587,8 +2320,10 @@ svn_repos_verify_fs3(svn_repos_t *repos,
svn_pool_clear(iterpool);
/* Wrapper function to catch the possible errors. */
- err = verify_one_revision(fs, rev, notify_func, notify_baton, start_rev,
- cancel_func, cancel_baton, iterpool);
+ err = verify_one_revision(fs, rev, notify_func, notify_baton,
+ start_rev, check_ucs_norm,
+ cancel_func, cancel_baton,
+ verified_dirents_cache, iterpool);
if (err)
{
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/fs-wrap.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/fs-wrap.c Wed Nov 27 11:52:35 2013
@@ -24,6 +24,7 @@
#include <string.h>
#include <ctype.h>
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_pools.h"
#include "svn_error.h"
@@ -34,7 +35,7 @@
#include "svn_time.h"
#include "svn_sorts.h"
#include "repos.h"
-#include "svn_private_config.h"
+
#include "private/svn_repos_private.h"
#include "private/svn_utf_private.h"
#include "private/svn_fspath.h"
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/hooks.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/hooks.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/hooks.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/hooks.c Wed Nov 27 11:52:35 2013
@@ -27,6 +27,7 @@
#include <apr_pools.h>
#include <apr_file_io.h>
+#include "svn_private_config.h"
#include "svn_config.h"
#include "svn_hash.h"
#include "svn_error.h"
@@ -36,7 +37,7 @@
#include "svn_repos.h"
#include "svn_utf.h"
#include "repos.h"
-#include "svn_private_config.h"
+
#include "private/svn_fs_private.h"
#include "private/svn_repos_private.h"
#include "private/svn_string_private.h"
@@ -334,7 +335,7 @@ check_hook_cmd(const char *hook, svn_boo
for (extn = check_extns; *extn; ++extn)
{
const char *const hook_path =
- (**extn ? apr_pstrcat(pool, hook, *extn, (char *)NULL) : hook);
+ (**extn ? apr_pstrcat(pool, hook, *extn, SVN_VA_NULL) : hook);
svn_node_kind_t kind;
if (!(err = svn_io_check_resolved_path(hook_path, &kind, pool))
@@ -416,17 +417,25 @@ svn_repos__parse_hooks_env(apr_hash_t **
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_config_t *cfg;
struct parse_hooks_env_section_baton b;
-
if (local_abspath)
{
- SVN_ERR(svn_config_read3(&cfg, local_abspath, FALSE,
- TRUE, TRUE, scratch_pool));
- b.cfg = cfg;
+ svn_node_kind_t kind;
+ SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
+
b.hooks_env = apr_hash_make(result_pool);
- (void)svn_config_enumerate_sections2(cfg, parse_hooks_env_section, &b,
- scratch_pool);
+
+ if (kind != svn_node_none)
+ {
+ svn_config_t *cfg;
+ SVN_ERR(svn_config_read3(&cfg, local_abspath, FALSE,
+ TRUE, TRUE, scratch_pool));
+ b.cfg = cfg;
+
+ (void)svn_config_enumerate_sections2(cfg, parse_hooks_env_section,
+ &b, scratch_pool);
+ }
+
*hooks_env_p = b.hooks_env;
}
else
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/load-fs-vtable.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/load-fs-vtable.c Wed Nov 27 11:52:35 2013
@@ -99,6 +99,9 @@ struct revision_baton
apr_int32_t rev_offset;
svn_boolean_t skipped;
+ /* Array of svn_prop_t with revision properties. */
+ apr_array_header_t *revprops;
+
struct parse_baton *pb;
apr_pool_t *pool;
};
@@ -448,6 +451,7 @@ make_revision_baton(apr_hash_t *headers,
rb->pb = pb;
rb->pool = pool;
rb->rev = SVN_INVALID_REVNUM;
+ rb->revprops = apr_array_make(rb->pool, 8, sizeof(svn_prop_t));
if ((val = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_REVISION_NUMBER)))
{
@@ -698,10 +702,12 @@ set_revision_property(void *baton,
if (rb->rev > 0)
{
- if (rb->pb->validate_props)
- SVN_ERR(svn_repos_fs_change_txn_prop(rb->txn, name, value, rb->pool));
- else
- SVN_ERR(svn_fs_change_txn_prop(rb->txn, name, value, rb->pool));
+ svn_prop_t *prop = &APR_ARRAY_PUSH(rb->revprops, svn_prop_t);
+
+ /* Collect property changes to apply them in one FS call in
+ close_revision. */
+ prop->name = apr_pstrdup(rb->pool, name);
+ prop->value = svn_string_dup(value, rb->pool);
/* Remember any datestamp that passes through! (See comment in
close_revision() below.) */
@@ -920,6 +926,21 @@ close_revision(void *baton)
if (rb->skipped || (rb->rev <= 0))
return SVN_NO_ERROR;
+ if (!rb->datestamp)
+ {
+ /* Remove 'svn:date' revision property that was set by FS layer when TXN
+ created if source dump doesn't have 'svn:date' property. */
+ svn_prop_t *prop = &APR_ARRAY_PUSH(rb->revprops, svn_prop_t);
+ prop->name = SVN_PROP_REVISION_DATE;
+ prop->value = NULL;
+ }
+
+ /* Apply revision property changes. */
+ if (rb->pb->validate_props)
+ SVN_ERR(svn_repos_fs_change_txn_props(rb->txn, rb->revprops, rb->pool));
+ else
+ SVN_ERR(svn_fs_change_txn_props(rb->txn, rb->revprops, rb->pool));
+
/* Get the txn name and hooks environment if they will be needed. */
if (pb->use_pre_commit_hook || pb->use_post_commit_hook)
{
@@ -947,7 +968,8 @@ close_revision(void *baton)
}
/* Commit. */
- err = svn_fs_commit_txn(&conflict_msg, &committed_rev, rb->txn, rb->pool);
+ err = svn_fs_commit_txn2(&conflict_msg, &committed_rev, rb->txn, FALSE,
+ rb->pool);
if (SVN_IS_VALID_REVNUM(committed_rev))
{
if (err)
@@ -1005,15 +1027,6 @@ close_revision(void *baton)
/* Deltify the predecessors of paths changed in this revision. */
SVN_ERR(svn_fs_deltify_revision(pb->fs, committed_rev, rb->pool));
- /* Grrr, svn_fs_commit_txn rewrites the datestamp property to the
- current clock-time. We don't want that, we want to preserve
- history exactly. Good thing revision props aren't versioned!
- Note that if rb->datestamp is NULL, that's fine -- if the dump
- data doesn't carry a datestamp, we want to preserve that fact in
- the load. */
- SVN_ERR(change_rev_prop(pb->repos, committed_rev, SVN_PROP_REVISION_DATE,
- rb->datestamp, pb->validate_props, rb->pool));
-
if (pb->notify_func)
{
pb->notify->action = svn_repos_notify_load_txn_committed;
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/log.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/log.c Wed Nov 27 11:52:35 2013
@@ -25,8 +25,8 @@
#define APR_WANT_STRFUNC
#include <apr_want.h>
-#include "svn_compat.h"
#include "svn_private_config.h"
+#include "svn_compat.h"
#include "svn_hash.h"
#include "svn_pools.h"
#include "svn_error.h"
@@ -42,7 +42,6 @@
#include "private/svn_mergeinfo_private.h"
#include "private/svn_subr_private.h"
-
svn_error_t *
svn_repos_check_revision_access(svn_repos_revision_access_level_t *access_level,
@@ -105,6 +104,8 @@ svn_repos_check_revision_access(svn_repo
{
case svn_fs_path_change_add:
case svn_fs_path_change_replace:
+ case svn_fs_path_change_move:
+ case svn_fs_path_change_movereplace:
{
const char *copyfrom_path;
svn_revnum_t copyfrom_rev;
@@ -152,6 +153,147 @@ svn_repos_check_revision_access(svn_repo
return SVN_NO_ERROR;
}
+/* Return TRUE, if CHANGE deleted the node previously found at its target
+ path. */
+static svn_boolean_t
+is_deletion(svn_log_changed_path2_t *change)
+{
+ /* We need a 'N' action here ... */
+ return change->action == 'E'
+ || change->action == 'R'
+ || change->action == 'D';
+}
+
+/* Change all moves in CHANGES to ADD. Use POOL for temporary allocations.
+ */
+static void
+turn_moves_into_copies(apr_hash_t *changes,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *hi;
+ for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+ {
+ const char *key;
+ apr_ssize_t klen;
+ svn_log_changed_path2_t *change;
+ apr_hash_this(hi, (const void **)&key, &klen, (void**)&change);
+
+ switch (change->action)
+ {
+ case 'V':
+ change->action = 'A';
+ break;
+
+ case 'E':
+ change->action = 'R';
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/* Replace ADDs with MOVes, if they are unique, have a matching deletion
+ * and if the copy-from revision is REVISION-1. Use POOL for temporary
+ * allocations.
+ */
+static void
+turn_unique_copies_into_moves(apr_hash_t *changes,
+ svn_revnum_t revision,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *hi;
+ apr_hash_t *unique_copy_sources;
+ const char **sources;
+ int i;
+
+ /* find all copy-from paths (ADD and MOV alike) */
+
+ svn_boolean_t any_deletion = FALSE;
+ apr_array_header_t *copy_sources
+ = apr_array_make(pool, apr_hash_count(changes), sizeof(const char*));
+
+ for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+ {
+ svn_log_changed_path2_t *change;
+ apr_hash_this(hi, NULL, NULL, (void**)&change);
+
+ if (change->copyfrom_path && change->copyfrom_rev == revision-1)
+ APR_ARRAY_PUSH(copy_sources, const char *)
+ = change->copyfrom_path;
+
+ any_deletion |= is_deletion(change);
+ }
+
+ /* no suitable copy-from or no deletion -> no moves */
+
+ if (!copy_sources->nelts || !any_deletion)
+ return;
+
+ /* identify copy-from paths that have been mentioned exactly once */
+
+ sources = (const char **)copy_sources->elts;
+ qsort(sources, copy_sources->nelts, copy_sources->elt_size,
+ (int (*)(const void *, const void *))svn_sort_compare_paths);
+
+ unique_copy_sources = apr_hash_make(pool);
+ for (i = 0; i < copy_sources->nelts; ++i)
+ if ( (i == 0 || strcmp(sources[i-1], sources[i]))
+ && (i == copy_sources->nelts-1 || strcmp(sources[i+1], sources[i])))
+ {
+ apr_hash_set(unique_copy_sources, sources[i],
+ APR_HASH_KEY_STRING, sources[i]);
+ }
+
+ /* no unique copy-from paths -> no moves */
+
+ if (!apr_hash_count(unique_copy_sources))
+ return;
+
+ /* Replace all additions, replacements with a unique copy-from path,
+ the correct copy-from rev and a matching deletion in this revision,
+ with moves and move-replacements, respectively. */
+
+ for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+ {
+ const char *key;
+ apr_ssize_t klen;
+ svn_log_changed_path2_t *change, *copy_from_change;
+
+ apr_hash_this(hi, (const void **)&key, &klen, (void**)&change);
+ if ( change->copyfrom_rev != revision-1
+ || !change->copyfrom_path
+ || !apr_hash_get(unique_copy_sources, change->copyfrom_path,
+ APR_HASH_KEY_STRING))
+ continue;
+
+ copy_from_change = apr_hash_get(changes, change->copyfrom_path,
+ APR_HASH_KEY_STRING);
+ if (!copy_from_change || !is_deletion(copy_from_change))
+ continue;
+
+ /* There is a deletion of the ADD's copy-from path in *REVISION*.
+ This can either be the same as in REVISION-1 (o.k.) or must have
+ been replaced by some other node. However, that would imply that
+ it still got deleted as part of the replacement, i.e. both cases
+ are o.k. */
+
+ switch (change->action)
+ {
+ case 'A':
+ change->action = 'V';
+ break;
+
+ case 'R':
+ change->action = 'E';
+ break;
+
+ default:
+ break;
+ }
+ }
+}
/* Store as keys in CHANGED the paths of all node in ROOT that show a
* significant change. "Significant" means that the text or
@@ -163,7 +305,8 @@ svn_repos_check_revision_access(svn_repo
*
* To prevent changes from being processed over and over again, the
* changed paths for ROOT may be passed in PREFETCHED_CHANGES. If the
- * latter is NULL, we will request the list inside this function.
+ * latter is NULL, we will request the list inside this function using
+ * the specified MOVE_BEHAVIOR.
*
* If optional AUTHZ_READ_FUNC is non-NULL, then use it (with
* AUTHZ_READ_BATON and FS) to check whether each changed-path (and
@@ -184,6 +327,7 @@ detect_changed(apr_hash_t **changed,
svn_fs_root_t *root,
svn_fs_t *fs,
apr_hash_t *prefetched_changes,
+ svn_move_behavior_t move_behavior,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
apr_pool_t *pool)
@@ -255,6 +399,14 @@ detect_changed(apr_hash_t **changed,
action = 'D';
break;
+ case svn_fs_path_change_move:
+ action = 'V';
+ break;
+
+ case svn_fs_path_change_movereplace:
+ action = 'E';
+ break;
+
case svn_fs_path_change_modify:
default:
action = 'M';
@@ -306,7 +458,8 @@ detect_changed(apr_hash_t **changed,
}
- if ((action == 'A') || (action == 'R'))
+ if ( (action == 'A') || (action == 'R')
+ || (action == 'V') || (action == 'E'))
{
const char *copyfrom_path = change->copyfrom_path;
svn_revnum_t copyfrom_rev = change->copyfrom_rev;
@@ -354,6 +507,23 @@ detect_changed(apr_hash_t **changed,
return svn_error_create(SVN_ERR_AUTHZ_UNREADABLE,
NULL, NULL);
+ /* at least some paths are readable. Post-process them. */
+ switch(move_behavior)
+ {
+ case svn_move_behavior_no_moves:
+ turn_moves_into_copies(*changed, pool);
+ break;
+
+ case svn_move_behavior_auto_moves:
+ turn_unique_copies_into_moves(*changed,
+ svn_fs_revision_root_revision(root),
+ pool);
+ break;
+
+ default:
+ break;
+ }
+
if (found_unreadable)
/* At least one changed-path was unreadable. */
return svn_error_create(SVN_ERR_AUTHZ_PARTIALLY_READABLE,
@@ -638,6 +808,8 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
was. If not, there's no previous location to examine. */
case svn_fs_path_change_add:
case svn_fs_path_change_replace:
+ case svn_fs_path_change_move:
+ case svn_fs_path_change_movereplace:
{
const char *copyfrom_path;
svn_revnum_t copyfrom_rev;
@@ -782,8 +954,7 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
*ADDED_MERGEINFO and deleted mergeinfo in *DELETED_MERGEINFO.
If *PREFETCHED_CAHNGES already contains the changed paths for
REV, use that. Otherwise, request that data and return it in
- *PREFETCHED_CHANGES.
- Use POOL for all allocations. */
+ *PREFETCHED_CHANGES. Use POOL for all allocations. */
static svn_error_t *
get_combined_mergeinfo_changes(svn_mergeinfo_t *added_mergeinfo,
svn_mergeinfo_t *deleted_mergeinfo,
@@ -820,7 +991,8 @@ get_combined_mergeinfo_changes(svn_merge
err = fs_mergeinfo_changed(&deleted_mergeinfo_catalog,
&added_mergeinfo_catalog,
prefetched_changes,
- fs, rev, scratch_pool, scratch_pool);
+ fs, rev,
+ scratch_pool, scratch_pool);
if (err)
{
if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
@@ -1025,6 +1197,7 @@ fill_log_entry(svn_log_entry_t *log_entr
svn_fs_t *fs,
apr_hash_t *prefetched_changes,
svn_boolean_t discover_changed_paths,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
@@ -1043,7 +1216,7 @@ fill_log_entry(svn_log_entry_t *log_entr
SVN_ERR(svn_fs_revision_root(&newroot, fs, rev, pool));
patherr = detect_changed(&changed_paths,
- newroot, fs, prefetched_changes,
+ newroot, fs, prefetched_changes, move_behavior,
authz_read_func, authz_read_baton,
pool);
@@ -1160,9 +1333,9 @@ fill_log_entry(svn_log_entry_t *log_entr
only the revision properties named by the (const char *) array elements
(i.e. retrieve none if the array is empty).
- LOG_TARGET_HISTORY_AS_MERGEINFO, HANDLING_MERGED_REVISION, and
- NESTED_MERGES are as per the arguments of the same name to DO_LOGS. If
- HANDLING_MERGED_REVISION is true and *all* changed paths within REV are
+ LOG_TARGET_HISTORY_AS_MERGEINFO, HANDLING_MERGED_REVISION, MOVE_BEHAVIOR,
+ and NESTED_MERGES are as per the arguments of the same name to DO_LOGS.
+ If HANDLING_MERGED_REVISION is true and *all* changed paths within REV are
already represented in LOG_TARGET_HISTORY_AS_MERGEINFO, then don't send
the log message for REV. If SUBTRACTIVE_MERGE is true, then REV was
reverse merged.
@@ -1180,6 +1353,7 @@ send_log(svn_revnum_t rev,
svn_boolean_t discover_changed_paths,
svn_boolean_t subtractive_merge,
svn_boolean_t handling_merged_revision,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_boolean_t has_children,
svn_log_entry_receiver_t receiver,
@@ -1195,8 +1369,8 @@ send_log(svn_revnum_t rev,
log_entry = svn_log_entry_create(pool);
SVN_ERR(fill_log_entry(log_entry, rev, fs, prefetched_changes,
discover_changed_paths || handling_merged_revision,
- revprops, authz_read_func, authz_read_baton,
- pool));
+ move_behavior, revprops,
+ authz_read_func, authz_read_baton, pool));
log_entry->has_children = has_children;
log_entry->subtractive_merge = subtractive_merge;
@@ -1663,6 +1837,7 @@ do_logs(svn_fs_t *fs,
svn_boolean_t handling_merged_revisions,
svn_boolean_t subtractive_merge,
svn_boolean_t ignore_missing_locations,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_boolean_t descending_order,
svn_log_entry_receiver_t receiver,
@@ -1712,6 +1887,7 @@ handle_merged_revisions(svn_revnum_t rev
svn_mergeinfo_t deleted_mergeinfo,
svn_boolean_t discover_changed_paths,
svn_boolean_t strict_node_history,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_log_entry_receiver_t receiver,
void *receiver_baton,
@@ -1754,7 +1930,7 @@ handle_merged_revisions(svn_revnum_t rev
pl_range->range.start, pl_range->range.end, 0,
discover_changed_paths, strict_node_history,
TRUE, pl_range->reverse_merge, TRUE, TRUE,
- revprops, TRUE, receiver, receiver_baton,
+ move_behavior, revprops, TRUE, receiver, receiver_baton,
authz_read_func, authz_read_baton, iterpool));
}
svn_pool_destroy(iterpool);
@@ -1888,6 +2064,9 @@ store_search(svn_mergeinfo_t processed,
If IGNORE_MISSING_LOCATIONS is set, don't treat requests for bogus
repository locations as fatal -- just ignore them.
+ MOVE_BEHAVIOR is a simple pass-through parameter that tells the FS
+ layer which changes to report as moves instead of additions.
+
If LOG_TARGET_HISTORY_AS_MERGEINFO is not NULL then it contains mergeinfo
representing the history of PATHS between HIST_START and HIST_END.
@@ -1925,6 +2104,7 @@ do_logs(svn_fs_t *fs,
svn_boolean_t subtractive_merge,
svn_boolean_t handling_merged_revisions,
svn_boolean_t ignore_missing_locations,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_boolean_t descending_order,
svn_log_entry_receiver_t receiver,
@@ -2019,8 +2199,8 @@ do_logs(svn_fs_t *fs,
&deleted_mergeinfo,
&changes,
fs, cur_paths,
- current, iterpool,
- iterpool));
+ current,
+ iterpool, iterpool));
has_children = (apr_hash_count(added_mergeinfo) > 0
|| apr_hash_count(deleted_mergeinfo) > 0);
}
@@ -2034,7 +2214,7 @@ do_logs(svn_fs_t *fs,
log_target_history_as_mergeinfo, nested_merges,
discover_changed_paths,
subtractive_merge, handling_merged_revisions,
- revprops, has_children,
+ move_behavior, revprops, has_children,
receiver, receiver_baton,
authz_read_func, authz_read_baton, iterpool));
@@ -2057,6 +2237,7 @@ do_logs(svn_fs_t *fs,
added_mergeinfo, deleted_mergeinfo,
discover_changed_paths,
strict_node_history,
+ move_behavior,
revprops,
receiver, receiver_baton,
authz_read_func,
@@ -2138,7 +2319,8 @@ do_logs(svn_fs_t *fs,
SVN_ERR(send_log(current, fs, NULL,
log_target_history_as_mergeinfo, nested_merges,
discover_changed_paths, subtractive_merge,
- handling_merged_revisions, revprops, has_children,
+ handling_merged_revisions, move_behavior,
+ revprops, has_children,
receiver, receiver_baton, authz_read_func,
authz_read_baton, iterpool));
if (has_children)
@@ -2156,7 +2338,8 @@ do_logs(svn_fs_t *fs,
added_mergeinfo,
deleted_mergeinfo,
discover_changed_paths,
- strict_node_history, revprops,
+ strict_node_history,
+ move_behavior, revprops,
receiver, receiver_baton,
authz_read_func,
authz_read_baton,
@@ -2258,7 +2441,7 @@ get_paths_history_as_mergeinfo(svn_merge
}
svn_error_t *
-svn_repos_get_logs4(svn_repos_t *repos,
+svn_repos_get_logs5(svn_repos_t *repos,
const apr_array_header_t *paths,
svn_revnum_t start,
svn_revnum_t end,
@@ -2266,6 +2449,7 @@ svn_repos_get_logs4(svn_repos_t *repos,
svn_boolean_t discover_changed_paths,
svn_boolean_t strict_node_history,
svn_boolean_t include_merged_revisions,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_repos_authz_func_t authz_read_func,
void *authz_read_baton,
@@ -2374,7 +2558,7 @@ svn_repos_get_logs4(svn_repos_t *repos,
rev = start + i;
SVN_ERR(send_log(rev, fs, NULL, NULL, NULL,
discover_changed_paths, FALSE,
- FALSE, revprops, FALSE, receiver,
+ FALSE, move_behavior, revprops, FALSE, receiver,
receiver_baton, authz_read_func,
authz_read_baton, iterpool));
}
@@ -2402,7 +2586,8 @@ svn_repos_get_logs4(svn_repos_t *repos,
return do_logs(repos->fs, paths, paths_history_mergeinfo, NULL, NULL, start, end,
limit, discover_changed_paths, strict_node_history,
- include_merged_revisions, FALSE, FALSE, FALSE, revprops,
+ include_merged_revisions, FALSE, FALSE, FALSE,
+ move_behavior, revprops,
descending_order, receiver, receiver_baton,
authz_read_func, authz_read_baton, pool);
}
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/replay.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/replay.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/replay.c Wed Nov 27 11:52:35 2013
@@ -25,6 +25,7 @@
#include <apr_hash.h>
+#include "svn_private_config.h"
#include "svn_types.h"
#include "svn_delta.h"
#include "svn_hash.h"
@@ -35,7 +36,7 @@
#include "svn_props.h"
#include "svn_pools.h"
#include "svn_path.h"
-#include "svn_private_config.h"
+
#include "private/svn_fspath.h"
#include "private/svn_repos_private.h"
#include "private/svn_delta_private.h"
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/reporter.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/reporter.c Wed Nov 27 11:52:35 2013
@@ -21,6 +21,7 @@
* ====================================================================
*/
+#include "svn_private_config.h"
#include "svn_dirent_uri.h"
#include "svn_hash.h"
#include "svn_path.h"
@@ -32,7 +33,6 @@
#include "svn_pools.h"
#include "svn_props.h"
#include "repos.h"
-#include "svn_private_config.h"
#include "private/svn_dep_compat.h"
#include "private/svn_fspath.h"
@@ -499,7 +499,7 @@ get_revision_info(report_baton_t *b,
info->author = author ? svn_string_dup(author, b->pool) : NULL;
/* Cache it */
- apr_hash_set(b->revision_infos, &info->rev, sizeof(rev), info);
+ apr_hash_set(b->revision_infos, &info->rev, sizeof(info->rev), info);
}
*revision_info = info;
@@ -842,7 +842,7 @@ add_file_smartly(report_baton_t *b,
starting with '/', so make sure o_path always starts with a '/'
too. */
if (*o_path != '/')
- o_path = apr_pstrcat(pool, "/", o_path, (char *)NULL);
+ o_path = apr_pstrcat(pool, "/", o_path, SVN_VA_NULL);
SVN_ERR(svn_fs_closest_copy(&closest_copy_root, &closest_copy_path,
b->t_root, o_path, pool));
@@ -1143,6 +1143,8 @@ delta_dirs(report_baton_t *b, svn_revnum
apr_hash_t *s_entries = NULL, *t_entries;
apr_hash_index_t *hi;
apr_pool_t *subpool;
+ apr_array_header_t *t_ordered_entries = NULL;
+ int i;
/* Compare the property lists. If we're starting empty, pass a NULL
source path so that we add all the properties.
@@ -1275,9 +1277,12 @@ delta_dirs(report_baton_t *b, svn_revnum
}
/* Loop over the dirents in the target. */
- for (hi = apr_hash_first(pool, t_entries); hi; hi = apr_hash_next(hi))
+ SVN_ERR(svn_fs_dir_optimal_order(&t_ordered_entries, b->t_root,
+ t_entries, pool));
+ for (i = 0; i < t_ordered_entries->nelts; ++i)
{
- const svn_fs_dirent_t *t_entry = svn__apr_hash_index_val(hi);
+ const svn_fs_dirent_t *t_entry
+ = APR_ARRAY_IDX(t_ordered_entries, i, svn_fs_dirent_t *);
const svn_fs_dirent_t *s_entry;
const char *s_fullpath, *t_fullpath, *e_fullpath;
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/repos.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/repos.c Wed Nov 27 11:52:35 2013
@@ -23,6 +23,7 @@
#include <apr_pools.h>
#include <apr_file_io.h>
+#include "svn_private_config.h"
#include "svn_pools.h"
#include "svn_error.h"
#include "svn_dirent_uri.h"
@@ -38,7 +39,6 @@
#include "private/svn_repos_private.h"
#include "private/svn_subr_private.h"
-#include "svn_private_config.h" /* for SVN_TEMPLATE_ROOT_DIR */
#include "repos.h"
@@ -1796,6 +1796,11 @@ svn_repos_fs(svn_repos_t *repos)
return repos->fs;
}
+const char *
+svn_repos_fs_type(svn_repos_t *repos, apr_pool_t *pool)
+{
+ return apr_pstrdup(pool, repos->fs_type);
+}
/* For historical reasons, for the Berkeley DB backend, this code uses
* repository locking, which is motivated by the need to support the
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/repos.h?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/repos.h (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/repos.h Wed Nov 27 11:52:35 2013
@@ -382,6 +382,11 @@ svn_repos__authz_read(svn_authz_t **auth
svn_boolean_t accept_urls,
apr_pool_t *pool);
+/* Walk the configuration in AUTHZ looking for any errors. */
+svn_error_t *
+svn_repos__authz_validate(svn_authz_t *authz,
+ apr_pool_t *pool);
+
/*** Utility Functions ***/
Modified: subversion/branches/verify-keep-going/subversion/libsvn_repos/rev_hunt.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_repos/rev_hunt.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_repos/rev_hunt.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_repos/rev_hunt.c Wed Nov 27 11:52:35 2013
@@ -23,8 +23,9 @@
#include <string.h>
-#include "svn_compat.h"
+
#include "svn_private_config.h"
+#include "svn_compat.h"
#include "svn_hash.h"
#include "svn_pools.h"
#include "svn_error.h"
@@ -660,7 +661,7 @@ svn_repos_trace_node_locations(svn_fs_t
/* Ensure that FS_PATH is absolute, because our path-math below will
depend on that being the case. */
if (*fs_path != '/')
- fs_path = apr_pstrcat(pool, "/", fs_path, (char *)NULL);
+ fs_path = apr_pstrcat(pool, "/", fs_path, SVN_VA_NULL);
/* Another sanity check. */
if (authz_read_func)
@@ -877,7 +878,7 @@ svn_repos_node_location_segments(svn_rep
/* Ensure that PATH is absolute, because our path-math will depend
on that being the case. */
if (*path != '/')
- path = apr_pstrcat(pool, "/", path, (char *)NULL);
+ path = apr_pstrcat(pool, "/", path, SVN_VA_NULL);
/* Auth check. */
if (authz_read_func)
@@ -941,7 +942,7 @@ svn_repos_node_location_segments(svn_rep
/* authz_read_func requires path to have a leading slash. */
const char *abs_path = apr_pstrcat(subpool, "/", segment->path,
- (char *)NULL);
+ SVN_VA_NULL);
SVN_ERR(svn_fs_revision_root(&cur_rev_root, fs,
segment->range_end, subpool));
Modified: subversion/branches/verify-keep-going/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_subr/auth.c?rev=1546002&r1=1546001&r2=1546002&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_subr/auth.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_subr/auth.c Wed Nov 27 11:52:35 2013
@@ -26,15 +26,16 @@
#include <apr_tables.h>
#include <apr_strings.h>
+#include "svn_private_config.h"
#include "svn_hash.h"
#include "svn_types.h"
#include "svn_string.h"
#include "svn_error.h"
#include "svn_auth.h"
#include "svn_config.h"
-#include "svn_private_config.h"
#include "svn_dso.h"
#include "svn_version.h"
+#include "private/svn_auth_private.h"
#include "private/svn_dep_compat.h"
#include "auth.h"
@@ -176,14 +177,18 @@ svn_auth_set_parameter(svn_auth_baton_t
const char *name,
const void *value)
{
- svn_hash_sets(auth_baton->parameters, name, value);
+ if (auth_baton)
+ svn_hash_sets(auth_baton->parameters, name, value);
}
const void *
svn_auth_get_parameter(svn_auth_baton_t *auth_baton,
const char *name)
{
- return svn_hash_gets(auth_baton->parameters, name);
+ if (auth_baton)
+ return svn_hash_gets(auth_baton->parameters, name);
+ else
+ return NULL;
}
@@ -194,7 +199,7 @@ make_cache_key(const char *cred_kind,
const char *realmstring,
apr_pool_t *pool)
{
- return apr_pstrcat(pool, cred_kind, ":", realmstring, (char *)NULL);
+ return apr_pstrcat(pool, cred_kind, ":", realmstring, SVN_VA_NULL);
}
svn_error_t *
@@ -214,6 +219,10 @@ svn_auth_first_credentials(void **creden
svn_auth_iterstate_t *iterstate;
const char *cache_key;
+ if (! auth_baton)
+ return svn_error_create(SVN_ERR_AUTHN_NO_PROVIDER, NULL,
+ _("No authentication providers registered"));
+
/* Get the appropriate table of providers for CRED_KIND. */
table = svn_hash_gets(auth_baton->tables, cred_kind);
if (! table)
@@ -481,7 +490,8 @@ svn_auth_get_platform_specific_provider(
check_list[0].version_query = version_function;
check_list[1].label = NULL;
check_list[1].version_query = NULL;
- SVN_ERR(svn_ver_check_list(svn_subr_version(), check_list));
+ SVN_ERR(svn_ver_check_list2(svn_subr_version(), check_list,
+ svn_ver_equal));
}
if (apr_dso_sym(&provider_function_symbol,
dso,
@@ -509,19 +519,19 @@ svn_auth_get_platform_specific_provider(
if (strcmp(provider_name, "gpg_agent") == 0 &&
strcmp(provider_type, "simple") == 0)
{
- svn_auth_get_gpg_agent_simple_provider(provider, pool);
+ svn_auth__get_gpg_agent_simple_provider(provider, pool);
}
#endif
#ifdef SVN_HAVE_KEYCHAIN_SERVICES
if (strcmp(provider_name, "keychain") == 0 &&
strcmp(provider_type, "simple") == 0)
{
- svn_auth_get_keychain_simple_provider(provider, pool);
+ svn_auth__get_keychain_simple_provider(provider, pool);
}
else if (strcmp(provider_name, "keychain") == 0 &&
strcmp(provider_type, "ssl_client_cert_pw") == 0)
{
- svn_auth_get_keychain_ssl_client_cert_pw_provider(provider, pool);
+ svn_auth__get_keychain_ssl_client_cert_pw_provider(provider, pool);
}
#endif
@@ -529,17 +539,22 @@ svn_auth_get_platform_specific_provider(
if (strcmp(provider_name, "windows") == 0 &&
strcmp(provider_type, "simple") == 0)
{
- svn_auth_get_windows_simple_provider(provider, pool);
+ svn_auth__get_windows_simple_provider(provider, pool);
}
else if (strcmp(provider_name, "windows") == 0 &&
strcmp(provider_type, "ssl_client_cert_pw") == 0)
{
- svn_auth_get_windows_ssl_client_cert_pw_provider(provider, pool);
+ svn_auth__get_windows_ssl_client_cert_pw_provider(provider, pool);
}
else if (strcmp(provider_name, "windows") == 0 &&
strcmp(provider_type, "ssl_server_trust") == 0)
{
- svn_auth_get_windows_ssl_server_trust_provider(provider, pool);
+ svn_auth__get_windows_ssl_server_trust_provider(provider, pool);
+ }
+ else if (strcmp(provider_name, "windows") == 0 &&
+ strcmp(provider_type, "ssl_server_authority") == 0)
+ {
+ svn_auth__get_windows_ssl_server_authority_provider(provider, pool);
}
#endif
}
@@ -651,5 +666,22 @@ svn_auth_get_platform_specific_client_pr
}
}
+ /* Windows has two providers without a store to allow easy access to
+ SSL servers. We enable these unconditionally.
+ (This behavior was moved here from svn_cmdline_create_auth_baton()) */
+ SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
+ "windows",
+ "ssl_server_trust",
+ pool));
+ SVN__MAYBE_ADD_PROVIDER(*providers, provider);
+
+ /* The windows ssl authority certificate CRYPTOAPI provider. */
+ SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
+ "windows",
+ "ssl_server_authority",
+ pool));
+
+ SVN__MAYBE_ADD_PROVIDER(*providers, provider);
+
return SVN_NO_ERROR;
}