summaryrefslogtreecommitdiff
path: root/subversion/svnrdump
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/svnrdump')
-rw-r--r--subversion/svnrdump/dump_editor.c532
-rw-r--r--subversion/svnrdump/load_editor.c309
-rw-r--r--subversion/svnrdump/svnrdump.c403
-rw-r--r--subversion/svnrdump/svnrdump.h1
-rw-r--r--subversion/svnrdump/util.c4
5 files changed, 449 insertions, 800 deletions
diff --git a/subversion/svnrdump/dump_editor.c b/subversion/svnrdump/dump_editor.c
index faf029f..bf4f81c 100644
--- a/subversion/svnrdump/dump_editor.c
+++ b/subversion/svnrdump/dump_editor.c
@@ -30,6 +30,7 @@
#include "svn_subst.h"
#include "svn_dirent_uri.h"
+#include "private/svn_repos_private.h"
#include "private/svn_subr_private.h"
#include "private/svn_dep_compat.h"
#include "private/svn_editor.h"
@@ -39,28 +40,16 @@
#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
-#if 0
-#define LDR_DBG(x) SVN_DBG(x)
-#else
-#define LDR_DBG(x) while(0)
-#endif
/* A directory baton used by all directory-related callback functions
* in the dump editor. */
struct dir_baton
{
struct dump_edit_baton *eb;
- struct dir_baton *parent_dir_baton;
/* Pool for per-directory allocations */
apr_pool_t *pool;
- /* is this directory a new addition to this revision? */
- svn_boolean_t added;
-
- /* has this directory been written to the output stream? */
- svn_boolean_t written_out;
-
/* the path to this directory */
const char *repos_relpath; /* a relpath */
@@ -68,6 +57,9 @@ struct dir_baton
const char *copyfrom_path; /* a relpath */
svn_revnum_t copyfrom_rev;
+ /* Headers accumulated so far for this directory */
+ svn_repos__dumpfile_headers_t *headers;
+
/* Properties which were modified during change_dir_prop. */
apr_hash_t *props;
@@ -80,9 +72,8 @@ struct dir_baton
us, although they're all really within this directory. */
apr_hash_t *deleted_entries;
- /* Flags to trigger dumping props and record termination newlines. */
+ /* Flag to trigger dumping props. */
svn_boolean_t dump_props;
- svn_boolean_t dump_newlines;
};
/* A file baton used by all file-related callback functions in the dump
@@ -90,7 +81,6 @@ struct dir_baton
struct file_baton
{
struct dump_edit_baton *eb;
- struct dir_baton *parent_dir_baton;
/* Pool for per-file allocations */
apr_pool_t *pool;
@@ -120,13 +110,6 @@ struct file_baton
svn_boolean_t dump_props;
};
-/* A handler baton to be used in window_handler(). */
-struct handler_baton
-{
- svn_txdelta_window_handler_t apply_handler;
- void *apply_baton;
-};
-
/* The baton used by the dump editor. */
struct dump_edit_baton {
/* The output stream we write the dumpfile to */
@@ -155,11 +138,10 @@ struct dump_edit_baton {
/* The revision we're currently dumping. */
svn_revnum_t current_revision;
- /* The kind (file or directory) and baton of the item whose block of
+ /* The baton of the directory node whose block of
dump stream data has not been fully completed; NULL if there's no
such item. */
- svn_node_kind_t pending_kind;
- void *pending_baton;
+ struct dir_baton *pending_db;
};
/* Make a directory baton to represent the directory at PATH (relative
@@ -171,16 +153,15 @@ struct dump_edit_baton {
* copy source.
*
* PB is the directory baton of this directory's parent, or NULL if
- * this is the top-level directory of the edit. ADDED indicates if
- * this directory is newly added in this revision. Perform all
- * allocations in POOL. */
+ * this is the top-level directory of the edit.
+ *
+ * Perform all allocations in POOL. */
static struct dir_baton *
make_dir_baton(const char *path,
const char *copyfrom_path,
svn_revnum_t copyfrom_rev,
void *edit_baton,
struct dir_baton *pb,
- svn_boolean_t added,
apr_pool_t *pool)
{
struct dump_edit_baton *eb = edit_baton;
@@ -199,15 +180,13 @@ make_dir_baton(const char *path,
copyfrom_path = svn_relpath_canonicalize(copyfrom_path, pool);
new_db->eb = eb;
- new_db->parent_dir_baton = pb;
new_db->pool = pool;
new_db->repos_relpath = repos_relpath;
new_db->copyfrom_path = copyfrom_path
? svn_relpath_canonicalize(copyfrom_path, pool)
: NULL;
new_db->copyfrom_rev = copyfrom_rev;
- new_db->added = added;
- new_db->written_out = FALSE;
+ new_db->headers = NULL;
new_db->props = apr_hash_make(pool);
new_db->deleted_props = apr_hash_make(pool);
new_db->deleted_entries = apr_hash_make(pool);
@@ -227,7 +206,6 @@ make_file_baton(const char *path,
struct file_baton *new_fb = apr_pcalloc(pool, sizeof(*new_fb));
new_fb->eb = pb->eb;
- new_fb->parent_dir_baton = pb;
new_fb->pool = pool;
new_fb->repos_relpath = svn_relpath_canonicalize(path, pool);
new_fb->props = apr_hash_make(pool);
@@ -240,9 +218,11 @@ make_file_baton(const char *path,
return new_fb;
}
-/* Return in *HEADER and *CONTENT the headers and content for PROPS. */
+/* Append to HEADERS the required headers, and set *CONTENT to the property
+ * content section, to represent the property delta of PROPS/DELETED_PROPS.
+ */
static svn_error_t *
-get_props_content(svn_stringbuf_t **header,
+get_props_content(svn_repos__dumpfile_headers_t *headers,
svn_stringbuf_t **content,
apr_hash_t *props,
apr_hash_t *deleted_props,
@@ -251,10 +231,8 @@ get_props_content(svn_stringbuf_t **header,
{
svn_stream_t *content_stream;
apr_hash_t *normal_props;
- const char *buf;
*content = svn_stringbuf_create_empty(result_pool);
- *header = svn_stringbuf_create_empty(result_pool);
content_stream = svn_stream_from_stringbuf(*content, scratch_pool);
@@ -265,101 +243,63 @@ get_props_content(svn_stringbuf_t **header,
SVN_ERR(svn_stream_close(content_stream));
/* Prop-delta: true */
- *header = svn_stringbuf_createf(result_pool, SVN_REPOS_DUMPFILE_PROP_DELTA
- ": true\n");
-
- /* Prop-content-length: 193 */
- buf = apr_psprintf(scratch_pool, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
- ": %" APR_SIZE_T_FMT "\n", (*content)->len);
- svn_stringbuf_appendcstr(*header, buf);
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_PROP_DELTA, "true");
return SVN_NO_ERROR;
}
-/* Extract and dump properties stored in PROPS and property deletions
- * stored in DELETED_PROPS. If TRIGGER_VAR is not NULL, it is set to
- * FALSE.
+/* A special case of dump_node(), for a delete record.
*
- * If PROPSTRING is non-NULL, set *PROPSTRING to a string containing
- * the content block of the property changes; otherwise, dump that to
- * the stream, too.
+ * The only thing special about this version is it only writes one blank
+ * line, not two, after the headers. Why? Historical precedent for the
+ * case where a delete record is used as part of a (delete + add-with-history)
+ * in implementing a replacement.
*/
static svn_error_t *
-do_dump_props(svn_stringbuf_t **propstring,
- svn_stream_t *stream,
- apr_hash_t *props,
- apr_hash_t *deleted_props,
- svn_boolean_t *trigger_var,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+dump_node_delete(svn_stream_t *stream,
+ const char *node_relpath,
+ apr_pool_t *pool)
{
- svn_stringbuf_t *header;
- svn_stringbuf_t *content;
- apr_size_t len;
+ svn_repos__dumpfile_headers_t *headers
+ = svn_repos__dumpfile_headers_create(pool);
- if (trigger_var && !*trigger_var)
- return SVN_NO_ERROR;
-
- SVN_ERR(get_props_content(&header, &content, props, deleted_props,
- result_pool, scratch_pool));
- len = header->len;
- SVN_ERR(svn_stream_write(stream, header->data, &len));
+ assert(svn_relpath_is_canonical(node_relpath));
- if (propstring)
- {
- *propstring = content;
- }
- else
- {
- /* Content-length: 14 */
- SVN_ERR(svn_stream_printf(stream, scratch_pool,
- SVN_REPOS_DUMPFILE_CONTENT_LENGTH
- ": %" APR_SIZE_T_FMT "\n\n",
- content->len));
-
- len = content->len;
- SVN_ERR(svn_stream_write(stream, content->data, &len));
-
- /* No text is going to be dumped. Write a couple of newlines and
- wait for the next node/ revision. */
- SVN_ERR(svn_stream_puts(stream, "\n\n"));
-
- /* Cleanup so that data is never dumped twice. */
- apr_hash_clear(props);
- apr_hash_clear(deleted_props);
- if (trigger_var)
- *trigger_var = FALSE;
- }
+ /* Node-path: ... */
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_NODE_PATH, node_relpath);
- return SVN_NO_ERROR;
-}
+ /* Node-action: delete */
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
-static svn_error_t *
-do_dump_newlines(struct dump_edit_baton *eb,
- svn_boolean_t *trigger_var,
- apr_pool_t *pool)
-{
- if (trigger_var && *trigger_var)
- {
- SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
- *trigger_var = FALSE;
- }
+ SVN_ERR(svn_repos__dump_node_record(stream, headers,
+ NULL, FALSE, 0, /* props & text */
+ FALSE /*content_length_always*/, pool));
return SVN_NO_ERROR;
}
-/*
- * Write out a node record for PATH of type KIND under EB->FS_ROOT.
+/* Set *HEADERS_P to contain some headers for the node at PATH of type KIND.
+ *
* ACTION describes what is happening to the node (see enum
- * svn_node_action). Write record to writable EB->STREAM, using
- * EB->BUFFER to write in chunks.
+ * svn_node_action).
*
* If the node was itself copied, IS_COPY is TRUE and the
* path/revision of the copy source are in COPYFROM_PATH/COPYFROM_REV.
* If IS_COPY is FALSE, yet COPYFROM_PATH/COPYFROM_REV are valid, this
* node is part of a copied subtree.
+ *
+ * Iff ACTION is svn_node_action_replace and IS_COPY, then first write a
+ * complete deletion record to the dump stream.
+ *
+ * If ACTION is svn_node_action_delete, then the node record will be
+ * complete. (The caller may want to write two blank lines after the
+ * header block.)
*/
static svn_error_t *
-dump_node(struct dump_edit_baton *eb,
+dump_node(svn_repos__dumpfile_headers_t **headers_p,
+ struct dump_edit_baton *eb,
const char *repos_relpath,
struct dir_baton *db,
struct file_baton *fb,
@@ -370,6 +310,8 @@ dump_node(struct dump_edit_baton *eb,
apr_pool_t *pool)
{
const char *node_relpath = repos_relpath;
+ svn_repos__dumpfile_headers_t *headers
+ = svn_repos__dumpfile_headers_create(pool);
assert(svn_relpath_is_canonical(repos_relpath));
assert(!copyfrom_path || svn_relpath_is_canonical(copyfrom_path));
@@ -381,17 +323,16 @@ dump_node(struct dump_edit_baton *eb,
node_relpath, pool);
/* Node-path: ... */
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n",
- node_relpath));
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_NODE_PATH, node_relpath);
/* Node-kind: "file" | "dir" */
if (fb)
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_NODE_KIND ": file\n"));
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_NODE_KIND, "file");
else if (db)
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n"));
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_NODE_KIND, "dir");
/* Write the appropriate Node-action header */
@@ -403,26 +344,22 @@ dump_node(struct dump_edit_baton *eb,
do here but print node action information.
Node-action: change. */
- SVN_ERR(svn_stream_puts(eb->stream,
- SVN_REPOS_DUMPFILE_NODE_ACTION ": change\n"));
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "change");
+ break;
+
+ case svn_node_action_delete:
+ /* Node-action: delete */
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
break;
case svn_node_action_replace:
- if (is_copy)
- {
- /* Delete the original, and then re-add the replacement as a
- copy using recursive calls into this function. */
- SVN_ERR(dump_node(eb, repos_relpath, db, fb, svn_node_action_delete,
- FALSE, NULL, SVN_INVALID_REVNUM, pool));
- SVN_ERR(dump_node(eb, repos_relpath, db, fb, svn_node_action_add,
- is_copy, copyfrom_path, copyfrom_rev, pool));
- }
- else
+ if (! is_copy)
{
/* Node-action: replace */
- SVN_ERR(svn_stream_puts(eb->stream,
- SVN_REPOS_DUMPFILE_NODE_ACTION
- ": replace\n"));
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "replace");
/* Wait for a change_*_prop to be called before dumping
anything */
@@ -430,45 +367,36 @@ dump_node(struct dump_edit_baton *eb,
fb->dump_props = TRUE;
else if (db)
db->dump_props = TRUE;
+ break;
}
- break;
-
- case svn_node_action_delete:
- /* Node-action: delete */
- SVN_ERR(svn_stream_puts(eb->stream,
- SVN_REPOS_DUMPFILE_NODE_ACTION ": delete\n"));
+ else
+ {
+ /* More complex case: is_copy is true, and copyfrom_path/
+ copyfrom_rev are present: delete the original, and then re-add
+ it */
+ /* ### Why not write a 'replace' record? Don't know. */
- /* We can leave this routine quietly now. Nothing more to do-
- print a couple of newlines because we're not dumping props or
- text. */
- SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
+ /* ### Unusually, we end this 'delete' node record with only a single
+ blank line after the header block -- no extra blank line. */
+ SVN_ERR(dump_node_delete(eb->stream, repos_relpath, pool));
- break;
+ /* The remaining action is a non-replacing add-with-history */
+ /* action = svn_node_action_add; */
+ }
+ /* FALL THROUGH to 'add' */
case svn_node_action_add:
/* Node-action: add */
- SVN_ERR(svn_stream_puts(eb->stream,
- SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "add");
if (is_copy)
{
/* Node-copyfrom-rev / Node-copyfrom-path */
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV
- ": %ld\n"
- SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH
- ": %s\n",
- copyfrom_rev, copyfrom_path));
-
- /* Ugly hack: If a directory was copied from a previous
- revision, nothing like close_file() will be called to write two
- blank lines. If change_dir_prop() is called, props are dumped
- (along with the necessary PROPS-END\n\n and we're good. So
- set DUMP_NEWLINES here to print the newlines unless
- change_dir_prop() is called next otherwise the `svnadmin load`
- parser will fail. */
- if (db)
- db->dump_newlines = TRUE;
+ svn_repos__dumpfile_header_pushf(
+ headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV, "%ld", copyfrom_rev);
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH, copyfrom_path);
}
else
{
@@ -496,6 +424,11 @@ dump_node(struct dump_edit_baton *eb,
break;
}
+
+ /* Return the headers so far. We don't necessarily have all the headers
+ yet -- there may be property-related and content length headers to
+ come, if this was not a 'delete' record. */
+ *headers_p = headers;
return SVN_NO_ERROR;
}
@@ -504,35 +437,29 @@ dump_mkdir(struct dump_edit_baton *eb,
const char *repos_relpath,
apr_pool_t *pool)
{
- svn_stringbuf_t *prop_header, *prop_content;
- apr_size_t len;
- const char *buf;
+ svn_stringbuf_t *prop_content;
+ svn_repos__dumpfile_headers_t *headers
+ = svn_repos__dumpfile_headers_create(pool);
/* Node-path: ... */
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n",
- repos_relpath));
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_NODE_PATH, repos_relpath);
/* Node-kind: dir */
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n"));
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_NODE_KIND, "dir");
/* Node-action: add */
- SVN_ERR(svn_stream_puts(eb->stream,
- SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "add");
/* Dump the (empty) property block. */
- SVN_ERR(get_props_content(&prop_header, &prop_content,
+ SVN_ERR(get_props_content(headers, &prop_content,
apr_hash_make(pool), apr_hash_make(pool),
pool, pool));
- len = prop_header->len;
- SVN_ERR(svn_stream_write(eb->stream, prop_header->data, &len));
- len = prop_content->len;
- buf = apr_psprintf(pool, SVN_REPOS_DUMPFILE_CONTENT_LENGTH
- ": %" APR_SIZE_T_FMT "\n", len);
- SVN_ERR(svn_stream_puts(eb->stream, buf));
- SVN_ERR(svn_stream_puts(eb->stream, "\n"));
- SVN_ERR(svn_stream_write(eb->stream, prop_content->data, &len));
+ SVN_ERR(svn_repos__dump_node_record(eb->stream, headers, prop_content,
+ FALSE, 0, FALSE /*content_length_always*/,
+ pool));
/* Newlines to tie it all off. */
SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
@@ -540,40 +467,43 @@ dump_mkdir(struct dump_edit_baton *eb,
return SVN_NO_ERROR;
}
-/* Dump pending items from the specified node, to allow starting the dump
- of a child node */
+/* Dump pending headers and properties for the directory EB->pending_db (if
+ * not null), to allow starting the dump of a child node */
static svn_error_t *
-dump_pending(struct dump_edit_baton *eb,
- apr_pool_t *scratch_pool)
+dump_pending_dir(struct dump_edit_baton *eb,
+ apr_pool_t *scratch_pool)
{
- if (! eb->pending_baton)
+ struct dir_baton *db = eb->pending_db;
+ svn_stringbuf_t *prop_content = NULL;
+
+ if (! db)
return SVN_NO_ERROR;
- if (eb->pending_kind == svn_node_dir)
+ /* Some pending properties to dump? */
+ if (db->dump_props)
{
- struct dir_baton *db = eb->pending_baton;
+ SVN_ERR(get_props_content(db->headers, &prop_content,
+ db->props, db->deleted_props,
+ scratch_pool, scratch_pool));
+ }
+ SVN_ERR(svn_repos__dump_node_record(eb->stream, db->headers, prop_content,
+ FALSE, 0, FALSE /*content_length_always*/,
+ scratch_pool));
- /* Some pending properties to dump? */
- SVN_ERR(do_dump_props(NULL, eb->stream, db->props, db->deleted_props,
- &(db->dump_props), db->pool, scratch_pool));
+ /* No text is going to be dumped. Write a couple of newlines and
+ wait for the next node/ revision. */
+ SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
- /* Some pending newlines to dump? */
- SVN_ERR(do_dump_newlines(eb, &(db->dump_newlines), scratch_pool));
- }
- else if (eb->pending_kind == svn_node_file)
+ if (db->dump_props)
{
- struct file_baton *fb = eb->pending_baton;
-
- /* Some pending properties to dump? */
- SVN_ERR(do_dump_props(NULL, eb->stream, fb->props, fb->deleted_props,
- &(fb->dump_props), fb->pool, scratch_pool));
+ /* Cleanup so that data is never dumped twice. */
+ apr_hash_clear(db->props);
+ apr_hash_clear(db->deleted_props);
+ db->dump_props = FALSE;
}
- else
- abort();
/* Anything that was pending is pending no longer. */
- eb->pending_baton = NULL;
- eb->pending_kind = svn_node_none;
+ eb->pending_db = NULL;
return SVN_NO_ERROR;
}
@@ -594,8 +524,6 @@ open_root(void *edit_baton,
/* Clear the per-revision pool after each revision */
svn_pool_clear(eb->pool);
- LDR_DBG(("open_root %p\n", *root_baton));
-
if (eb->update_anchor_relpath)
{
int i;
@@ -628,16 +556,15 @@ open_root(void *edit_baton,
/* ... but for the source directory itself, we'll defer
to letting the typical plumbing handle this task. */
new_db = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
- edit_baton, NULL, TRUE, pool);
- SVN_ERR(dump_node(eb, new_db->repos_relpath, new_db,
+ edit_baton, NULL, pool);
+ SVN_ERR(dump_node(&new_db->headers,
+ eb, new_db->repos_relpath, new_db,
NULL, svn_node_action_add, FALSE,
NULL, SVN_INVALID_REVNUM, pool));
/* Remember that we've started but not yet finished
handling this directory. */
- new_db->written_out = TRUE;
- eb->pending_baton = new_db;
- eb->pending_kind = svn_node_dir;
+ eb->pending_db = new_db;
}
}
svn_pool_destroy(iterpool);
@@ -646,7 +573,7 @@ open_root(void *edit_baton,
if (! new_db)
{
new_db = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
- edit_baton, NULL, FALSE, pool);
+ edit_baton, NULL, pool);
}
*root_baton = new_db;
@@ -661,15 +588,13 @@ delete_entry(const char *path,
{
struct dir_baton *pb = parent_baton;
- LDR_DBG(("delete_entry %s\n", path));
-
- SVN_ERR(dump_pending(pb->eb, pool));
+ SVN_ERR(dump_pending_dir(pb->eb, pool));
/* We don't dump this deletion immediate. Rather, we add this path
to the deleted_entries of the parent directory baton. That way,
we can tell (later) an addition from a replacement. All the real
deletions get handled in close_directory(). */
- svn_hash_sets(pb->deleted_entries, apr_pstrdup(pb->eb->pool, path), pb);
+ svn_hash_sets(pb->deleted_entries, apr_pstrdup(pb->pool, path), pb);
return SVN_NO_ERROR;
}
@@ -683,40 +608,37 @@ add_directory(const char *path,
void **child_baton)
{
struct dir_baton *pb = parent_baton;
- void *val;
+ void *was_deleted;
struct dir_baton *new_db;
svn_boolean_t is_copy;
- LDR_DBG(("add_directory %s\n", path));
-
- SVN_ERR(dump_pending(pb->eb, pool));
+ SVN_ERR(dump_pending_dir(pb->eb, pool));
new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb,
- pb, TRUE, pb->eb->pool);
+ pb, pb->pool);
/* This might be a replacement -- is the path already deleted? */
- val = svn_hash_gets(pb->deleted_entries, path);
+ was_deleted = svn_hash_gets(pb->deleted_entries, path);
/* Detect an add-with-history */
is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
/* Dump the node */
- SVN_ERR(dump_node(pb->eb, new_db->repos_relpath, new_db, NULL,
- val ? svn_node_action_replace : svn_node_action_add,
+ SVN_ERR(dump_node(&new_db->headers,
+ pb->eb, new_db->repos_relpath, new_db, NULL,
+ was_deleted ? svn_node_action_replace : svn_node_action_add,
is_copy,
is_copy ? new_db->copyfrom_path : NULL,
is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
pool));
- if (val)
+ if (was_deleted)
/* Delete the path, it's now been dumped */
svn_hash_sets(pb->deleted_entries, path, NULL);
/* Remember that we've started, but not yet finished handling this
directory. */
- new_db->written_out = TRUE;
- pb->eb->pending_baton = new_db;
- pb->eb->pending_kind = svn_node_dir;
+ pb->eb->pending_db = new_db;
*child_baton = new_db;
return SVN_NO_ERROR;
@@ -734,9 +656,7 @@ open_directory(const char *path,
const char *copyfrom_path = NULL;
svn_revnum_t copyfrom_rev = SVN_INVALID_REVNUM;
- LDR_DBG(("open_directory %s\n", path));
-
- SVN_ERR(dump_pending(pb->eb, pool));
+ SVN_ERR(dump_pending_dir(pb->eb, pool));
/* If the parent directory has explicit comparison path and rev,
record the same for this one. */
@@ -744,12 +664,12 @@ open_directory(const char *path,
{
copyfrom_path = svn_relpath_join(pb->copyfrom_path,
svn_relpath_basename(path, NULL),
- pb->eb->pool);
+ pb->pool);
copyfrom_rev = pb->copyfrom_rev;
}
new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb, pb,
- FALSE, pb->eb->pool);
+ pb->pool);
*child_baton = new_db;
return SVN_NO_ERROR;
@@ -763,12 +683,10 @@ close_directory(void *dir_baton,
apr_hash_index_t *hi;
svn_boolean_t this_pending;
- LDR_DBG(("close_directory %p\n", dir_baton));
-
/* Remember if this directory is the one currently pending. */
- this_pending = (db->eb->pending_baton == db);
+ this_pending = (db->eb->pending_db == db);
- SVN_ERR(dump_pending(db->eb, pool));
+ SVN_ERR(dump_pending_dir(db->eb, pool));
/* If this directory was pending, then dump_pending() should have
taken care of all the props and such. Of course, the only way
@@ -781,22 +699,23 @@ close_directory(void *dir_baton,
directory. */
if ((! this_pending) && (db->dump_props))
{
- SVN_ERR(dump_node(db->eb, db->repos_relpath, db, NULL,
+ SVN_ERR(dump_node(&db->headers,
+ db->eb, db->repos_relpath, db, NULL,
svn_node_action_change, FALSE,
NULL, SVN_INVALID_REVNUM, pool));
- db->eb->pending_baton = db;
- db->eb->pending_kind = svn_node_dir;
- SVN_ERR(dump_pending(db->eb, pool));
+ db->eb->pending_db = db;
+ SVN_ERR(dump_pending_dir(db->eb, pool));
}
/* Dump the deleted directory entries */
for (hi = apr_hash_first(pool, db->deleted_entries); hi;
hi = apr_hash_next(hi))
{
- const char *path = svn__apr_hash_index_key(hi);
+ const char *path = apr_hash_this_key(hi);
- SVN_ERR(dump_node(db->eb, path, NULL, NULL, svn_node_action_delete,
- FALSE, NULL, SVN_INVALID_REVNUM, pool));
+ SVN_ERR(dump_node_delete(db->eb->stream, path, pool));
+ /* This deletion record is complete -- write an extra newline */
+ SVN_ERR(svn_stream_puts(db->eb->stream, "\n"));
}
/* ### should be unnecessary */
@@ -815,17 +734,15 @@ add_file(const char *path,
{
struct dir_baton *pb = parent_baton;
struct file_baton *fb;
- void *val;
+ void *was_deleted;
- LDR_DBG(("add_file %s\n", path));
-
- SVN_ERR(dump_pending(pb->eb, pool));
+ SVN_ERR(dump_pending_dir(pb->eb, pool));
/* Make the file baton. */
fb = make_file_baton(path, pb, pool);
/* This might be a replacement -- is the path already deleted? */
- val = svn_hash_gets(pb->deleted_entries, path);
+ was_deleted = svn_hash_gets(pb->deleted_entries, path);
/* Detect add-with-history. */
if (ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev))
@@ -834,10 +751,10 @@ add_file(const char *path,
fb->copyfrom_rev = copyfrom_rev;
fb->is_copy = TRUE;
}
- fb->action = val ? svn_node_action_replace : svn_node_action_add;
+ fb->action = was_deleted ? svn_node_action_replace : svn_node_action_add;
/* Delete the path, it's now been dumped. */
- if (val)
+ if (was_deleted)
svn_hash_sets(pb->deleted_entries, path, NULL);
*file_baton = fb;
@@ -854,9 +771,7 @@ open_file(const char *path,
struct dir_baton *pb = parent_baton;
struct file_baton *fb;
- LDR_DBG(("open_file %s\n", path));
-
- SVN_ERR(dump_pending(pb->eb, pool));
+ SVN_ERR(dump_pending_dir(pb->eb, pool));
/* Make the file baton. */
fb = make_file_baton(path, pb, pool);
@@ -867,7 +782,7 @@ open_file(const char *path,
{
fb->copyfrom_path = svn_relpath_join(pb->copyfrom_path,
svn_relpath_basename(path, NULL),
- pb->eb->pool);
+ pb->pool);
fb->copyfrom_rev = pb->copyfrom_rev;
}
@@ -884,13 +799,11 @@ change_dir_prop(void *parent_baton,
struct dir_baton *db = parent_baton;
svn_boolean_t this_pending;
- LDR_DBG(("change_dir_prop %p\n", parent_baton));
-
/* This directory is not pending, but something else is, so handle
the "something else". */
- this_pending = (db->eb->pending_baton == db);
+ this_pending = (db->eb->pending_db == db);
if (! this_pending)
- SVN_ERR(dump_pending(db->eb, pool));
+ SVN_ERR(dump_pending_dir(db->eb, pool));
if (svn_property_kind2(name) != svn_prop_regular_kind)
return SVN_NO_ERROR;
@@ -902,9 +815,7 @@ change_dir_prop(void *parent_baton,
else
svn_hash_sets(db->deleted_props, apr_pstrdup(db->pool, name), "");
- /* Make sure we eventually output the props, and disable printing
- a couple of extra newlines */
- db->dump_newlines = FALSE;
+ /* Make sure we eventually output the props */
db->dump_props = TRUE;
return SVN_NO_ERROR;
@@ -918,8 +829,6 @@ change_file_prop(void *file_baton,
{
struct file_baton *fb = file_baton;
- LDR_DBG(("change_file_prop %p\n", file_baton));
-
if (svn_property_kind2(name) != svn_prop_regular_kind)
return SVN_NO_ERROR;
@@ -939,22 +848,6 @@ change_file_prop(void *file_baton,
}
static svn_error_t *
-window_handler(svn_txdelta_window_t *window, void *baton)
-{
- struct handler_baton *hb = baton;
- static svn_error_t *err;
-
- err = hb->apply_handler(window, hb->apply_baton);
- if (window != NULL && !err)
- return SVN_NO_ERROR;
-
- if (err)
- SVN_ERR(err);
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
apply_textdelta(void *file_baton, const char *base_checksum,
apr_pool_t *pool,
svn_txdelta_window_handler_t *handler,
@@ -962,31 +855,19 @@ apply_textdelta(void *file_baton, const char *base_checksum,
{
struct file_baton *fb = file_baton;
struct dump_edit_baton *eb = fb->eb;
- struct handler_baton *hb;
svn_stream_t *delta_filestream;
- LDR_DBG(("apply_textdelta %p\n", file_baton));
-
- /* This is custom handler_baton, allocated from a separate pool. */
- hb = apr_pcalloc(eb->pool, sizeof(*hb));
-
/* Use a temporary file to measure the Text-content-length */
delta_filestream = svn_stream_from_aprfile2(eb->delta_file, TRUE, pool);
/* Prepare to write the delta to the delta_filestream */
- svn_txdelta_to_svndiff3(&(hb->apply_handler), &(hb->apply_baton),
+ svn_txdelta_to_svndiff3(handler, handler_baton,
delta_filestream, 0,
SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, pool);
/* Record that there's text to be dumped, and its base checksum. */
fb->dump_text = TRUE;
- fb->base_checksum = apr_pstrdup(eb->pool, base_checksum);
-
- /* The actual writing takes place when this function has
- finished. Set handler and handler_baton now so for
- window_handler() */
- *handler = window_handler;
- *handler_baton = hb;
+ fb->base_checksum = apr_pstrdup(fb->pool, base_checksum);
return SVN_NO_ERROR;
}
@@ -999,22 +880,25 @@ close_file(void *file_baton,
struct file_baton *fb = file_baton;
struct dump_edit_baton *eb = fb->eb;
apr_finfo_t *info = apr_pcalloc(pool, sizeof(apr_finfo_t));
- svn_stringbuf_t *propstring;
+ svn_stringbuf_t *propstring = NULL;
+ svn_repos__dumpfile_headers_t *headers;
- LDR_DBG(("close_file %p\n", file_baton));
+ SVN_ERR(dump_pending_dir(eb, pool));
- SVN_ERR(dump_pending(eb, pool));
-
- /* Dump the node. */
- SVN_ERR(dump_node(eb, fb->repos_relpath, NULL, fb,
+ /* Start dumping this node, by collecting some basic headers for it. */
+ SVN_ERR(dump_node(&headers, eb, fb->repos_relpath, NULL, fb,
fb->action, fb->is_copy, fb->copyfrom_path,
fb->copyfrom_rev, pool));
/* Some pending properties to dump? We'll dump just the headers for
now, then dump the actual propchange content only after dumping
the text headers too (if present). */
- SVN_ERR(do_dump_props(&propstring, eb->stream, fb->props, fb->deleted_props,
- &(fb->dump_props), pool, pool));
+ if (fb->dump_props)
+ {
+ SVN_ERR(get_props_content(headers, &propstring,
+ fb->props, fb->deleted_props,
+ pool, pool));
+ }
/* Dump the text headers */
if (fb->dump_text)
@@ -1022,9 +906,8 @@ close_file(void *file_baton,
apr_status_t err;
/* Text-delta: true */
- SVN_ERR(svn_stream_puts(eb->stream,
- SVN_REPOS_DUMPFILE_TEXT_DELTA
- ": true\n"));
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_TEXT_DELTA, "true");
err = apr_file_info_get(info, APR_FINFO_SIZE, eb->delta_file);
if (err)
@@ -1032,43 +915,22 @@ close_file(void *file_baton,
if (fb->base_checksum)
/* Text-delta-base-md5: */
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_MD5
- ": %s\n",
- fb->base_checksum));
-
- /* Text-content-length: 39 */
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH
- ": %lu\n",
- (unsigned long)info->size));
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_MD5, fb->base_checksum);
/* Text-content-md5: 82705804337e04dcd0e586bfa2389a7f */
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_TEXT_CONTENT_MD5
- ": %s\n",
- text_checksum));
+ svn_repos__dumpfile_header_push(
+ headers, SVN_REPOS_DUMPFILE_TEXT_CONTENT_MD5, text_checksum);
}
- /* Content-length: 1549 */
- /* If both text and props are absent, skip this header */
- if (fb->dump_props)
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_CONTENT_LENGTH
- ": %ld\n\n",
- (unsigned long)info->size + propstring->len));
- else if (fb->dump_text)
- SVN_ERR(svn_stream_printf(eb->stream, pool,
- SVN_REPOS_DUMPFILE_CONTENT_LENGTH
- ": %ld\n\n",
- (unsigned long)info->size));
-
- /* Dump the props now */
+ /* Dump the headers and props now */
+ SVN_ERR(svn_repos__dump_node_record(eb->stream, headers, propstring,
+ fb->dump_text, info->size,
+ FALSE /*content_length_always*/,
+ pool));
+
if (fb->dump_props)
{
- SVN_ERR(svn_stream_write(eb->stream, propstring->data,
- &(propstring->len)));
-
/* Cleanup */
fb->dump_props = FALSE;
apr_hash_clear(fb->props);
@@ -1235,7 +1097,7 @@ svn_rdump__get_dump_editor(const svn_delta_editor_t **editor,
eb->ra_session = ra_session;
eb->update_anchor_relpath = update_anchor_relpath;
eb->current_revision = revision;
- eb->pending_kind = svn_node_none;
+ eb->pending_db = NULL;
/* Create a special per-revision pool */
eb->pool = svn_pool_create(pool);
diff --git a/subversion/svnrdump/load_editor.c b/subversion/svnrdump/load_editor.c
index c35a289..15dac6e 100644
--- a/subversion/svnrdump/load_editor.c
+++ b/subversion/svnrdump/load_editor.c
@@ -43,14 +43,7 @@
#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
-#if 0
-#define LDR_DBG(x) SVN_DBG(x)
-#else
-#define LDR_DBG(x) while(0)
-#endif
-
-
/**
* General baton used by the parser functions.
*/
@@ -68,9 +61,6 @@ struct parse_baton
/* To bleep, or not to bleep? (What kind of question is that?) */
svn_boolean_t quiet;
- /* UUID found in the dumpstream, if any; NULL otherwise. */
- const char *uuid;
-
/* Root URL of the target repository. */
const char *root_url;
@@ -93,17 +83,20 @@ struct parse_baton
/* The oldest revision loaded from the dump stream, or
SVN_INVALID_REVNUM if none have been loaded. */
svn_revnum_t oldest_dumpstream_rev;
+
+ /* An hash containing specific revision properties to skip while
+ loading. */
+ apr_hash_t *skip_revprops;
};
/**
* Use to wrap the dir_context_t in commit.c so we can keep track of
- * depth, relpath and parent for open_directory and close_directory.
+ * relpath and parent for open_directory and close_directory.
*/
struct directory_baton
{
void *baton;
const char *relpath;
- int depth;
/* The copy-from source of this directory, no matter whether it is
copied explicitly (the root node of a copy) or implicitly (being an
@@ -190,160 +183,6 @@ get_revision_mapping(apr_hash_t *rev_map,
}
-/* Prepend the mergeinfo source paths in MERGEINFO_ORIG with
- PARENT_DIR, and return it in *MERGEINFO_VAL. */
-/* ### FIXME: Consider somehow sharing code with
- ### libsvn_repos/load-fs-vtable.c:prefix_mergeinfo_paths() */
-static svn_error_t *
-prefix_mergeinfo_paths(svn_string_t **mergeinfo_val,
- const svn_string_t *mergeinfo_orig,
- const char *parent_dir,
- apr_pool_t *pool)
-{
- apr_hash_t *prefixed_mergeinfo, *mergeinfo;
- apr_hash_index_t *hi;
- void *rangelist;
-
- SVN_ERR(svn_mergeinfo_parse(&mergeinfo, mergeinfo_orig->data, pool));
- prefixed_mergeinfo = apr_hash_make(pool);
- for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
- {
- const void *key;
- const char *path, *merge_source;
-
- apr_hash_this(hi, &key, NULL, &rangelist);
- merge_source = svn_relpath_canonicalize(key, pool);
-
- /* The svn:mergeinfo property syntax demands a repos abspath */
- path = svn_fspath__canonicalize(svn_relpath_join(parent_dir,
- merge_source, pool),
- pool);
- svn_hash_sets(prefixed_mergeinfo, path, rangelist);
- }
- return svn_mergeinfo_to_string(mergeinfo_val, prefixed_mergeinfo, pool);
-}
-
-
-/* Examine the mergeinfo in INITIAL_VAL, renumber revisions in rangelists
- as appropriate, and return the (possibly new) mergeinfo in *FINAL_VAL
- (allocated from POOL). */
-/* ### FIXME: Consider somehow sharing code with
- ### libsvn_repos/load-fs-vtable.c:renumber_mergeinfo_revs() */
-static svn_error_t *
-renumber_mergeinfo_revs(svn_string_t **final_val,
- const svn_string_t *initial_val,
- struct revision_baton *rb,
- apr_pool_t *pool)
-{
- apr_pool_t *subpool = svn_pool_create(pool);
- svn_mergeinfo_t mergeinfo, predates_stream_mergeinfo;
- svn_mergeinfo_t final_mergeinfo = apr_hash_make(subpool);
- apr_hash_index_t *hi;
-
- SVN_ERR(svn_mergeinfo_parse(&mergeinfo, initial_val->data, subpool));
-
- /* Issue #3020
- http://subversion.tigris.org/issues/show_bug.cgi?id=3020#desc16
- Remove mergeinfo older than the oldest revision in the dump stream
- and adjust its revisions by the difference between the head rev of
- the target repository and the current dump stream rev. */
- if (rb->pb->oldest_dumpstream_rev > 1)
- {
- SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
- &predates_stream_mergeinfo, mergeinfo,
- rb->pb->oldest_dumpstream_rev - 1, 0,
- TRUE, subpool, subpool));
- SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
- &mergeinfo, mergeinfo,
- rb->pb->oldest_dumpstream_rev - 1, 0,
- FALSE, subpool, subpool));
- SVN_ERR(svn_mergeinfo__adjust_mergeinfo_rangelists(
- &predates_stream_mergeinfo,
- predates_stream_mergeinfo,
- -rb->rev_offset, subpool, subpool));
- }
- else
- {
- predates_stream_mergeinfo = NULL;
- }
-
- for (hi = apr_hash_first(subpool, mergeinfo); hi; hi = apr_hash_next(hi))
- {
- svn_rangelist_t *rangelist;
- struct parse_baton *pb = rb->pb;
- int i;
- const void *path;
- apr_ssize_t pathlen;
- void *val;
-
- apr_hash_this(hi, &path, &pathlen, &val);
- rangelist = val;
-
- /* Possibly renumber revisions in merge source's rangelist. */
- for (i = 0; i < rangelist->nelts; i++)
- {
- svn_revnum_t rev_from_map;
- svn_merge_range_t *range = APR_ARRAY_IDX(rangelist, i,
- svn_merge_range_t *);
- rev_from_map = get_revision_mapping(pb->rev_map, range->start);
- if (SVN_IS_VALID_REVNUM(rev_from_map))
- {
- range->start = rev_from_map;
- }
- else if (range->start == pb->oldest_dumpstream_rev - 1)
- {
- /* Since the start revision of svn_merge_range_t are not
- inclusive there is one possible valid start revision that
- won't be found in the PB->REV_MAP mapping of load stream
- revsions to loaded revisions: The revision immediately
- preceeding the oldest revision from the load stream.
- This is a valid revision for mergeinfo, but not a valid
- copy from revision (which PB->REV_MAP also maps for) so it
- will never be in the mapping.
-
- If that is what we have here, then find the mapping for the
- oldest rev from the load stream and subtract 1 to get the
- renumbered, non-inclusive, start revision. */
- rev_from_map = get_revision_mapping(pb->rev_map,
- pb->oldest_dumpstream_rev);
- if (SVN_IS_VALID_REVNUM(rev_from_map))
- range->start = rev_from_map - 1;
- }
- else
- {
- /* If we can't remap the start revision then don't even bother
- trying to remap the end revision. It's possible we might
- actually succeed at the latter, which can result in invalid
- mergeinfo with a start rev > end rev. If that gets into the
- repository then a world of bustage breaks loose anytime that
- bogus mergeinfo is parsed. See
- http://subversion.tigris.org/issues/show_bug.cgi?id=3020#desc16.
- */
- continue;
- }
-
- rev_from_map = get_revision_mapping(pb->rev_map, range->end);
- if (SVN_IS_VALID_REVNUM(rev_from_map))
- range->end = rev_from_map;
- }
- apr_hash_set(final_mergeinfo, path, pathlen, rangelist);
- }
-
- if (predates_stream_mergeinfo)
- {
- SVN_ERR(svn_mergeinfo_merge2(final_mergeinfo, predates_stream_mergeinfo,
- subpool, subpool));
- }
-
- SVN_ERR(svn_mergeinfo__canonicalize_ranges(final_mergeinfo, subpool));
-
- SVN_ERR(svn_mergeinfo_to_string(final_val, final_mergeinfo, pool));
- svn_pool_destroy(subpool);
-
- return SVN_NO_ERROR;
-}
-
-
static svn_error_t *
commit_callback(const svn_commit_info_t *commit_info,
void *baton,
@@ -564,8 +403,8 @@ new_revision_record(void **revision_baton,
for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
{
- const char *hname = svn__apr_hash_index_key(hi);
- const char *hval = svn__apr_hash_index_val(hi);
+ const char *hname = apr_hash_this_key(hi);
+ const char *hval = apr_hash_this_val(hi);
if (strcmp(hname, SVN_REPOS_DUMPFILE_REVISION_NUMBER) == 0)
rb->rev = atoi(hval);
@@ -606,9 +445,6 @@ uuid_record(const char *uuid,
void *parse_baton,
apr_pool_t *pool)
{
- struct parse_baton *pb;
- pb = parse_baton;
- pb->uuid = apr_pstrdup(pool, uuid);
return SVN_NO_ERROR;
}
@@ -704,8 +540,6 @@ new_node_record(void **node_baton,
rb->rev - rb->rev_offset - 1,
rb->pool, &child_baton));
- LDR_DBG(("Opened root %p\n", child_baton));
-
/* child_baton corresponds to the root directory baton here */
push_directory(rb, child_baton, "", TRUE /*is_added*/,
NULL, SVN_INVALID_REVNUM);
@@ -713,8 +547,8 @@ new_node_record(void **node_baton,
for (hi = apr_hash_first(rb->pool, headers); hi; hi = apr_hash_next(hi))
{
- const char *hname = svn__apr_hash_index_key(hi);
- const char *hval = svn__apr_hash_index_val(hi);
+ const char *hname = apr_hash_this_key(hi);
+ const char *hval = apr_hash_this_val(hi);
/* Parse the different kinds of headers we can encounter and
stuff them into the node_baton for writing later */
@@ -741,6 +575,9 @@ new_node_record(void **node_baton,
nb->copyfrom_path = apr_pstrdup(rb->pool, hval);
}
+ /* Before handling the new node, ensure depth-first editing order by
+ traversing the directory hierarchy from the old node's to the new
+ node's parent directory. */
nb_dirname = svn_relpath_dirname(nb->path, pool);
if (svn_path_compare_paths(nb_dirname,
rb->db->relpath) != 0)
@@ -751,9 +588,6 @@ new_node_record(void **node_baton,
int i;
apr_size_t n;
- /* Before attempting to handle the action, call open_directory
- for all the path components and set the directory baton
- accordingly */
ancestor_path =
svn_relpath_get_longest_ancestor(nb_dirname,
rb->db->relpath, pool);
@@ -771,7 +605,6 @@ new_node_record(void **node_baton,
/* Don't worry about destroying the actual rb->db object,
since the pool we're using has the lifetime of one
revision anyway */
- LDR_DBG(("Closing dir %p\n", rb->db->baton));
SVN_ERR(commit_editor->close_directory(rb->db->baton, rb->pool));
rb->db = rb->db->parent;
}
@@ -786,7 +619,6 @@ new_node_record(void **node_baton,
rb->db->baton,
rb->rev - rb->rev_offset - 1,
rb->pool, &child_baton));
- LDR_DBG(("Opened dir %p\n", child_baton));
push_directory(rb, child_baton, relpath_compose, TRUE /*is_added*/,
NULL, SVN_INVALID_REVNUM);
}
@@ -816,6 +648,7 @@ new_node_record(void **node_baton,
if (rb->pb->parent_dir)
nb->copyfrom_path = svn_relpath_join(rb->pb->parent_dir,
nb->copyfrom_path, rb->pool);
+ /* Convert to a URL, as the commit editor requires. */
nb->copyfrom_url = svn_path_url_add_component2(rb->pb->root_url,
nb->copyfrom_path,
rb->pool);
@@ -826,7 +659,6 @@ new_node_record(void **node_baton,
{
case svn_node_action_delete:
case svn_node_action_replace:
- LDR_DBG(("Deleting entry %s in %p\n", nb->path, rb->db->baton));
SVN_ERR(commit_editor->delete_entry(nb->path,
rb->rev - rb->rev_offset - 1,
rb->db->baton, rb->pool));
@@ -843,16 +675,12 @@ new_node_record(void **node_baton,
nb->copyfrom_url,
nb->copyfrom_rev,
rb->pool, &(nb->file_baton)));
- LDR_DBG(("Added file %s to dir %p as %p\n",
- nb->path, rb->db->baton, nb->file_baton));
break;
case svn_node_dir:
SVN_ERR(commit_editor->add_directory(nb->path, rb->db->baton,
nb->copyfrom_url,
nb->copyfrom_rev,
rb->pool, &child_baton));
- LDR_DBG(("Added dir %s to dir %p as %p\n",
- nb->path, rb->db->baton, child_baton));
push_directory(rb, child_baton, nb->path, TRUE /*is_added*/,
nb->copyfrom_path, nb->copyfrom_rev);
break;
@@ -896,11 +724,13 @@ set_revision_property(void *baton,
if (rb->rev > 0)
{
- svn_hash_sets(rb->revprop_table,
- apr_pstrdup(rb->pool, name),
- svn_string_dup(value, rb->pool));
+ if (! svn_hash_gets(rb->pb->skip_revprops, name))
+ svn_hash_sets(rb->revprop_table,
+ apr_pstrdup(rb->pool, name),
+ svn_string_dup(value, rb->pool));
}
- else if (rb->rev_offset == -1)
+ else if (rb->rev_offset == -1
+ && ! svn_hash_gets(rb->pb->skip_revprops, name))
{
/* Special case: set revision 0 properties directly (which is
safe because the commit_editor hasn't been created yet), but
@@ -925,51 +755,30 @@ set_node_property(void *baton,
const svn_string_t *value)
{
struct node_baton *nb = baton;
+ struct revision_baton *rb = nb->rb;
+ struct parse_baton *pb = rb->pb;
apr_pool_t *pool = nb->rb->pool;
svn_prop_t *prop;
if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0)
{
- svn_string_t *renumbered_mergeinfo;
- svn_string_t prop_val;
-
- /* Tolerate mergeinfo with "\r\n" line endings because some
- dumpstream sources might contain as much. If so normalize
- the line endings to '\n' and make a notification to
- PARSE_BATON->FEEDBACK_STREAM that we have made this
- correction. */
- if (strstr(value->data, "\r"))
+ svn_string_t *new_value;
+ svn_error_t *err;
+
+ err = svn_repos__adjust_mergeinfo_property(&new_value, value,
+ pb->parent_dir,
+ pb->rev_map,
+ pb->oldest_dumpstream_rev,
+ rb->rev_offset,
+ NULL, NULL, /*notify*/
+ pool, pool);
+ if (err)
{
- const char *prop_eol_normalized;
-
- SVN_ERR(svn_subst_translate_cstring2(value->data,
- &prop_eol_normalized,
- "\n", /* translate to LF */
- FALSE, /* no repair */
- NULL, /* no keywords */
- FALSE, /* no expansion */
- pool));
- prop_val.data = prop_eol_normalized;
- prop_val.len = strlen(prop_eol_normalized);
- value = &prop_val;
-
- /* ### TODO: notify? */
+ return svn_error_quick_wrap(err,
+ _("Invalid svn:mergeinfo value"));
}
- /* Renumber mergeinfo as appropriate. */
- SVN_ERR(renumber_mergeinfo_revs(&renumbered_mergeinfo, value,
- nb->rb, pool));
- value = renumbered_mergeinfo;
-
- if (nb->rb->pb->parent_dir)
- {
- /* Prefix the merge source paths with PB->parent_dir. */
- /* ASSUMPTION: All source paths are included in the dump stream. */
- svn_string_t *mergeinfo_val;
- SVN_ERR(prefix_mergeinfo_paths(&mergeinfo_val, value,
- nb->rb->pb->parent_dir, pool));
- value = mergeinfo_val;
- }
+ value = new_value;
}
SVN_ERR(svn_rdump__normalize_prop(name, &value, pool));
@@ -978,7 +787,7 @@ set_node_property(void *baton,
prop = apr_palloc(nb->rb->pool, sizeof (*prop));
prop->name = apr_pstrdup(pool, name);
- prop->value = value ? svn_string_dup(value, pool) : NULL;
+ prop->value = svn_string_dup(value, pool);
svn_hash_sets(nb->prop_changes, prop->name, prop);
return SVN_NO_ERROR;
@@ -1024,7 +833,6 @@ remove_node_props(void *baton)
/* Find the path and revision that has the node's original properties */
if (ARE_VALID_COPY_ARGS(nb->copyfrom_path, nb->copyfrom_rev))
{
- LDR_DBG(("using nb->copyfrom %s@%ld", nb->copyfrom_path, nb->copyfrom_rev));
orig_path = nb->copyfrom_path;
orig_rev = nb->copyfrom_rev;
}
@@ -1033,8 +841,6 @@ remove_node_props(void *baton)
{
/* If this is a dir, then it's described by rb->db;
if this is a file, then it's a child of the dir in rb->db. */
- LDR_DBG(("using rb->db->copyfrom (k=%d) %s@%ld",
- nb->kind, rb->db->copyfrom_path, rb->db->copyfrom_rev));
orig_path = (nb->kind == svn_node_dir)
? rb->db->copyfrom_path
: svn_relpath_join(rb->db->copyfrom_path,
@@ -1044,13 +850,11 @@ remove_node_props(void *baton)
}
else
{
- LDR_DBG(("using self.path@head %s@%ld", nb->path, SVN_INVALID_REVNUM));
/* ### Should we query at a known, fixed, "head" revision number
instead of passing SVN_INVALID_REVNUM and getting a moving target? */
orig_path = nb->path;
orig_rev = SVN_INVALID_REVNUM;
}
- LDR_DBG(("Trying %s@%ld", orig_path, orig_rev));
if ((nb->action == svn_node_action_add
|| nb->action == svn_node_action_replace)
@@ -1071,7 +875,7 @@ remove_node_props(void *baton)
for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
{
- const char *name = svn__apr_hash_index_key(hi);
+ const char *name = apr_hash_this_key(hi);
svn_prop_kind_t kind = svn_property_kind2(name);
if (kind == svn_prop_regular_kind)
@@ -1091,7 +895,6 @@ set_fulltext(svn_stream_t **stream,
void *handler_baton;
apr_pool_t *pool = nb->rb->pool;
- LDR_DBG(("Setting fulltext for %p\n", nb->file_baton));
SVN_ERR(commit_editor->apply_textdelta(nb->file_baton, nb->base_checksum,
pool, &handler, &handler_baton));
*stream = svn_txdelta_target_push(handler, handler_baton,
@@ -1108,7 +911,6 @@ apply_textdelta(svn_txdelta_window_handler_t *handler,
const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
apr_pool_t *pool = nb->rb->pool;
- LDR_DBG(("Applying textdelta to %p\n", nb->file_baton));
SVN_ERR(commit_editor->apply_textdelta(nb->file_baton, nb->base_checksum,
pool, handler, handler_baton));
@@ -1126,8 +928,8 @@ close_node(void *baton)
for (hi = apr_hash_first(pool, nb->prop_changes);
hi; hi = apr_hash_next(hi))
{
- const char *name = svn__apr_hash_index_key(hi);
- svn_prop_t *prop = svn__apr_hash_index_val(hi);
+ const char *name = apr_hash_this_key(hi);
+ svn_prop_t *prop = apr_hash_this_val(hi);
switch (nb->kind)
{
@@ -1148,7 +950,6 @@ close_node(void *baton)
deleted the file (which doesn't require us to open it). */
if ((nb->kind == svn_node_file) && (nb->file_baton))
{
- LDR_DBG(("Closing file %p\n", nb->file_baton));
SVN_ERR(commit_editor->close_file(nb->file_baton, NULL, nb->rb->pool));
}
@@ -1178,12 +979,10 @@ close_revision(void *baton)
session itself */
while (rb->db && rb->db->parent)
{
- LDR_DBG(("Closing dir %p\n", rb->db->baton));
SVN_ERR(commit_editor->close_directory(rb->db->baton, rb->pool));
rb->db = rb->db->parent;
}
/* root dir's baton */
- LDR_DBG(("Closing edit on %p\n", commit_edit_baton));
SVN_ERR(commit_editor->close_directory(rb->db->baton, rb->pool));
SVN_ERR(commit_editor->close_edit(commit_edit_baton, rb->pool));
}
@@ -1201,8 +1000,6 @@ close_revision(void *baton)
rb->rev - rb->rev_offset - 1,
rb->pool, &child_baton));
- LDR_DBG(("Opened root %p\n", child_baton));
- LDR_DBG(("Closing edit on %p\n", commit_edit_baton));
SVN_ERR(commit_editor->close_directory(child_baton, rb->pool));
SVN_ERR(commit_editor->close_edit(commit_edit_baton, rb->pool));
}
@@ -1222,16 +1019,22 @@ close_revision(void *baton)
if (SVN_IS_VALID_REVNUM(committed_rev))
{
- SVN_ERR(svn_repos__validate_prop(SVN_PROP_REVISION_DATE,
- rb->datestamp, rb->pool));
- SVN_ERR(svn_ra_change_rev_prop2(rb->pb->session, committed_rev,
- SVN_PROP_REVISION_DATE,
- NULL, rb->datestamp, rb->pool));
- SVN_ERR(svn_repos__validate_prop(SVN_PROP_REVISION_AUTHOR,
- rb->author, rb->pool));
- SVN_ERR(svn_ra_change_rev_prop2(rb->pb->session, committed_rev,
- SVN_PROP_REVISION_AUTHOR,
- NULL, rb->author, rb->pool));
+ if (!svn_hash_gets(rb->pb->skip_revprops, SVN_PROP_REVISION_DATE))
+ {
+ SVN_ERR(svn_repos__validate_prop(SVN_PROP_REVISION_DATE,
+ rb->datestamp, rb->pool));
+ SVN_ERR(svn_ra_change_rev_prop2(rb->pb->session, committed_rev,
+ SVN_PROP_REVISION_DATE,
+ NULL, rb->datestamp, rb->pool));
+ }
+ if (!svn_hash_gets(rb->pb->skip_revprops, SVN_PROP_REVISION_AUTHOR))
+ {
+ SVN_ERR(svn_repos__validate_prop(SVN_PROP_REVISION_AUTHOR,
+ rb->author, rb->pool));
+ SVN_ERR(svn_ra_change_rev_prop2(rb->pb->session, committed_rev,
+ SVN_PROP_REVISION_AUTHOR,
+ NULL, rb->author, rb->pool));
+ }
}
svn_pool_destroy(rb->pool);
@@ -1244,6 +1047,7 @@ svn_rdump__load_dumpstream(svn_stream_t *stream,
svn_ra_session_t *session,
svn_ra_session_t *aux_session,
svn_boolean_t quiet,
+ apr_hash_t *skip_revprops,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *pool)
@@ -1287,6 +1091,7 @@ svn_rdump__load_dumpstream(svn_stream_t *stream,
parse_baton->rev_map = apr_hash_make(pool);
parse_baton->last_rev_mapped = SVN_INVALID_REVNUM;
parse_baton->oldest_dumpstream_rev = SVN_INVALID_REVNUM;
+ parse_baton->skip_revprops = skip_revprops;
err = svn_repos_parse_dumpstream3(stream, parser, parse_baton, FALSE,
cancel_func, cancel_baton, pool);
diff --git a/subversion/svnrdump/svnrdump.c b/subversion/svnrdump/svnrdump.c
index 6bf409c..df0286b 100644
--- a/subversion/svnrdump/svnrdump.c
+++ b/subversion/svnrdump/svnrdump.c
@@ -39,6 +39,7 @@
#include "svnrdump.h"
+#include "private/svn_repos_private.h"
#include "private/svn_cmdline_private.h"
#include "private/svn_ra_private.h"
@@ -80,9 +81,11 @@ enum svn_svnrdump__longopt_t
opt_auth_password,
opt_auth_nocache,
opt_non_interactive,
+ opt_skip_revprop,
opt_force_interactive,
opt_incremental,
opt_trust_server_cert,
+ opt_trust_server_cert_failures,
opt_version
};
@@ -92,6 +95,7 @@ enum svn_svnrdump__longopt_t
opt_auth_password, \
opt_auth_nocache, \
opt_trust_server_cert, \
+ opt_trust_server_cert_failures, \
opt_non_interactive, \
opt_force_interactive
@@ -106,7 +110,7 @@ static const svn_opt_subcommand_desc2_t svnrdump__cmd_table[] =
{ "load", load_cmd, { 0 },
N_("usage: svnrdump load URL\n\n"
"Load a 'dumpfile' given on stdin to a repository at remote URL.\n"),
- { 'q', SVN_SVNRDUMP__BASE_OPTIONS } },
+ { 'q', opt_skip_revprop, SVN_SVNRDUMP__BASE_OPTIONS } },
{ "help", 0, { "?", "h" },
N_("usage: svnrdump help [SUBCOMMAND...]\n\n"
"Describe the usage of this program or its subcommands.\n"),
@@ -122,6 +126,8 @@ static const apr_getopt_option_t svnrdump__options[] =
N_("no progress (only errors) to stderr")},
{"incremental", opt_incremental, 0,
N_("dump incrementally")},
+ {"skip-revprop", opt_skip_revprop, 1,
+ N_("skip revision property ARG (e.g., \"svn:author\")")},
{"config-dir", opt_config_dir, 1,
N_("read user configuration files from directory ARG")},
{"username", opt_auth_username, 1,
@@ -150,12 +156,24 @@ static const apr_getopt_option_t svnrdump__options[] =
"For example:\n"
" "
" servers:global:http-library=serf")},
- {"trust-server-cert", opt_trust_server_cert, 0,
- N_("accept SSL server certificates from unknown\n"
- " "
- "certificate authorities without prompting (but only\n"
- " "
- "with '--non-interactive')") },
+ {"trust-server-cert", opt_trust_server_cert, 0,
+ N_("deprecated; same as\n"
+ " "
+ "--trust-server-cert-failures=unknown-ca")},
+ {"trust-server-cert-failures", opt_trust_server_cert_failures, 1,
+ N_("with --non-interactive, accept SSL server\n"
+ " "
+ "certificates with failures; ARG is comma-separated\n"
+ " "
+ "list of 'unknown-ca' (Unknown Authority),\n"
+ " "
+ "'cn-mismatch' (Hostname mismatch), 'expired'\n"
+ " "
+ "(Expired certificate), 'not-yet-valid' (Not yet\n"
+ " "
+ "valid certificate) and 'other' (all other not\n"
+ " "
+ "separately classified certificate errors).")},
{0, 0, 0, 0}
};
@@ -182,6 +200,7 @@ typedef struct opt_baton_t {
svn_opt_revision_t end_revision;
svn_boolean_t quiet;
svn_boolean_t incremental;
+ apr_hash_t *skip_revprops;
} opt_baton_t;
/* Print dumpstream-formatted information about REVISION.
@@ -197,38 +216,13 @@ replay_revstart(svn_revnum_t revision,
{
struct replay_baton *rb = replay_baton;
apr_hash_t *normal_props;
- svn_stringbuf_t *propstring;
- svn_stream_t *stdout_stream;
- svn_stream_t *revprop_stream;
-
- SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
- /* Revision-number: 19 */
- SVN_ERR(svn_stream_printf(stdout_stream, pool,
- SVN_REPOS_DUMPFILE_REVISION_NUMBER
- ": %ld\n", revision));
+ /* Normalize and dump the revprops */
SVN_ERR(svn_rdump__normalize_props(&normal_props, rev_props, pool));
- propstring = svn_stringbuf_create_ensure(0, pool);
- revprop_stream = svn_stream_from_stringbuf(propstring, pool);
- SVN_ERR(svn_hash_write2(normal_props, revprop_stream, "PROPS-END", pool));
- SVN_ERR(svn_stream_close(revprop_stream));
-
- /* Prop-content-length: 13 */
- SVN_ERR(svn_stream_printf(stdout_stream, pool,
- SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
- ": %" APR_SIZE_T_FMT "\n", propstring->len));
-
- /* Content-length: 29 */
- SVN_ERR(svn_stream_printf(stdout_stream, pool,
- SVN_REPOS_DUMPFILE_CONTENT_LENGTH
- ": %" APR_SIZE_T_FMT "\n\n", propstring->len));
-
- /* Property data. */
- SVN_ERR(svn_stream_write(stdout_stream, propstring->data,
- &(propstring->len)));
-
- SVN_ERR(svn_stream_puts(stdout_stream, "\n"));
- SVN_ERR(svn_stream_close(stdout_stream));
+ SVN_ERR(svn_repos__dump_revision_record(rb->stdout_stream, revision, NULL,
+ normal_props,
+ TRUE /*props_section_always*/,
+ pool));
SVN_ERR(svn_rdump__get_dump_editor(editor, edit_baton, revision,
rb->stdout_stream, rb->extra_ra_session,
@@ -271,38 +265,13 @@ replay_revstart_v2(svn_revnum_t revision,
{
struct replay_baton *rb = replay_baton;
apr_hash_t *normal_props;
- svn_stringbuf_t *propstring;
- svn_stream_t *stdout_stream;
- svn_stream_t *revprop_stream;
-
- SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
- /* Revision-number: 19 */
- SVN_ERR(svn_stream_printf(stdout_stream, pool,
- SVN_REPOS_DUMPFILE_REVISION_NUMBER
- ": %ld\n", revision));
+ /* Normalize and dump the revprops */
SVN_ERR(svn_rdump__normalize_props(&normal_props, rev_props, pool));
- propstring = svn_stringbuf_create_ensure(0, pool);
- revprop_stream = svn_stream_from_stringbuf(propstring, pool);
- SVN_ERR(svn_hash_write2(normal_props, revprop_stream, "PROPS-END", pool));
- SVN_ERR(svn_stream_close(revprop_stream));
-
- /* Prop-content-length: 13 */
- SVN_ERR(svn_stream_printf(stdout_stream, pool,
- SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
- ": %" APR_SIZE_T_FMT "\n", propstring->len));
-
- /* Content-length: 29 */
- SVN_ERR(svn_stream_printf(stdout_stream, pool,
- SVN_REPOS_DUMPFILE_CONTENT_LENGTH
- ": %" APR_SIZE_T_FMT "\n\n", propstring->len));
-
- /* Property data. */
- SVN_ERR(svn_stream_write(stdout_stream, propstring->data,
- &(propstring->len)));
-
- SVN_ERR(svn_stream_puts(stdout_stream, "\n"));
- SVN_ERR(svn_stream_close(stdout_stream));
+ SVN_ERR(svn_repos__dump_revision_record(rb->stdout_stream, revision,
+ normal_props,
+ TRUE /*props_section_always*/,
+ pool));
SVN_ERR(svn_rdump__get_dump_editor_v2(editor, revision,
rb->stdout_stream,
@@ -348,7 +317,11 @@ init_client_context(svn_client_ctx_t **ctx_p,
const char *config_dir,
const char *repos_url,
svn_boolean_t no_auth_cache,
- svn_boolean_t trust_server_cert,
+ svn_boolean_t trust_unknown_ca,
+ svn_boolean_t trust_cn_mismatch,
+ svn_boolean_t trust_expired,
+ svn_boolean_t trust_not_yet_valid,
+ svn_boolean_t trust_other_failure,
apr_array_header_t *config_options,
apr_pool_t *pool)
{
@@ -412,11 +385,14 @@ init_client_context(svn_client_ctx_t **ctx_p,
ctx->cancel_func = check_cancel;
/* Default authentication providers for non-interactive use */
- SVN_ERR(svn_cmdline_create_auth_baton(&(ctx->auth_baton), non_interactive,
- username, password, config_dir,
- no_auth_cache, trust_server_cert,
- cfg_config, ctx->cancel_func,
- ctx->cancel_baton, pool));
+ SVN_ERR(svn_cmdline_create_auth_baton2(&(ctx->auth_baton), non_interactive,
+ username, password, config_dir,
+ no_auth_cache, trust_unknown_ca,
+ trust_cn_mismatch, trust_expired,
+ trust_not_yet_valid,
+ trust_other_failure,
+ cfg_config, ctx->cancel_func,
+ ctx->cancel_baton, pool));
*ctx_p = ctx;
return SVN_NO_ERROR;
}
@@ -432,35 +408,12 @@ dump_revision_header(svn_ra_session_t *session,
apr_pool_t *pool)
{
apr_hash_t *prophash;
- svn_stringbuf_t *propstring;
- svn_stream_t *propstream;
-
- SVN_ERR(svn_stream_printf(stdout_stream, pool,
- SVN_REPOS_DUMPFILE_REVISION_NUMBER
- ": %ld\n", revision));
- prophash = apr_hash_make(pool);
- propstring = svn_stringbuf_create_empty(pool);
SVN_ERR(svn_ra_rev_proplist(session, revision, &prophash, pool));
-
- propstream = svn_stream_from_stringbuf(propstring, pool);
- SVN_ERR(svn_hash_write2(prophash, propstream, "PROPS-END", pool));
- SVN_ERR(svn_stream_close(propstream));
-
- /* Property-content-length: 14; Content-length: 14 */
- SVN_ERR(svn_stream_printf(stdout_stream, pool,
- SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
- ": %" APR_SIZE_T_FMT "\n",
- propstring->len));
- SVN_ERR(svn_stream_printf(stdout_stream, pool,
- SVN_REPOS_DUMPFILE_CONTENT_LENGTH
- ": %" APR_SIZE_T_FMT "\n\n",
- propstring->len));
- /* The properties */
- SVN_ERR(svn_stream_write(stdout_stream, propstring->data,
- &(propstring->len)));
- SVN_ERR(svn_stream_puts(stdout_stream, "\n"));
-
+ SVN_ERR(svn_repos__dump_revision_record(stdout_stream, revision, NULL,
+ prophash,
+ TRUE /*props_section_always*/,
+ pool));
return SVN_NO_ERROR;
}
@@ -608,6 +561,7 @@ load_revisions(svn_ra_session_t *session,
svn_ra_session_t *aux_session,
const char *url,
svn_boolean_t quiet,
+ apr_hash_t *skip_revprops,
apr_pool_t *pool)
{
apr_file_t *stdin_file;
@@ -617,7 +571,8 @@ load_revisions(svn_ra_session_t *session,
stdin_stream = svn_stream_from_aprfile2(stdin_file, FALSE, pool);
SVN_ERR(svn_rdump__load_dumpstream(stdin_stream, session, aux_session,
- quiet, check_cancel, NULL, pool));
+ quiet, skip_revprops,
+ check_cancel, NULL, pool));
SVN_ERR(svn_stream_close(stdin_stream));
@@ -667,23 +622,6 @@ version(const char *progname,
}
-/* A statement macro, similar to @c SVN_ERR, but returns an integer.
- * Evaluate @a expr. If it yields an error, handle that error and
- * return @c EXIT_FAILURE.
- */
-#define SVNRDUMP_ERR(expr) \
- do \
- { \
- svn_error_t *svn_err__temp = (expr); \
- if (svn_err__temp) \
- { \
- svn_handle_error2(svn_err__temp, stderr, FALSE, "svnrdump: "); \
- svn_error_clear(svn_err__temp); \
- return EXIT_FAILURE; \
- } \
- } \
- while (0)
-
/* Handle the "dump" subcommand. Implements `svn_opt_subcommand_t'. */
static svn_error_t *
dump_cmd(apr_getopt_t *os,
@@ -718,7 +656,7 @@ load_cmd(apr_getopt_t *os,
SVN_ERR(svn_client_open_ra_session2(&aux_session, opt_baton->url, NULL,
opt_baton->ctx, pool, pool));
return load_revisions(opt_baton->session, aux_session, opt_baton->url,
- opt_baton->quiet, pool);
+ opt_baton->quiet, opt_baton->skip_revprops, pool);
}
/* Handle the "help" subcommand. Implements `svn_opt_subcommand_t'. */
@@ -729,6 +667,7 @@ help_cmd(apr_getopt_t *os,
{
const char *header =
_("general usage: svnrdump SUBCOMMAND URL [-r LOWER[:UPPER]]\n"
+ "Subversion remote repository dump and load tool.\n"
"Type 'svnrdump help <subcommand>' for help on a specific subcommand.\n"
"Type 'svnrdump --version' to see the program version and RA modules.\n"
"\n"
@@ -831,19 +770,27 @@ validate_and_resolve_revisions(opt_baton_t *opt_baton,
return SVN_NO_ERROR;
}
-int
-main(int argc, const char **argv)
+/*
+ * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error,
+ * either return an error to be displayed, or set *EXIT_CODE to non-zero and
+ * return SVN_NO_ERROR.
+ */
+static svn_error_t *
+sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
{
svn_error_t *err = SVN_NO_ERROR;
const svn_opt_subcommand_desc2_t *subcommand = NULL;
opt_baton_t *opt_baton;
svn_revnum_t latest_revision = SVN_INVALID_REVNUM;
- apr_pool_t *pool = NULL;
const char *config_dir = NULL;
const char *username = NULL;
const char *password = NULL;
svn_boolean_t no_auth_cache = FALSE;
- svn_boolean_t trust_server_cert = FALSE;
+ svn_boolean_t trust_unknown_ca = FALSE;
+ svn_boolean_t trust_cn_mismatch = FALSE;
+ svn_boolean_t trust_expired = FALSE;
+ svn_boolean_t trust_not_yet_valid = FALSE;
+ svn_boolean_t trust_other_failure = FALSE;
svn_boolean_t non_interactive = FALSE;
svn_boolean_t force_interactive = FALSE;
apr_array_header_t *config_options = NULL;
@@ -852,20 +799,13 @@ main(int argc, const char **argv)
apr_array_header_t *received_opts;
int i;
- if (svn_cmdline_init ("svnrdump", stderr) != EXIT_SUCCESS)
- return EXIT_FAILURE;
-
- /* Create our top-level pool. Use a separate mutexless allocator,
- * given this application is single threaded.
- */
- pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
-
opt_baton = apr_pcalloc(pool, sizeof(*opt_baton));
opt_baton->start_revision.kind = svn_opt_revision_unspecified;
opt_baton->end_revision.kind = svn_opt_revision_unspecified;
opt_baton->url = NULL;
+ opt_baton->skip_revprops = apr_hash_make(pool);
- SVNRDUMP_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
+ SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
os->interleave = TRUE; /* Options and arguments can be interleaved */
@@ -905,8 +845,9 @@ main(int argc, const char **argv)
break;
if (status != APR_SUCCESS)
{
- SVNRDUMP_ERR(usage(argv[0], pool));
- exit(EXIT_FAILURE);
+ SVN_ERR(usage(argv[0], pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
/* Stash the option code in an array before parsing it. */
@@ -919,11 +860,10 @@ main(int argc, const char **argv)
/* Make sure we've not seen -r already. */
if (opt_baton->start_revision.kind != svn_opt_revision_unspecified)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Multiple revision arguments "
- "encountered; try '-r N:M' instead "
- "of '-r N -r M'"));
- return svn_cmdline_handle_exit_error(err, pool, "svnrdump: ");
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Multiple revision arguments "
+ "encountered; try '-r N:M' instead "
+ "of '-r N -r M'"));
}
/* Parse the -r argument. */
if (svn_opt_parse_revision(&(opt_baton->start_revision),
@@ -931,12 +871,10 @@ main(int argc, const char **argv)
opt_arg, pool) != 0)
{
const char *utf8_opt_arg;
- err = svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool);
- if (! err)
- err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("Syntax error in revision "
- "argument '%s'"), utf8_opt_arg);
- return svn_cmdline_handle_exit_error(err, pool, "svnrdump: ");
+ SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Syntax error in revision "
+ "argument '%s'"), utf8_opt_arg);
}
}
break;
@@ -953,10 +891,10 @@ main(int argc, const char **argv)
opt_baton->help = TRUE;
break;
case opt_auth_username:
- SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&username, opt_arg, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&username, opt_arg, pool));
break;
case opt_auth_password:
- SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&password, opt_arg, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&password, opt_arg, pool));
break;
case opt_auth_nocache:
no_auth_cache = TRUE;
@@ -970,8 +908,22 @@ main(int argc, const char **argv)
case opt_incremental:
opt_baton->incremental = TRUE;
break;
- case opt_trust_server_cert:
- trust_server_cert = TRUE;
+ case opt_skip_revprop:
+ SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
+ svn_hash_sets(opt_baton->skip_revprops, opt_arg, opt_arg);
+ break;
+ case opt_trust_server_cert: /* backward compat */
+ trust_unknown_ca = TRUE;
+ break;
+ case opt_trust_server_cert_failures:
+ SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
+ SVN_ERR(svn_cmdline__parse_trust_options(
+ &trust_unknown_ca,
+ &trust_cn_mismatch,
+ &trust_expired,
+ &trust_not_yet_valid,
+ &trust_other_failure,
+ opt_arg, pool));
break;
case opt_config_option:
if (!config_options)
@@ -979,9 +931,11 @@ main(int argc, const char **argv)
apr_array_make(pool, 1,
sizeof(svn_cmdline__config_argument_t*));
- SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
- SVNRDUMP_ERR(svn_cmdline__parse_config_option(config_options,
- opt_arg, pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
+ SVN_ERR(svn_cmdline__parse_config_option(config_options,
+ opt_arg,
+ "svnrdump: ",
+ pool));
}
}
@@ -989,10 +943,9 @@ main(int argc, const char **argv)
* exclusive. */
if (non_interactive && force_interactive)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("--non-interactive and --force-interactive "
- "are mutually exclusive"));
- return svn_cmdline_handle_exit_error(err, pool, "svnrdump: ");
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--non-interactive and --force-interactive "
+ "are mutually exclusive"));
}
if (opt_baton->help)
@@ -1017,9 +970,9 @@ main(int argc, const char **argv)
else
{
- SVNRDUMP_ERR(help_cmd(NULL, NULL, pool));
- svn_pool_destroy(pool);
- exit(EXIT_FAILURE);
+ SVN_ERR(help_cmd(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
}
else
@@ -1031,16 +984,15 @@ main(int argc, const char **argv)
if (subcommand == NULL)
{
const char *first_arg_utf8;
- err = svn_utf_cstring_to_utf8(&first_arg_utf8, first_arg, pool);
- if (err)
- return svn_cmdline_handle_exit_error(err, pool, "svnrdump: ");
+ SVN_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8, first_arg,
+ pool));
svn_error_clear(
svn_cmdline_fprintf(stderr, pool,
_("Unknown subcommand: '%s'\n"),
first_arg_utf8));
- SVNRDUMP_ERR(help_cmd(NULL, NULL, pool));
- svn_pool_destroy(pool);
- exit(EXIT_FAILURE);
+ SVN_ERR(help_cmd(NULL, NULL, pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
}
}
@@ -1065,69 +1017,64 @@ main(int argc, const char **argv)
subcommand, pool);
svn_opt_format_option(&optstr, badopt, FALSE, pool);
if (subcommand->name[0] == '-')
- SVN_INT_ERR(help_cmd(NULL, NULL, pool));
+ SVN_ERR(help_cmd(NULL, NULL, pool));
else
svn_error_clear(svn_cmdline_fprintf(
stderr, pool,
_("Subcommand '%s' doesn't accept option '%s'\n"
"Type 'svnrdump help %s' for usage.\n"),
subcommand->name, optstr, subcommand->name));
- svn_pool_destroy(pool);
- return EXIT_FAILURE;
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
}
- if (subcommand && strcmp(subcommand->name, "--version") == 0)
+ if (strcmp(subcommand->name, "--version") == 0)
{
- SVNRDUMP_ERR(version(argv[0], opt_baton->quiet, pool));
- svn_pool_destroy(pool);
- exit(EXIT_SUCCESS);
+ SVN_ERR(version(argv[0], opt_baton->quiet, pool));
+ return SVN_NO_ERROR;
}
- if (subcommand && strcmp(subcommand->name, "help") == 0)
+ if (strcmp(subcommand->name, "help") == 0)
{
- SVNRDUMP_ERR(help_cmd(os, opt_baton, pool));
- svn_pool_destroy(pool);
- exit(EXIT_SUCCESS);
+ SVN_ERR(help_cmd(os, opt_baton, pool));
+ return SVN_NO_ERROR;
}
- /* --trust-server-cert can only be used with --non-interactive */
- if (trust_server_cert && !non_interactive)
+ /* --trust-* can only be used with --non-interactive */
+ if (!non_interactive)
{
- err = svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("--trust-server-cert requires "
- "--non-interactive"));
- return svn_cmdline_handle_exit_error(err, pool, "svnrdump: ");
+ if (trust_unknown_ca || trust_cn_mismatch || trust_expired
+ || trust_not_yet_valid || trust_other_failure)
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--trust-server-cert-failures requires "
+ "--non-interactive"));
}
/* Expect one more non-option argument: the repository URL. */
if (os->ind != os->argc - 1)
{
- SVNRDUMP_ERR(usage(argv[0], pool));
- svn_pool_destroy(pool);
- exit(EXIT_FAILURE);
+ SVN_ERR(usage(argv[0], pool));
+ *exit_code = EXIT_FAILURE;
+ return SVN_NO_ERROR;
}
else
{
const char *repos_url;
- SVNRDUMP_ERR(svn_utf_cstring_to_utf8(&repos_url,
- os->argv[os->ind], pool));
+ SVN_ERR(svn_utf_cstring_to_utf8(&repos_url, os->argv[os->ind], pool));
if (! svn_path_is_url(repos_url))
{
- err = svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, 0,
- "Target '%s' is not a URL",
- repos_url);
- SVNRDUMP_ERR(err);
- svn_pool_destroy(pool);
- exit(EXIT_FAILURE);
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, 0,
+ "Target '%s' is not a URL",
+ repos_url);
}
opt_baton->url = svn_uri_canonicalize(repos_url, pool);
}
if (strcmp(subcommand->name, "load") == 0)
{
- /*
+ /*
* By default (no --*-interactive options given), the 'load' subcommand
* is interactive unless username and password were provided on the
* command line. This allows prompting for auth creds to work without
@@ -1141,16 +1088,20 @@ main(int argc, const char **argv)
non_interactive = !svn_cmdline__be_interactive(non_interactive,
force_interactive);
- SVNRDUMP_ERR(init_client_context(&(opt_baton->ctx),
- non_interactive,
- username,
- password,
- config_dir,
- opt_baton->url,
- no_auth_cache,
- trust_server_cert,
- config_options,
- pool));
+ SVN_ERR(init_client_context(&(opt_baton->ctx),
+ non_interactive,
+ username,
+ password,
+ config_dir,
+ opt_baton->url,
+ no_auth_cache,
+ trust_unknown_ca,
+ trust_cn_mismatch,
+ trust_expired,
+ trust_not_yet_valid,
+ trust_other_failure,
+ config_options,
+ pool));
err = svn_client_open_ra_session2(&(opt_baton->session),
opt_baton->url, NULL,
@@ -1171,15 +1122,45 @@ main(int argc, const char **argv)
if (err && err->apr_err == SVN_ERR_AUTHN_FAILED && non_interactive)
{
- err = svn_error_quick_wrap(err,
- _("Authentication failed and interactive"
- " prompting is disabled; see the"
- " --force-interactive option"));
+ return svn_error_quick_wrap(err,
+ _("Authentication failed and interactive"
+ " prompting is disabled; see the"
+ " --force-interactive option"));
}
+ else if (err)
+ return err;
+ else
+ return SVN_NO_ERROR;
+}
- SVNRDUMP_ERR(err);
+int
+main(int argc, const char *argv[])
+{
+ apr_pool_t *pool;
+ int exit_code = EXIT_SUCCESS;
+ svn_error_t *err;
- svn_pool_destroy(pool);
+ /* Initialize the app. */
+ if (svn_cmdline_init("svnrdump", stderr) != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ /* Create our top-level pool. Use a separate mutexless allocator,
+ * given this application is single threaded.
+ */
+ pool = apr_allocator_owner_get(svn_pool_create_allocator(FALSE));
+
+ err = sub_main(&exit_code, argc, argv, pool);
+
+ /* Flush stdout and report if it fails. It would be flushed on exit anyway
+ but this makes sure that output is not silently lost if it fails. */
+ err = svn_error_compose_create(err, svn_cmdline_fflush(stdout));
- return EXIT_SUCCESS;
+ if (err)
+ {
+ exit_code = EXIT_FAILURE;
+ svn_cmdline_handle_exit_error(err, NULL, "svnrdump: ");
+ }
+
+ svn_pool_destroy(pool);
+ return exit_code;
}
diff --git a/subversion/svnrdump/svnrdump.h b/subversion/svnrdump/svnrdump.h
index 2a81014..919ea5e 100644
--- a/subversion/svnrdump/svnrdump.h
+++ b/subversion/svnrdump/svnrdump.h
@@ -89,6 +89,7 @@ svn_rdump__load_dumpstream(svn_stream_t *stream,
svn_ra_session_t *session,
svn_ra_session_t *aux_session,
svn_boolean_t quiet,
+ apr_hash_t *skip_revprops,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *pool);
diff --git a/subversion/svnrdump/util.c b/subversion/svnrdump/util.c
index 2586cd1..9a89c89 100644
--- a/subversion/svnrdump/util.c
+++ b/subversion/svnrdump/util.c
@@ -61,8 +61,8 @@ svn_rdump__normalize_props(apr_hash_t **normal_props,
for (hi = apr_hash_first(result_pool, props); hi;
hi = apr_hash_next(hi))
{
- const char *key = svn__apr_hash_index_key(hi);
- const svn_string_t *value = svn__apr_hash_index_val(hi);
+ const char *key = apr_hash_this_key(hi);
+ const svn_string_t *value = apr_hash_this_val(hi);
SVN_ERR(svn_rdump__normalize_prop(key, &value,
result_pool));