static void mark_parent_stable(const svn_editor_t *editor, const char *relpath) { const char *parent = svn_relpath_dirname(relpath, editor->scratch_pool); const void *marker = svn_hash_gets(editor->completed_nodes, parent); /* If RELPATH has already been marked (to disallow adds, or that it has been fully-completed), then do nothing. */ if (marker == MARKER_ALLOW_ALTER || marker == MARKER_DONE || marker == MARKER_ADDED_DIR) return; /* If the marker is MARKER_ALLOW_ADD, then that means the parent was moved away. There is no way to work on a child. That should have been tested before we got here by VERIFY_PARENT_MAY_EXIST(). */ SVN_ERR_ASSERT_NO_RETURN(marker != MARKER_ALLOW_ADD); /* MARKER is NULL. Upgrade it to MARKER_ALLOW_ALTER. */ MARK_RELPATH(editor, parent, MARKER_ALLOW_ALTER); }
static svn_boolean_t check_unknown_child(const svn_editor_t *editor, const char *relpath) { const char *parent; /* If we already know about the new child, then exit early. */ if (svn_hash_gets(editor->pending_incomplete_children, relpath) != NULL) return TRUE; parent = svn_relpath_dirname(relpath, editor->scratch_pool); /* Was this parent created via svn_editor_add_directory() ? */ if (svn_hash_gets(editor->completed_nodes, parent) == MARKER_ADDED_DIR) { /* Whoops. This child should have been listed in that add call, and placed into ->pending_incomplete_children. */ return FALSE; } /* The parent was not added in this drive. */ return TRUE; }
static svn_error_t * new_node_record(void **node_baton, apr_hash_t *headers, void *revision_baton, apr_pool_t *pool) { struct revision_baton *rb = revision_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; apr_hash_index_t *hi; void *child_baton; 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. */ if (!commit_editor) { /* The revprop_table should have been filled in with important information like svn:log in set_revision_property. We can now use it all this information to create our commit_editor. But first, clear revprops that we aren't allowed to set with the commit_editor. We'll set them separately using the RA API after closing the editor (see close_revision). */ svn_hash_sets(rb->revprop_table, SVN_PROP_REVISION_AUTHOR, NULL); svn_hash_sets(rb->revprop_table, SVN_PROP_REVISION_DATE, NULL); SVN_ERR(svn_ra__register_editor_shim_callbacks(rb->pb->session, get_shim_callbacks(rb, rb->pool))); SVN_ERR(svn_ra_get_commit_editor3(rb->pb->session, &commit_editor, &commit_edit_baton, rb->revprop_table, commit_callback, revision_baton, NULL, FALSE, rb->pool)); rb->pb->commit_editor = commit_editor; rb->pb->commit_edit_baton = commit_edit_baton; SVN_ERR(commit_editor->open_root(commit_edit_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); } 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); /* Parse the different kinds of headers we can encounter and stuff them into the node_baton for writing later */ if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_PATH) == 0) nb->path = apr_pstrdup(rb->pool, hval); if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_KIND) == 0) nb->kind = strcmp(hval, "file") == 0 ? svn_node_file : svn_node_dir; if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_ACTION) == 0) { if (strcmp(hval, "add") == 0) nb->action = svn_node_action_add; if (strcmp(hval, "change") == 0) nb->action = svn_node_action_change; if (strcmp(hval, "delete") == 0) nb->action = svn_node_action_delete; if (strcmp(hval, "replace") == 0) nb->action = svn_node_action_replace; } if (strcmp(hname, SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_MD5) == 0) nb->base_checksum = apr_pstrdup(rb->pool, hval); if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV) == 0) nb->copyfrom_rev = atoi(hval); if (strcmp(hname, SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH) == 0) nb->copyfrom_path = apr_pstrdup(rb->pool, hval); } nb_dirname = svn_relpath_dirname(nb->path, pool); if (svn_path_compare_paths(nb_dirname, rb->db->relpath) != 0) { char *ancestor_path; apr_size_t residual_close_count; apr_array_header_t *residual_open_path; 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); residual_close_count = svn_path_component_count(svn_relpath_skip_ancestor(ancestor_path, rb->db->relpath)); residual_open_path = svn_path_decompose(svn_relpath_skip_ancestor(ancestor_path, nb_dirname), pool); /* First close all as many directories as there are after skip_ancestor, and then open fresh directories */ for (n = 0; n < residual_close_count; n ++) { /* 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 ++) { char *relpath_compose = svn_relpath_join(rb->db->relpath, APR_ARRAY_IDX(residual_open_path, i, const char *), rb->pool); SVN_ERR(commit_editor->open_directory(relpath_compose, 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); } }