Modified: subversion/branches/svn-auth-x509/subversion/svndumpfilter/svndumpfilter.c URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/svndumpfilter/svndumpfilter.c?rev=1655189&r1=1655188&r2=1655189&view=diff ============================================================================== --- subversion/branches/svn-auth-x509/subversion/svndumpfilter/svndumpfilter.c (original) +++ subversion/branches/svn-auth-x509/subversion/svndumpfilter/svndumpfilter.c Tue Jan 27 23:27:44 2015 @@ -43,6 +43,7 @@ #include "svn_mergeinfo.h" #include "svn_version.h" +#include "private/svn_repos_private.h" #include "private/svn_mergeinfo_private.h" #include "private/svn_cmdline_private.h" #include "private/svn_sorts_private.h" @@ -240,7 +241,6 @@ struct revision_baton_t /* Does this revision have node or prop changes? */ svn_boolean_t has_nodes; - svn_boolean_t has_props; /* Did we drop any nodes? */ svn_boolean_t had_dropped_nodes; @@ -253,7 +253,7 @@ struct revision_baton_t svn_revnum_t rev_actual; /* Pointers to dumpfile data. */ - svn_stringbuf_t *header; + apr_hash_t *original_headers; apr_hash_t *props; }; @@ -278,7 +278,7 @@ struct node_baton_t svn_filesize_t tcl; /* Pointers to dumpfile data. */ - svn_stringbuf_t *header; + apr_array_header_t *headers; svn_stringbuf_t *props; /* Expect deltas? */ @@ -287,6 +287,8 @@ struct node_baton_t /* We might need the node path in a parse error message. */ char *node_path; + + apr_pool_t *node_pool; }; @@ -310,6 +312,24 @@ magic_header_record(int version, void *p } +/* Return a deep copy of a (char * -> char *) hash. */ +static apr_hash_t * +headers_dup(apr_hash_t *headers, + apr_pool_t *pool) +{ + apr_hash_t *new_hash = apr_hash_make(pool); + apr_hash_index_t *hi; + + for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi)) + { + const char *key = apr_hash_this_key(hi); + const char *val = apr_hash_this_val(hi); + + svn_hash_sets(new_hash, apr_pstrdup(pool, key), apr_pstrdup(pool, val)); + } + return new_hash; +} + /* New revision: set up revision_baton, decide if we skip it. */ static svn_error_t * new_revision_record(void **revision_baton, @@ -318,21 +338,16 @@ new_revision_record(void **revision_bato apr_pool_t *pool) { struct revision_baton_t *rb; - apr_hash_index_t *hi; const char *rev_orig; - svn_stream_t *header_stream; *revision_baton = apr_palloc(pool, sizeof(struct revision_baton_t)); rb = *revision_baton; rb->pb = parse_baton; rb->has_nodes = FALSE; - rb->has_props = FALSE; rb->had_dropped_nodes = FALSE; rb->writing_begun = FALSE; - rb->header = svn_stringbuf_create_empty(pool); rb->props = apr_hash_make(pool); - - header_stream = svn_stream_from_stringbuf(rb->header, pool); + rb->original_headers = headers_dup(headers, pool); rev_orig = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_REVISION_NUMBER); rb->rev_orig = SVN_STR_TO_REV(rev_orig); @@ -342,28 +357,6 @@ new_revision_record(void **revision_bato else rb->rev_actual = rb->rev_orig; - SVN_ERR(svn_stream_printf(header_stream, pool, - SVN_REPOS_DUMPFILE_REVISION_NUMBER ": %ld\n", - rb->rev_actual)); - - for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi)) - { - const char *key = apr_hash_this_key(hi); - const char *val = apr_hash_this_val(hi); - - if ((!strcmp(key, SVN_REPOS_DUMPFILE_CONTENT_LENGTH)) - || (!strcmp(key, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH)) - || (!strcmp(key, SVN_REPOS_DUMPFILE_REVISION_NUMBER))) - continue; - - /* passthru: put header into header stringbuf. */ - - SVN_ERR(svn_stream_printf(header_stream, pool, "%s: %s\n", - key, val)); - } - - SVN_ERR(svn_stream_close(header_stream)); - return SVN_NO_ERROR; } @@ -375,12 +368,8 @@ new_revision_record(void **revision_bato static svn_error_t * output_revision(struct revision_baton_t *rb) { - int bytes_used; - char buf[SVN_KEYLINE_MAXLEN]; - apr_hash_index_t *hi; svn_boolean_t write_out_rev = FALSE; apr_pool_t *hash_pool = apr_hash_pool_get(rb->props); - svn_stringbuf_t *props = svn_stringbuf_create_empty(hash_pool); apr_pool_t *subpool = svn_pool_create(hash_pool); rb->writing_begun = TRUE; @@ -398,7 +387,6 @@ output_revision(struct revision_baton_t && (! rb->pb->drop_all_empty_revs)) { apr_hash_t *old_props = rb->props; - rb->has_props = TRUE; rb->props = apr_hash_make(hash_pool); svn_hash_sets(rb->props, SVN_PROP_REVISION_DATE, svn_hash_gets(old_props, SVN_PROP_REVISION_DATE)); @@ -407,39 +395,6 @@ output_revision(struct revision_baton_t "padding."), hash_pool)); } - /* Now, "rasterize" the props to a string, and append the property - information to the header string. */ - if (rb->has_props) - { - for (hi = apr_hash_first(subpool, rb->props); - hi; - hi = apr_hash_next(hi)) - { - const char *pname = apr_hash_this_key(hi); - const svn_string_t *pval = apr_hash_this_val(hi); - - write_prop_to_stringbuf(props, pname, pval); - } - svn_stringbuf_appendcstr(props, "PROPS-END\n"); - svn_stringbuf_appendcstr(rb->header, - SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH); - bytes_used = apr_snprintf(buf, sizeof(buf), ": %" APR_SIZE_T_FMT, - props->len); - svn_stringbuf_appendbytes(rb->header, buf, bytes_used); - svn_stringbuf_appendbyte(rb->header, '\n'); - } - - svn_stringbuf_appendcstr(rb->header, SVN_REPOS_DUMPFILE_CONTENT_LENGTH); - bytes_used = apr_snprintf(buf, sizeof(buf), ": %" APR_SIZE_T_FMT, props->len); - svn_stringbuf_appendbytes(rb->header, buf, bytes_used); - svn_stringbuf_appendbyte(rb->header, '\n'); - - /* put an end to headers */ - svn_stringbuf_appendbyte(rb->header, '\n'); - - /* put an end to revision */ - svn_stringbuf_appendbyte(props, '\n'); - /* write out the revision */ /* Revision is written out in the following cases: 1. If the revision has nodes or @@ -459,10 +414,12 @@ output_revision(struct revision_baton_t if (write_out_rev) { /* This revision is a keeper. */ - SVN_ERR(svn_stream_write(rb->pb->out_stream, - rb->header->data, &(rb->header->len))); - SVN_ERR(svn_stream_write(rb->pb->out_stream, - props->data, &(props->len))); + SVN_ERR(svn_repos__dump_revision_record(rb->pb->out_stream, + rb->rev_actual, + rb->original_headers, + rb->props, + FALSE /*props_section_always*/, + subpool)); /* Stash the oldest original rev not dropped. */ if (rb->rev_orig > 0 @@ -544,6 +501,7 @@ new_node_record(void **node_baton, *node_baton = apr_palloc(pool, sizeof(struct node_baton_t)); nb = *node_baton; nb->rb = rev_baton; + nb->node_pool = pool; pb = nb->rb->pb; node_path = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_PATH); @@ -615,7 +573,7 @@ new_node_record(void **node_baton, nb->has_text_delta = FALSE; nb->writing_begun = FALSE; nb->tcl = tcl ? svn__atoui64(tcl) : 0; - nb->header = svn_stringbuf_create_empty(pool); + nb->headers = svn_repos__dumpfile_headers_create(pool); nb->props = svn_stringbuf_create_empty(pool); nb->node_path = apr_pstrdup(pool, node_path); @@ -627,23 +585,20 @@ new_node_record(void **node_baton, /* A node record is required to begin with 'Node-path', skip the leading '/' to match the form used by 'svnadmin dump'. */ - SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream, - pool, "%s: %s\n", - SVN_REPOS_DUMPFILE_NODE_PATH, node_path + 1)); + svn_repos__dumpfile_header_push( + nb->headers, SVN_REPOS_DUMPFILE_NODE_PATH, node_path + 1); /* Node-kind is next and is optional. */ kind = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_KIND); if (kind) - SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream, - pool, "%s: %s\n", - SVN_REPOS_DUMPFILE_NODE_KIND, kind)); + svn_repos__dumpfile_header_push( + nb->headers, SVN_REPOS_DUMPFILE_NODE_KIND, kind); /* Node-action is next and required. */ action = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_ACTION); if (action) - SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream, - pool, "%s: %s\n", - SVN_REPOS_DUMPFILE_NODE_ACTION, action)); + svn_repos__dumpfile_header_push( + nb->headers, SVN_REPOS_DUMPFILE_NODE_ACTION, action); else return svn_error_createf(SVN_ERR_INCOMPLETE_DATA, 0, _("Missing Node-action for path '%s'"), @@ -690,18 +645,14 @@ new_node_record(void **node_baton, return svn_error_createf (SVN_ERR_NODE_UNEXPECTED_KIND, NULL, _("No valid copyfrom revision in filtered stream")); - SVN_ERR(svn_stream_printf - (nb->rb->pb->out_stream, pool, - SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV ": %ld\n", - cf_renum_val->rev)); + svn_repos__dumpfile_header_pushf( + nb->headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV, + "%ld", cf_renum_val->rev); continue; } /* passthru: put header straight to output */ - - SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream, - pool, "%s: %s\n", - key, val)); + svn_repos__dumpfile_header_push(nb->headers, key, val); } } @@ -709,65 +660,6 @@ new_node_record(void **node_baton, } -/* Output node header and props to dumpstream - This will be called by set_fulltext() after setting nb->has_text to TRUE, - if the node has any text, or by close_node() otherwise. This must only - be called if nb->writing_begun is FALSE. */ -static svn_error_t * -output_node(struct node_baton_t *nb) -{ - int bytes_used; - char buf[SVN_KEYLINE_MAXLEN]; - - nb->writing_begun = TRUE; - - /* when there are no props nb->props->len would be zero and won't mess up - Content-Length. */ - if (nb->has_props) - svn_stringbuf_appendcstr(nb->props, "PROPS-END\n"); - - /* 1. recalculate & check text-md5 if present. Passed through right now. */ - - /* 2. recalculate and add content-lengths */ - - if (nb->has_props) - { - svn_stringbuf_appendcstr(nb->header, - SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH); - bytes_used = apr_snprintf(buf, sizeof(buf), ": %" APR_SIZE_T_FMT, - nb->props->len); - svn_stringbuf_appendbytes(nb->header, buf, bytes_used); - svn_stringbuf_appendbyte(nb->header, '\n'); - } - if (nb->has_text) - { - svn_stringbuf_appendcstr(nb->header, - SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH); - bytes_used = apr_snprintf(buf, sizeof(buf), ": %" SVN_FILESIZE_T_FMT, - nb->tcl); - svn_stringbuf_appendbytes(nb->header, buf, bytes_used); - svn_stringbuf_appendbyte(nb->header, '\n'); - } - svn_stringbuf_appendcstr(nb->header, SVN_REPOS_DUMPFILE_CONTENT_LENGTH); - bytes_used = apr_snprintf(buf, sizeof(buf), ": %" SVN_FILESIZE_T_FMT, - (svn_filesize_t) (nb->props->len + nb->tcl)); - svn_stringbuf_appendbytes(nb->header, buf, bytes_used); - svn_stringbuf_appendbyte(nb->header, '\n'); - - /* put an end to headers */ - svn_stringbuf_appendbyte(nb->header, '\n'); - - /* 3. output all the stuff */ - - SVN_ERR(svn_stream_write(nb->rb->pb->out_stream, - nb->header->data , &(nb->header->len))); - SVN_ERR(svn_stream_write(nb->rb->pb->out_stream, - nb->props->data , &(nb->props->len))); - - return SVN_NO_ERROR; -} - - /* Examine the mergeinfo in INITIAL_VAL, omitting missing merge sources or renumbering revisions in rangelists as appropriate, and return the (possibly new) mergeinfo in *FINAL_VAL (allocated from @@ -874,7 +766,6 @@ set_revision_property(void *revision_bat struct revision_baton_t *rb = revision_baton; apr_pool_t *hash_pool = apr_hash_pool_get(rb->props); - rb->has_props = TRUE; svn_hash_sets(rb->props, apr_pstrdup(hash_pool, name), svn_string_dup(value, hash_pool)); @@ -893,6 +784,9 @@ set_node_property(void *node_baton, if (nb->do_skip) return SVN_NO_ERROR; + /* Try to detect if a delta-mode property occurs unexpectedly. HAS_PROPS + can be false here only if the parser didn't call remove_node_props(), + so this may indicate a bug rather than bad data. */ if (! (nb->has_props || nb->has_prop_delta)) return svn_error_createf(SVN_ERR_STREAM_MALFORMED_DATA, NULL, _("Delta property block detected, but deltas " @@ -938,14 +832,17 @@ delete_node_property(void *node_baton, c } +/* The parser calls this method if the node record has a non-delta + * property content section, before any calls to set_node_property(). + * If the node record uses property deltas, this is not called. + */ static svn_error_t * remove_node_props(void *node_baton) { struct node_baton_t *nb = node_baton; /* In this case, not actually indicating that the node *has* props, - rather that we know about all the props that it has, since it now - has none. */ + rather that it has a property content section. */ nb->has_props = TRUE; return SVN_NO_ERROR; @@ -961,7 +858,20 @@ set_fulltext(svn_stream_t **stream, void { nb->has_text = TRUE; if (! nb->writing_begun) - SVN_ERR(output_node(nb)); + { + nb->writing_begun = TRUE; + if (nb->has_props) + { + svn_stringbuf_appendcstr(nb->props, "PROPS-END\n"); + } + SVN_ERR(svn_repos__dump_node_record(nb->rb->pb->out_stream, + nb->headers, + nb->has_props ? nb->props : NULL, + nb->has_text, + nb->tcl, + TRUE /*content_length_always*/, + nb->node_pool)); + } *stream = nb->rb->pb->out_stream; } @@ -982,7 +892,20 @@ close_node(void *node_baton) /* If the node was not flushed already to output its text, do it now. */ if (! nb->writing_begun) - SVN_ERR(output_node(nb)); + { + nb->writing_begun = TRUE; + if (nb->has_props) + { + svn_stringbuf_appendcstr(nb->props, "PROPS-END\n"); + } + SVN_ERR(svn_repos__dump_node_record(nb->rb->pb->out_stream, + nb->headers, + nb->has_props ? nb->props : NULL, + nb->has_text, + nb->tcl, + TRUE /*content_length_always*/, + nb->node_pool)); + } /* put an end to node. */ SVN_ERR(svn_stream_write(nb->rb->pb->out_stream, "\n\n", &len));
Modified: subversion/branches/svn-auth-x509/subversion/svnmucc/svnmucc.c URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/svnmucc/svnmucc.c?rev=1655189&r1=1655188&r2=1655189&view=diff ============================================================================== --- subversion/branches/svn-auth-x509/subversion/svnmucc/svnmucc.c (original) +++ subversion/branches/svn-auth-x509/subversion/svnmucc/svnmucc.c Tue Jan 27 23:27:44 2015 @@ -222,7 +222,7 @@ execute(const apr_array_header_t *action mtcc, iterpool); svn_pool_destroy(iterpool); - return svn_error_trace(err);; + return svn_error_trace(err); } static svn_error_t * Modified: subversion/branches/svn-auth-x509/subversion/svnrdump/dump_editor.c URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/svnrdump/dump_editor.c?rev=1655189&r1=1655188&r2=1655189&view=diff ============================================================================== --- subversion/branches/svn-auth-x509/subversion/svnrdump/dump_editor.c (original) +++ subversion/branches/svn-auth-x509/subversion/svnrdump/dump_editor.c Tue Jan 27 23:27:44 2015 @@ -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,25 +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; - /* the path to this directory */ const char *repos_relpath; /* a relpath */ @@ -65,6 +57,9 @@ struct dir_baton const char *copyfrom_path; /* a relpath */ svn_revnum_t copyfrom_rev; + /* Headers accumulated so far for this directory */ + apr_array_header_t *headers; + /* Properties which were modified during change_dir_prop. */ apr_hash_t *props; @@ -87,7 +82,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; @@ -145,11 +139,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 @@ -161,16 +154,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; @@ -189,14 +181,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->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); @@ -216,7 +207,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); @@ -229,9 +219,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(apr_array_header_t *headers, svn_stringbuf_t **content, apr_hash_t *props, apr_hash_t *deleted_props, @@ -240,10 +232,8 @@ get_props_content(svn_stringbuf_t **head { 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); @@ -254,100 +244,60 @@ get_props_content(svn_stringbuf_t **head 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) -{ - svn_stringbuf_t *header; - svn_stringbuf_t *content; - apr_size_t len; - - 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)); - - 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)); +dump_node_delete(svn_stream_t *stream, + const char *node_relpath, + apr_pool_t *pool) +{ + apr_array_header_t *headers = svn_repos__dumpfile_headers_create(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(stream, "\n\n")); + assert(svn_relpath_is_canonical(node_relpath)); - /* 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_headers(stream, headers, TRUE, 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. + * 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(apr_array_header_t **headers_p, + struct dump_edit_baton *eb, const char *repos_relpath, struct dir_baton *db, struct file_baton *fb, @@ -358,6 +308,7 @@ dump_node(struct dump_edit_baton *eb, apr_pool_t *pool) { const char *node_relpath = repos_relpath; + apr_array_header_t *headers = svn_repos__dumpfile_headers_create(pool); assert(svn_relpath_is_canonical(repos_relpath)); assert(!copyfrom_path || svn_relpath_is_canonical(copyfrom_path)); @@ -369,17 +320,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 */ @@ -391,26 +341,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 */ @@ -418,35 +364,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")); - - /* 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")); + 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. */ + + /* ### 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)); + 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); /* Ugly hack: If a directory was copied from a previous revision, nothing like close_file() will be called to write two @@ -484,6 +431,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; } @@ -492,35 +444,28 @@ 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; + apr_array_header_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")); @@ -528,40 +473,50 @@ 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)); + if (db->dump_props) + { + /* 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)); + /* Cleanup so that data is never dumped twice. */ + apr_hash_clear(db->props); + apr_hash_clear(db->deleted_props); + db->dump_props = FALSE; } - else if (eb->pending_kind == svn_node_file) - { - 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)); + /* Some pending newlines to dump? */ + if (db->dump_newlines) + { + SVN_ERR(svn_stream_puts(eb->stream, "\n\n")); + db->dump_newlines = 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; } @@ -582,8 +537,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; @@ -616,15 +569,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. */ - eb->pending_baton = new_db; - eb->pending_kind = svn_node_dir; + eb->pending_db = new_db; } } svn_pool_destroy(iterpool); @@ -633,7 +586,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; @@ -648,9 +601,7 @@ 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, @@ -670,39 +621,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->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. */ - 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; @@ -720,9 +669,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. */ @@ -735,7 +682,7 @@ open_directory(const char *path, } new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb, pb, - FALSE, pb->pool); + pb->pool); *child_baton = new_db; return SVN_NO_ERROR; @@ -749,12 +696,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 @@ -767,12 +712,12 @@ 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 */ @@ -781,8 +726,9 @@ close_directory(void *dir_baton, { 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 */ @@ -801,17 +747,15 @@ add_file(const char *path, { struct dir_baton *pb = parent_baton; struct file_baton *fb; - void *val; - - LDR_DBG(("add_file %s\n", path)); + void *was_deleted; - 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)) @@ -820,10 +764,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; @@ -840,9 +784,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); @@ -870,13 +812,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; @@ -904,8 +844,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; @@ -934,8 +872,6 @@ apply_textdelta(void *file_baton, const struct dump_edit_baton *eb = fb->eb; svn_stream_t *delta_filestream; - LDR_DBG(("apply_textdelta %p\n", file_baton)); - /* Use a temporary file to measure the Text-content-length */ delta_filestream = svn_stream_from_aprfile2(eb->delta_file, TRUE, pool); @@ -959,22 +895,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; - - LDR_DBG(("close_file %p\n", file_baton)); + svn_stringbuf_t *propstring = NULL; + apr_array_header_t *headers; - SVN_ERR(dump_pending(eb, pool)); + SVN_ERR(dump_pending_dir(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) @@ -982,9 +921,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) @@ -992,43 +930,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 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)); - /* Dump the props now */ 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); @@ -1195,7 +1112,7 @@ svn_rdump__get_dump_editor(const svn_del 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); Modified: subversion/branches/svn-auth-x509/subversion/svnrdump/load_editor.c URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/svnrdump/load_editor.c?rev=1655189&r1=1655188&r2=1655189&view=diff ============================================================================== --- subversion/branches/svn-auth-x509/subversion/svnrdump/load_editor.c (original) +++ subversion/branches/svn-auth-x509/subversion/svnrdump/load_editor.c Tue Jan 27 23:27:44 2015 @@ -41,14 +41,9 @@ #define SVNRDUMP_PROP_LOCK SVN_PROP_PREFIX "rdump-lock" -#if 0 -#define LDR_DBG(x) SVN_DBG(x) -#else -#define LDR_DBG(x) while(0) -#endif +#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r)) - /** * General baton used by the parser functions. */ @@ -66,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; @@ -99,13 +91,21 @@ struct parse_baton /** * 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 + existing child of a copied directory). For a node that is newly + added (without history), even inside a copied parent, these are + NULL and SVN_INVALID_REVNUM. */ + const char *copyfrom_path; + svn_revnum_t copyfrom_rev; + struct directory_baton *parent; }; @@ -119,12 +119,20 @@ struct node_baton svn_node_kind_t kind; enum svn_node_action action; + /* Is this directory explicitly added? If not, then it already existed + or is a child of a copy. */ + svn_boolean_t is_added; + svn_revnum_t copyfrom_rev; const char *copyfrom_path; + const char *copyfrom_url; void *file_baton; const char *base_checksum; + /* (const char *name) -> (svn_prop_t *) */ + apr_hash_t *prop_changes; + struct revision_baton *rb; }; @@ -175,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 - preceding 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, @@ -545,6 +399,7 @@ new_revision_record(void **revision_bato pb = parse_baton; rb->pool = svn_pool_create(pool); rb->pb = pb; + rb->db = NULL; for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi)) { @@ -590,12 +445,50 @@ 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; } +/* Push information about another directory onto the linked list RB->db. + * + * CHILD_BATON is the baton returned by the commit editor. RELPATH is the + * repository-relative path of this directory. IS_ADDED is true iff this + * directory is being added (with or without history). If added with + * history then COPYFROM_PATH/COPYFROM_REV are the copyfrom source, else + * are NULL/SVN_INVALID_REVNUM. + */ +static void +push_directory(struct revision_baton *rb, + void *child_baton, + const char *relpath, + svn_boolean_t is_added, + const char *copyfrom_path, + svn_revnum_t copyfrom_rev) +{ + struct directory_baton *child_db = apr_pcalloc(rb->pool, sizeof (*child_db)); + + SVN_ERR_ASSERT_NO_RETURN( + is_added || (copyfrom_path == NULL && copyfrom_rev == SVN_INVALID_REVNUM)); + + /* If this node is an existing (not newly added) child of a copied node, + calculate where it was copied from. */ + if (!is_added + && ARE_VALID_COPY_ARGS(rb->db->copyfrom_path, rb->db->copyfrom_rev)) + { + const char *name = svn_relpath_basename(relpath, NULL); + + copyfrom_path = svn_relpath_join(rb->db->copyfrom_path, name, + rb->pool); + copyfrom_rev = rb->db->copyfrom_rev; + } + + child_db->baton = child_baton; + child_db->relpath = relpath; + child_db->copyfrom_path = copyfrom_path; + child_db->copyfrom_rev = copyfrom_rev; + child_db->parent = rb->db; + rb->db = child_db; +} + static svn_error_t * new_node_record(void **node_baton, apr_hash_t *headers, @@ -606,17 +499,17 @@ new_node_record(void **node_baton, const struct svn_delta_editor_t *commit_editor = rb->pb->commit_editor; void *commit_edit_baton = rb->pb->commit_edit_baton; struct node_baton *nb; - struct directory_baton *child_db; apr_hash_index_t *hi; void *child_baton; - char *relpath_compose; const char *nb_dirname; nb = apr_pcalloc(rb->pool, sizeof(*nb)); nb->rb = rb; - + nb->is_added = FALSE; nb->copyfrom_path = NULL; + nb->copyfrom_url = NULL; nb->copyfrom_rev = SVN_INVALID_REVNUM; + nb->prop_changes = apr_hash_make(rb->pool); /* If the creation of commit_editor is pending, create it now and open_root on it; also create a top-level directory baton. */ @@ -647,15 +540,9 @@ 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_db corresponds to the root directory baton here */ - child_db = apr_pcalloc(rb->pool, sizeof(*child_db)); - child_db->baton = child_baton; - child_db->depth = 0; - child_db->relpath = ""; - child_db->parent = NULL; - rb->db = child_db; + /* child_baton corresponds to the root directory baton here */ + push_directory(rb, child_baton, "", TRUE /*is_added*/, + NULL, SVN_INVALID_REVNUM); } for (hi = apr_hash_first(rb->pool, headers); hi; hi = apr_hash_next(hi)) @@ -688,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) @@ -698,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); @@ -718,14 +605,13 @@ 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; } for (i = 0; i < residual_open_path->nelts; i ++) { - relpath_compose = + char *relpath_compose = svn_relpath_join(rb->db->relpath, APR_ARRAY_IDX(residual_open_path, i, const char *), rb->pool); @@ -733,13 +619,8 @@ 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)); - child_db = apr_pcalloc(rb->pool, sizeof(*child_db)); - child_db->baton = child_baton; - child_db->depth = rb->db->depth + 1; - child_db->relpath = relpath_compose; - child_db->parent = rb->db; - rb->db = child_db; + push_directory(rb, child_baton, relpath_compose, TRUE /*is_added*/, + NULL, SVN_INVALID_REVNUM); } } @@ -767,7 +648,8 @@ 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); - nb->copyfrom_path = svn_path_url_add_component2(rb->pb->root_url, + /* 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); } @@ -777,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, rb->db->baton, rb->pool)); if (nb->action == svn_node_action_delete) @@ -785,29 +666,22 @@ new_node_record(void **node_baton, else /* FALL THROUGH */; case svn_node_action_add: + nb->is_added = TRUE; switch (nb->kind) { case svn_node_file: SVN_ERR(commit_editor->add_file(nb->path, rb->db->baton, - nb->copyfrom_path, + 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_path, + 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)); - child_db = apr_pcalloc(rb->pool, sizeof(*child_db)); - child_db->baton = child_baton; - child_db->depth = rb->db->depth + 1; - child_db->relpath = apr_pstrdup(rb->pool, nb->path); - child_db->parent = rb->db; - rb->db = child_db; + push_directory(rb, child_baton, nb->path, TRUE /*is_added*/, + nb->copyfrom_path, nb->copyfrom_rev); break; default: break; @@ -825,12 +699,8 @@ new_node_record(void **node_baton, SVN_ERR(commit_editor->open_directory(nb->path, rb->db->baton, rb->rev - rb->rev_offset - 1, rb->pool, &child_baton)); - child_db = apr_pcalloc(rb->pool, sizeof(*child_db)); - child_db->baton = child_baton; - child_db->depth = rb->db->depth + 1; - child_db->relpath = apr_pstrdup(rb->pool, nb->path); - child_db->parent = rb->db; - rb->db = child_db; + push_directory(rb, child_baton, nb->path, FALSE /*is_added*/, + NULL, SVN_INVALID_REVNUM); break; } break; @@ -878,70 +748,35 @@ set_revision_property(void *baton, return SVN_NO_ERROR; } -/* Adjust mergeinfo: - * - normalize line endings (if all CRLF, change to LF; but error if mixed); - * - adjust revision numbers (see renumber_mergeinfo_revs()); - * - adjust paths (see prefix_mergeinfo_paths()). - */ -static svn_error_t * -adjust_mergeinfo_property(struct revision_baton *rb, - svn_string_t **new_value_p, - const svn_string_t *old_value, - apr_pool_t *result_pool) -{ - struct parse_baton *pb = rb->pb; - svn_string_t prop_val = *old_value; - - /* Tolerate mergeinfo with "\r\n" line endings because some - dumpstream sources might contain as much. If so normalize - the line endings to '\n' and notify that we have made this - correction. */ - if (strstr(prop_val.data, "\r")) - { - const char *prop_eol_normalized; - - SVN_ERR(svn_subst_translate_cstring2(prop_val.data, - &prop_eol_normalized, - "\n", /* translate to LF */ - FALSE, /* no repair */ - NULL, /* no keywords */ - FALSE, /* no expansion */ - result_pool)); - prop_val.data = prop_eol_normalized; - prop_val.len = strlen(prop_eol_normalized); - - /* ### TODO: notify? */ - } - - /* Renumber mergeinfo as appropriate. */ - SVN_ERR(renumber_mergeinfo_revs(new_value_p, &prop_val, rb, - result_pool)); - - if (pb->parent_dir) - { - /* Prefix the merge source paths with PB->parent_dir. */ - /* ASSUMPTION: All source paths are included in the dump stream. */ - SVN_ERR(prefix_mergeinfo_paths(new_value_p, *new_value_p, - pb->parent_dir, result_pool)); - } - - return SVN_NO_ERROR; -} - static svn_error_t * set_node_property(void *baton, const char *name, const svn_string_t *value) { struct node_baton *nb = baton; - const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor; + 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 *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) + { + return svn_error_quick_wrap(err, + _("Invalid svn:mergeinfo value")); + } - SVN_ERR(adjust_mergeinfo_property(nb->rb, &new_value, value, pool)); value = new_value; } @@ -949,21 +784,11 @@ set_node_property(void *baton, SVN_ERR(svn_repos__validate_prop(name, value, pool)); - switch (nb->kind) - { - case svn_node_file: - LDR_DBG(("Applying properties on %p\n", nb->file_baton)); - SVN_ERR(commit_editor->change_file_prop(nb->file_baton, name, - value, pool)); - break; - case svn_node_dir: - LDR_DBG(("Applying properties on %p\n", nb->rb->db->baton)); - SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton, name, - value, pool)); - break; - default: - break; - } + prop = apr_palloc(nb->rb->pool, sizeof (*prop)); + prop->name = apr_pstrdup(pool, name); + prop->value = value ? svn_string_dup(value, pool) : NULL; + svn_hash_sets(nb->prop_changes, prop->name, prop); + return SVN_NO_ERROR; } @@ -972,44 +797,79 @@ delete_node_property(void *baton, const char *name) { struct node_baton *nb = baton; - const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor; apr_pool_t *pool = nb->rb->pool; + svn_prop_t *prop; SVN_ERR(svn_repos__validate_prop(name, NULL, pool)); - if (nb->kind == svn_node_file) - SVN_ERR(commit_editor->change_file_prop(nb->file_baton, name, - NULL, pool)); - else - SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton, name, - NULL, pool)); + prop = apr_palloc(pool, sizeof (*prop)); + prop->name = apr_pstrdup(pool, name); + prop->value = NULL; + svn_hash_sets(nb->prop_changes, prop->name, prop); return SVN_NO_ERROR; } +/* Delete all the properties of the node, if any. + * + * The commit editor doesn't have a method to delete a node's properties + * without knowing what they are, so we have to first find out what + * properties the node would have had. If it's copied (explicitly or + * implicitly), we look at the copy source. If it's only being changed, + * we look at the node's current path in the head revision. + */ static svn_error_t * remove_node_props(void *baton) { struct node_baton *nb = baton; + struct revision_baton *rb = nb->rb; apr_pool_t *pool = nb->rb->pool; apr_hash_index_t *hi; apr_hash_t *props; + const char *orig_path; + svn_revnum_t orig_rev; + + /* Find the path and revision that has the node's original properties */ + if (ARE_VALID_COPY_ARGS(nb->copyfrom_path, nb->copyfrom_rev)) + { + orig_path = nb->copyfrom_path; + orig_rev = nb->copyfrom_rev; + } + else if (!nb->is_added + && ARE_VALID_COPY_ARGS(rb->db->copyfrom_path, rb->db->copyfrom_rev)) + { + /* 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. */ + orig_path = (nb->kind == svn_node_dir) + ? rb->db->copyfrom_path + : svn_relpath_join(rb->db->copyfrom_path, + svn_relpath_basename(nb->path, NULL), + rb->pool); + orig_rev = rb->db->copyfrom_rev; + } + else + { + /* ### 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; + } if ((nb->action == svn_node_action_add || nb->action == svn_node_action_replace) - && ! SVN_IS_VALID_REVNUM(nb->copyfrom_rev)) + && ! ARE_VALID_COPY_ARGS(orig_path, orig_rev)) /* Add-without-history; no "old" properties to worry about. */ return SVN_NO_ERROR; if (nb->kind == svn_node_file) { - SVN_ERR(svn_ra_get_file(nb->rb->pb->aux_session, nb->path, - SVN_INVALID_REVNUM, NULL, NULL, &props, pool)); + SVN_ERR(svn_ra_get_file(nb->rb->pb->aux_session, + orig_path, orig_rev, NULL, NULL, &props, pool)); } else /* nb->kind == svn_node_dir */ { SVN_ERR(svn_ra_get_dir2(nb->rb->pb->aux_session, NULL, NULL, &props, - nb->path, SVN_INVALID_REVNUM, 0, pool)); + orig_path, orig_rev, 0, pool)); } for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi)) @@ -1034,7 +894,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, @@ -1051,7 +910,6 @@ apply_textdelta(svn_txdelta_window_handl 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)); @@ -1063,12 +921,34 @@ close_node(void *baton) { struct node_baton *nb = baton; const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor; + apr_pool_t *pool = nb->rb->pool; + apr_hash_index_t *hi; + + for (hi = apr_hash_first(pool, nb->prop_changes); + hi; hi = apr_hash_next(hi)) + { + const char *name = apr_hash_this_key(hi); + svn_prop_t *prop = apr_hash_this_val(hi); + + switch (nb->kind) + { + case svn_node_file: + SVN_ERR(commit_editor->change_file_prop(nb->file_baton, + name, prop->value, pool)); + break; + case svn_node_dir: + SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton, + name, prop->value, pool)); + break; + default: + break; + } + } /* Pass a file node closure through to the editor *unless* we 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)); } @@ -1098,12 +978,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)); } @@ -1121,8 +999,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)); } Modified: subversion/branches/svn-auth-x509/subversion/svnrdump/svnrdump.c URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/svnrdump/svnrdump.c?rev=1655189&r1=1655188&r2=1655189&view=diff ============================================================================== --- subversion/branches/svn-auth-x509/subversion/svnrdump/svnrdump.c (original) +++ subversion/branches/svn-auth-x509/subversion/svnrdump/svnrdump.c Tue Jan 27 23:27:44 2015 @@ -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" @@ -229,34 +230,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 *revprop_stream; - /* Revision-number: 19 */ - SVN_ERR(svn_stream_printf(rb->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(rb->stdout_stream, pool, - SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH - ": %" APR_SIZE_T_FMT "\n", propstring->len)); - - /* Content-length: 29 */ - SVN_ERR(svn_stream_printf(rb->stdout_stream, pool, - SVN_REPOS_DUMPFILE_CONTENT_LENGTH - ": %" APR_SIZE_T_FMT "\n\n", propstring->len)); - - /* Property data. */ - SVN_ERR(svn_stream_write(rb->stdout_stream, propstring->data, - &(propstring->len))); - - SVN_ERR(svn_stream_puts(rb->stdout_stream, "\n")); + 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, @@ -299,34 +279,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 *revprop_stream; - /* Revision-number: 19 */ - SVN_ERR(svn_stream_printf(rb->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(rb->stdout_stream, pool, - SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH - ": %" APR_SIZE_T_FMT "\n", propstring->len)); - - /* Content-length: 29 */ - SVN_ERR(svn_stream_printf(rb->stdout_stream, pool, - SVN_REPOS_DUMPFILE_CONTENT_LENGTH - ": %" APR_SIZE_T_FMT "\n\n", propstring->len)); - - /* Property data. */ - SVN_ERR(svn_stream_write(rb->stdout_stream, propstring->data, - &(propstring->len))); - - SVN_ERR(svn_stream_puts(rb->stdout_stream, "\n")); + 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, @@ -463,35 +422,12 @@ dump_revision_header(svn_ra_session_t *s 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; } @@ -1168,7 +1104,7 @@ sub_main(int *exit_code, int argc, const 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
