Add a new dump_node function to dump node headers Node-path, Node-kind, Node-action and set the right variables to trigger dumping properties. Copies are also handled appropriately using eb->is_copy, copyfrom_path, copyfrom_rev informatino from the caller. Also add a related dump_props helper function that uses write_hash_to_stringbuf to dump properties. Signed-off-by: Ramkumar Ramachandra <artagnon@xxxxxxxxx> --- dump_editor.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ dumpr_util.c | 48 +++++++++++++++++++++ dumpr_util.h | 5 ++ 3 files changed, 185 insertions(+), 0 deletions(-) diff --git a/dump_editor.c b/dump_editor.c index 6e9b0f5..0f7d231 100644 --- a/dump_editor.c +++ b/dump_editor.c @@ -15,6 +15,10 @@ #include "dumpr_util.h" +#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r)) + +svn_boolean_t must_dump_props = FALSE, must_dump_text = FALSE, + dump_props_pending = FALSE; /* Make a directory baton to represent the directory was path (relative to EDIT_BATON's path) is PATH. @@ -70,6 +74,134 @@ struct dir_baton *make_dir_baton(const char *path, return new_db; } +/* + * Write out a node record for PATH of type KIND under EB->FS_ROOT. + * 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. + * + * If the node was itself copied, IS_COPY is TRUE and the + * path/revision of the copy source are in CMP_PATH/CMP_REV. If + * IS_COPY is FALSE, yet CMP_PATH/CMP_REV are valid, this node is part + * of a copied subtree. + */ +svn_error_t *dump_node(struct edit_baton *eb, + const char *path, /* an absolute path. */ + svn_node_kind_t kind, + enum svn_node_action action, + const char *cmp_path, + svn_revnum_t cmp_rev, + apr_pool_t *pool) +{ + /* Some pending properties to dump? */ + SVN_ERR(dump_props(eb, &dump_props_pending, TRUE, pool)); + + /* Write out metadata headers for this file node. */ + SVN_ERR(svn_stream_printf(eb->stream, pool, + SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n", + (*path == '/') ? path + 1 : path)); + + if (kind == svn_node_file) + SVN_ERR(svn_stream_printf(eb->stream, pool, + SVN_REPOS_DUMPFILE_NODE_KIND ": file\n")); + else if (kind == svn_node_dir) + SVN_ERR(svn_stream_printf(eb->stream, pool, + SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n")); + + /* Remove leading slashes from copyfrom paths. */ + if (cmp_path) + cmp_path = ((*cmp_path == '/') ? cmp_path + 1 : cmp_path); + + switch (action) { + /* Appropriately handle the four svn_node_action actions */ + + case svn_node_action_change: + SVN_ERR(svn_stream_printf(eb->stream, pool, + SVN_REPOS_DUMPFILE_NODE_ACTION + ": change\n")); + break; + + case svn_node_action_replace: + if (!eb->is_copy) { + /* a simple delete+add, implied by a single 'replace' action. */ + SVN_ERR(svn_stream_printf(eb->stream, pool, + SVN_REPOS_DUMPFILE_NODE_ACTION + ": replace\n")); + + /* definitely need to dump all content for a replace. */ + must_dump_props = TRUE; + break; + } + /* More complex case: eb->is_copy is true, and + cmp_path/ cmp_rev are present: delete the original, + and then re-add it */ + + /* the path & kind headers have already been printed; just + add a delete action, and end the current record.*/ + SVN_ERR(svn_stream_printf(eb->stream, pool, + SVN_REPOS_DUMPFILE_NODE_ACTION + ": delete\n\n")); + + /* recurse: print an additional add-with-history record. */ + SVN_ERR(dump_node(eb, path, kind, svn_node_action_add, + cmp_path, cmp_rev, pool)); + + /* we can leave this routine quietly now, don't need to dump + any content; that was already done in the second record. */ + must_dump_props = FALSE; + eb->is_copy = FALSE; + break; + + case svn_node_action_delete: + SVN_ERR(svn_stream_printf(eb->stream, pool, + SVN_REPOS_DUMPFILE_NODE_ACTION + ": delete\n")); + + /* we can leave this routine quietly now, don't need to dump + any content. */ + SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n")); + must_dump_props = FALSE; + break; + + case svn_node_action_add: + SVN_ERR(svn_stream_printf(eb->stream, pool, + SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n")); + + if (!eb->is_copy) { + /* If it's a file or directory not copied from + somewhere, wait for change_file_prop or + change_directory_prop */ + dump_props_pending = TRUE; + break; + } + + SVN_ERR(svn_stream_printf(eb->stream, pool, + SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV + ": %ld\n" + SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH + ": %s\n", + cmp_rev, cmp_path)); + + /* Dump the text only if apply_textdelta sets + must_dump_text */ + + /* UGLY hack: If a directory was copied from a + previous revision, nothing else can be done, and + close_file won't be called to write two blank + lines; write them here */ + if (kind == svn_node_dir) + SVN_ERR(svn_stream_printf(eb->stream, pool, "\n\n")); + + eb->is_copy = FALSE; + + break; + } + + /* Dump property headers */ + SVN_ERR(dump_props(eb, &must_dump_props, FALSE, pool)); + + return SVN_NO_ERROR; +} + svn_error_t *open_root(void *edit_baton, svn_revnum_t base_revision, apr_pool_t *pool, diff --git a/dumpr_util.c b/dumpr_util.c index 41940d4..a3328b6 100644 --- a/dumpr_util.c +++ b/dumpr_util.c @@ -62,3 +62,51 @@ void write_hash_to_stringbuf(apr_hash_t *properties, } } } + +svn_error_t *dump_props(struct edit_baton *eb, + svn_boolean_t *trigger_var, + svn_boolean_t dump_data_too, + apr_pool_t *pool) +{ + if (trigger_var && !*trigger_var) + return SVN_NO_ERROR; + + /* Build a propstring to print */ + svn_stringbuf_setempty(eb->propstring); + write_hash_to_stringbuf(eb->properties, + FALSE, + &(eb->propstring), eb->pool); + write_hash_to_stringbuf(eb->del_properties, + TRUE, + &(eb->propstring), eb->pool); + svn_stringbuf_appendbytes(eb->propstring, "PROPS-END\n", 10); + + /* prop-delta header */ + SVN_ERR(svn_stream_printf(eb->stream, pool, + SVN_REPOS_DUMPFILE_PROP_DELTA + ": true\n")); + + /* prop-content-length header */ + SVN_ERR(svn_stream_printf(eb->stream, pool, + SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH + ": %" APR_SIZE_T_FMT "\n", eb->propstring->len)); + + if (dump_data_too) { + /* content-length header */ + SVN_ERR(svn_stream_printf(eb->stream, pool, + SVN_REPOS_DUMPFILE_CONTENT_LENGTH + ": %" APR_SIZE_T_FMT "\n\n", + eb->propstring->len)); + + /* the properties themselves */ + SVN_ERR(svn_stream_write(eb->stream, eb->propstring->data, + &(eb->propstring->len))); + + /* Cleanup so that data is never dumped twice */ + apr_hash_clear(eb->properties); + apr_hash_clear(eb->del_properties); + if (trigger_var) + *trigger_var = FALSE; + } + return SVN_NO_ERROR; +} diff --git a/dumpr_util.h b/dumpr_util.h index 96670ff..79de1ab 100644 --- a/dumpr_util.h +++ b/dumpr_util.h @@ -66,4 +66,9 @@ void write_hash_to_stringbuf(apr_hash_t *properties, svn_stringbuf_t **strbuf, apr_pool_t *pool); +svn_error_t *dump_props(struct edit_baton *eb, + svn_boolean_t *trigger_var, + svn_boolean_t dump_data_too, + apr_pool_t *pool); + #endif -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html