svn_error_t * svn_fs_x__dag_things_different(svn_boolean_t *props_changed, svn_boolean_t *contents_changed, dag_node_t *node1, dag_node_t *node2) { node_revision_t *noderev1, *noderev2; /* If we have no place to store our results, don't bother doing anything. */ if (! props_changed && ! contents_changed) return SVN_NO_ERROR; /* The node revision skels for these two nodes. */ SVN_ERR(get_node_revision(&noderev1, node1)); SVN_ERR(get_node_revision(&noderev2, node2)); /* Compare property keys. */ if (props_changed != NULL) *props_changed = (! svn_fs_x__noderev_same_rep_key(noderev1->prop_rep, noderev2->prop_rep)); /* Compare contents keys. */ if (contents_changed != NULL) *contents_changed = (! svn_fs_x__noderev_same_rep_key(noderev1->data_rep, noderev2->data_rep)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__dag_get_file_delta_stream(svn_txdelta_stream_t **stream_p, dag_node_t *source, dag_node_t *target, apr_pool_t *pool) { node_revision_t *src_noderev; node_revision_t *tgt_noderev; /* Make sure our nodes are files. */ if ((source && source->kind != svn_node_file) || target->kind != svn_node_file) return svn_error_createf (SVN_ERR_FS_NOT_FILE, NULL, "Attempted to get textual contents of a *non*-file node"); /* Go get fresh node-revisions for the nodes. */ if (source) SVN_ERR(get_node_revision(&src_noderev, source)); else src_noderev = NULL; SVN_ERR(get_node_revision(&tgt_noderev, target)); /* Get the delta stream. */ return svn_fs_x__get_file_delta_stream(stream_p, target->fs, src_noderev, tgt_noderev, pool); }
svn_error_t * svn_fs_x__dag_get_contents(svn_stream_t **contents_p, dag_node_t *file, apr_pool_t *pool) { node_revision_t *noderev; svn_stream_t *contents; /* Make sure our node is a file. */ if (file->kind != svn_node_file) return svn_error_createf (SVN_ERR_FS_NOT_FILE, NULL, "Attempted to get textual contents of a *non*-file node"); /* Go get a fresh node-revision for FILE. */ SVN_ERR(get_node_revision(&noderev, file)); /* Get a stream to the contents. */ SVN_ERR(svn_fs_x__get_contents(&contents, file->fs, noderev->data_rep, pool)); *contents_p = contents; return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__dag_set_has_mergeinfo(dag_node_t *node, svn_boolean_t has_mergeinfo, apr_pool_t *pool) { node_revision_t *noderev; /* Sanity check: this node better be mutable! */ if (! svn_fs_x__dag_check_mutable(node)) { svn_string_t *idstr = svn_fs_x__id_unparse(node->id, pool); return svn_error_createf (SVN_ERR_FS_NOT_MUTABLE, NULL, "Can't set mergeinfo flag on *immutable* node-revision %s", idstr->data); } /* Go get a fresh NODE-REVISION for this node. */ SVN_ERR(get_node_revision(&noderev, node)); noderev->has_mergeinfo = has_mergeinfo; /* Flush it out. */ return svn_fs_x__put_node_revision(node->fs, noderev->id, noderev, FALSE, pool); }
svn_error_t * svn_fs_x__dag_get_edit_stream(svn_stream_t **contents, dag_node_t *file, apr_pool_t *pool) { node_revision_t *noderev; svn_stream_t *ws; /* Make sure our node is a file. */ if (file->kind != svn_node_file) return svn_error_createf (SVN_ERR_FS_NOT_FILE, NULL, "Attempted to set textual contents of a *non*-file node"); /* Make sure our node is mutable. */ if (! svn_fs_x__dag_check_mutable(file)) return svn_error_createf (SVN_ERR_FS_NOT_MUTABLE, NULL, "Attempted to set textual contents of an immutable node"); /* Get the node revision. */ SVN_ERR(get_node_revision(&noderev, file)); SVN_ERR(svn_fs_x__set_contents(&ws, file->fs, noderev, pool)); *contents = ws; return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__dag_get_node(dag_node_t **node, svn_fs_t *fs, const svn_fs_id_t *id, apr_pool_t *pool) { dag_node_t *new_node; node_revision_t *noderev; /* Construct the node. */ new_node = apr_pcalloc(pool, sizeof(*new_node)); new_node->fs = fs; new_node->id = svn_fs_x__id_copy(id, pool); /* Grab the contents so we can inspect the node's kind and created path. */ new_node->node_pool = pool; SVN_ERR(get_node_revision(&noderev, new_node)); /* Initialize the KIND and CREATED_PATH attributes */ new_node->kind = noderev->kind; new_node->created_path = apr_pstrdup(pool, noderev->created_path); if (noderev->is_fresh_txn_root) new_node->fresh_root_predecessor_id = noderev->predecessor_id; else new_node->fresh_root_predecessor_id = NULL; /* Return a fresh new node */ *node = new_node; return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__dag_delete(dag_node_t *parent, const char *name, const svn_fs_x__id_part_t *txn_id, apr_pool_t *pool) { node_revision_t *parent_noderev; svn_fs_t *fs = parent->fs; svn_fs_dirent_t *dirent; svn_fs_id_t *id; apr_pool_t *subpool; /* Make sure parent is a directory. */ if (parent->kind != svn_node_dir) return svn_error_createf (SVN_ERR_FS_NOT_DIRECTORY, NULL, "Attempted to delete entry '%s' from *non*-directory node", name); /* Make sure parent is mutable. */ if (! svn_fs_x__dag_check_mutable(parent)) return svn_error_createf (SVN_ERR_FS_NOT_MUTABLE, NULL, "Attempted to delete entry '%s' from immutable directory node", name); /* Make sure that NAME is a single path component. */ if (! svn_path_is_single_path_component(name)) return svn_error_createf (SVN_ERR_FS_NOT_SINGLE_PATH_COMPONENT, NULL, "Attempted to delete a node with an illegal name '%s'", name); /* Get a fresh NODE-REVISION for the parent node. */ SVN_ERR(get_node_revision(&parent_noderev, parent)); subpool = svn_pool_create(pool); /* Search this directory for a dirent with that NAME. */ SVN_ERR(svn_fs_x__rep_contents_dir_entry(&dirent, fs, parent_noderev, name, subpool, subpool)); /* If we never found ID in ENTRIES (perhaps because there are no ENTRIES, perhaps because ID just isn't in the existing ENTRIES ... it doesn't matter), return an error. */ if (! dirent) return svn_error_createf (SVN_ERR_FS_NO_SUCH_ENTRY, NULL, "Delete failed--directory has no entry '%s'", name); /* Copy the ID out of the subpool and release the rest of the directory listing. */ id = svn_fs_x__id_copy(dirent->id, pool); svn_pool_destroy(subpool); /* If mutable, remove it and any mutable children from db. */ SVN_ERR(svn_fs_x__dag_delete_if_mutable(parent->fs, id, pool)); /* Remove this entry from its parent's entries list. */ return svn_fs_x__set_entry(parent->fs, txn_id, parent_noderev, name, NULL, svn_node_unknown, pool); }
/* Make a new entry named NAME in PARENT. If IS_DIR is true, then the node revision the new entry points to will be a directory, else it will be a file. The new node will be allocated in POOL. PARENT must be mutable, and must not have an entry named NAME. Use POOL for all allocations, except caching the node_revision in PARENT. */ static svn_error_t * make_entry(dag_node_t **child_p, dag_node_t *parent, const char *parent_path, const char *name, svn_boolean_t is_dir, const svn_fs_x__id_part_t *txn_id, apr_pool_t *pool) { const svn_fs_id_t *new_node_id; node_revision_t new_noderev, *parent_noderev; /* Make sure that NAME is a single path component. */ if (! svn_path_is_single_path_component(name)) return svn_error_createf (SVN_ERR_FS_NOT_SINGLE_PATH_COMPONENT, NULL, _("Attempted to create a node with an illegal name '%s'"), name); /* Make sure that parent is a directory */ if (parent->kind != svn_node_dir) return svn_error_create (SVN_ERR_FS_NOT_DIRECTORY, NULL, _("Attempted to create entry in non-directory parent")); /* Check that the parent is mutable. */ if (! svn_fs_x__dag_check_mutable(parent)) return svn_error_createf (SVN_ERR_FS_NOT_MUTABLE, NULL, _("Attempted to clone child of non-mutable node")); /* Create the new node's NODE-REVISION */ memset(&new_noderev, 0, sizeof(new_noderev)); new_noderev.kind = is_dir ? svn_node_dir : svn_node_file; new_noderev.created_path = svn_fspath__join(parent_path, name, pool); SVN_ERR(get_node_revision(&parent_noderev, parent)); new_noderev.copyroot_path = apr_pstrdup(pool, parent_noderev->copyroot_path); new_noderev.copyroot_rev = parent_noderev->copyroot_rev; new_noderev.copyfrom_rev = SVN_INVALID_REVNUM; new_noderev.copyfrom_path = NULL; SVN_ERR(svn_fs_x__create_node (&new_node_id, svn_fs_x__dag_get_fs(parent), &new_noderev, svn_fs_x__id_copy_id(svn_fs_x__dag_get_id(parent)), txn_id, pool)); /* Create a new dag_node_t for our new node */ SVN_ERR(svn_fs_x__dag_get_node(child_p, svn_fs_x__dag_get_fs(parent), new_node_id, pool)); /* We can safely call set_entry because we already know that PARENT is mutable, and we just created CHILD, so we know it has no ancestors (therefore, PARENT cannot be an ancestor of CHILD) */ return set_entry(parent, name, svn_fs_x__dag_get_id(*child_p), new_noderev.kind, txn_id, pool); }
svn_error_t * svn_fs_x__dag_get_mergeinfo_count(apr_int64_t *count, dag_node_t *node) { node_revision_t *noderev; SVN_ERR(get_node_revision(&noderev, node)); *count = noderev->mergeinfo_count; return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__dag_has_mergeinfo(svn_boolean_t *has_mergeinfo, dag_node_t *node) { node_revision_t *noderev; SVN_ERR(get_node_revision(&noderev, node)); *has_mergeinfo = noderev->has_mergeinfo; return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__dag_get_predecessor_count(int *count, dag_node_t *node) { node_revision_t *noderev; SVN_ERR(get_node_revision(&noderev, node)); *count = noderev->predecessor_count; return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__dag_get_predecessor_id(const svn_fs_id_t **id_p, dag_node_t *node) { node_revision_t *noderev; SVN_ERR(get_node_revision(&noderev, node)); *id_p = noderev->predecessor_id; return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__dag_copy(dag_node_t *to_node, const char *entry, dag_node_t *from_node, svn_boolean_t preserve_history, svn_revnum_t from_rev, const char *from_path, const svn_fs_x__id_part_t *txn_id, apr_pool_t *pool) { const svn_fs_id_t *id; if (preserve_history) { node_revision_t *from_noderev, *to_noderev; svn_fs_x__id_part_t copy_id; const svn_fs_id_t *src_id = svn_fs_x__dag_get_id(from_node); svn_fs_t *fs = svn_fs_x__dag_get_fs(from_node); /* Make a copy of the original node revision. */ SVN_ERR(get_node_revision(&from_noderev, from_node)); to_noderev = copy_node_revision(from_noderev, pool); /* Reserve a copy ID for this new copy. */ SVN_ERR(svn_fs_x__reserve_copy_id(©_id, fs, txn_id, pool)); /* Create a successor with its predecessor pointing at the copy source. */ to_noderev->predecessor_id = svn_fs_x__id_copy(src_id, pool); if (to_noderev->predecessor_count != -1) to_noderev->predecessor_count++; to_noderev->created_path = svn_fspath__join(svn_fs_x__dag_get_created_path(to_node), entry, pool); to_noderev->copyfrom_path = apr_pstrdup(pool, from_path); to_noderev->copyfrom_rev = from_rev; /* Set the copyroot equal to our own id. */ to_noderev->copyroot_path = NULL; SVN_ERR(svn_fs_x__create_successor(&id, fs, src_id, to_noderev, ©_id, txn_id, pool)); } else /* don't preserve history */ { id = svn_fs_x__dag_get_id(from_node); } /* Set the entry in to_node to the new id. */ return svn_fs_x__dag_set_entry(to_node, entry, id, from_node->kind, txn_id, pool); }
svn_error_t * svn_fs_x__dag_get_copyfrom_rev(svn_revnum_t *rev, dag_node_t *node) { node_revision_t *noderev; /* Go get a fresh node-revision for NODE. */ SVN_ERR(get_node_revision(&noderev, node)); *rev = noderev->copyfrom_rev; return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__dag_get_copyfrom_path(const char **path, dag_node_t *node) { node_revision_t *noderev; /* Go get a fresh node-revision for NODE. */ SVN_ERR(get_node_revision(&noderev, node)); *path = noderev->copyfrom_path; return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__dag_increment_mergeinfo_count(dag_node_t *node, apr_int64_t increment, apr_pool_t *pool) { node_revision_t *noderev; /* Sanity check: this node better be mutable! */ if (! svn_fs_x__dag_check_mutable(node)) { svn_string_t *idstr = svn_fs_x__id_unparse(node->id, pool); return svn_error_createf (SVN_ERR_FS_NOT_MUTABLE, NULL, "Can't increment mergeinfo count on *immutable* node-revision %s", idstr->data); } if (increment == 0) return SVN_NO_ERROR; /* Go get a fresh NODE-REVISION for this node. */ SVN_ERR(get_node_revision(&noderev, node)); noderev->mergeinfo_count += increment; if (noderev->mergeinfo_count < 0) { svn_string_t *idstr = svn_fs_x__id_unparse(node->id, pool); return svn_error_createf (SVN_ERR_FS_CORRUPT, NULL, apr_psprintf(pool, _("Can't increment mergeinfo count on node-revision %%s " "to negative value %%%s"), APR_INT64_T_FMT), idstr->data, noderev->mergeinfo_count); } if (noderev->mergeinfo_count > 1 && noderev->kind == svn_node_file) { svn_string_t *idstr = svn_fs_x__id_unparse(node->id, pool); return svn_error_createf (SVN_ERR_FS_CORRUPT, NULL, apr_psprintf(pool, _("Can't increment mergeinfo count on *file* " "node-revision %%s to %%%s (> 1)"), APR_INT64_T_FMT), idstr->data, noderev->mergeinfo_count); } /* Flush it out. */ return svn_fs_x__put_node_revision(node->fs, noderev->id, noderev, FALSE, pool); }
svn_error_t * svn_fs_fs__dag_get_copyfrom_rev(svn_revnum_t *rev, dag_node_t *node, apr_pool_t *pool) { node_revision_t *noderev; /* Go get a fresh node-revision for FILE. */ SVN_ERR(get_node_revision(&noderev, node, pool)); *rev = noderev->copyfrom_rev; return SVN_NO_ERROR; }
svn_error_t * svn_fs_fs__dag_get_copyfrom_path(const char **path, dag_node_t *node, apr_pool_t *pool) { node_revision_t *noderev; /* Go get a fresh node-revision for FILE. */ SVN_ERR(get_node_revision(&noderev, node, pool)); *path = noderev->copyfrom_path; return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__dag_update_ancestry(dag_node_t *target, dag_node_t *source, apr_pool_t *pool) { node_revision_t *source_noderev, *target_noderev; if (! svn_fs_x__dag_check_mutable(target)) return svn_error_createf (SVN_ERR_FS_NOT_MUTABLE, NULL, _("Attempted to update ancestry of non-mutable node")); SVN_ERR(get_node_revision(&source_noderev, source)); SVN_ERR(get_node_revision(&target_noderev, target)); target_noderev->predecessor_id = source->id; target_noderev->predecessor_count = source_noderev->predecessor_count; if (target_noderev->predecessor_count != -1) target_noderev->predecessor_count++; return svn_fs_x__put_node_revision(target->fs, target->id, target_noderev, FALSE, pool); }
svn_error_t * svn_fs_x__dag_dir_entries(apr_hash_t **entries, dag_node_t *node, apr_pool_t *pool) { node_revision_t *noderev; SVN_ERR(get_node_revision(&noderev, node)); if (noderev->kind != svn_node_dir) return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, NULL, _("Can't get entries of non-directory")); return svn_fs_x__rep_contents_dir(entries, node->fs, noderev, pool); }
svn_error_t * svn_fs_x__dag_try_process_file_contents(svn_boolean_t *success, dag_node_t *node, svn_fs_process_contents_func_t processor, void* baton, apr_pool_t *pool) { node_revision_t *noderev; /* Go get fresh node-revisions for the nodes. */ SVN_ERR(get_node_revision(&noderev, node)); return svn_fs_x__try_process_file_contents(success, node->fs, noderev, processor, baton, pool); }
svn_error_t * svn_fs_x__dag_get_proplist(apr_hash_t **proplist_p, dag_node_t *node, apr_pool_t *pool) { node_revision_t *noderev; apr_hash_t *proplist = NULL; SVN_ERR(get_node_revision(&noderev, node)); SVN_ERR(svn_fs_x__get_proplist(&proplist, node->fs, noderev, pool)); *proplist_p = proplist; return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__dag_file_checksum(svn_checksum_t **checksum, dag_node_t *file, svn_checksum_kind_t kind, apr_pool_t *pool) { node_revision_t *noderev; if (file->kind != svn_node_file) return svn_error_createf (SVN_ERR_FS_NOT_FILE, NULL, "Attempted to get checksum of a *non*-file node"); SVN_ERR(get_node_revision(&noderev, file)); return svn_fs_x__file_checksum(checksum, noderev, kind, pool); }
/* Add or set in PARENT a directory entry NAME pointing to ID. Allocations are done in POOL. Assumptions: - PARENT is a mutable directory. - ID does not refer to an ancestor of parent - NAME is a single path component */ static svn_error_t * set_entry(dag_node_t *parent, const char *name, const svn_fs_id_t *id, svn_node_kind_t kind, const svn_fs_x__id_part_t *txn_id, apr_pool_t *pool) { node_revision_t *parent_noderev; /* Get the parent's node-revision. */ SVN_ERR(get_node_revision(&parent_noderev, parent)); /* Set the new entry. */ return svn_fs_x__set_entry(parent->fs, txn_id, parent_noderev, name, id, kind, pool); }
svn_error_t * svn_fs_x__dag_dir_entry(svn_fs_dirent_t **dirent, dag_node_t *node, const char* name, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { node_revision_t *noderev; SVN_ERR(get_node_revision(&noderev, node)); if (noderev->kind != svn_node_dir) return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, NULL, _("Can't get entries of non-directory")); /* Get a dirent hash for this directory. */ return svn_fs_x__rep_contents_dir_entry(dirent, node->fs, noderev, name, result_pool, scratch_pool); }
svn_error_t * svn_fs_x__dag_file_length(svn_filesize_t *length, dag_node_t *file, apr_pool_t *pool) { node_revision_t *noderev; /* Make sure our node is a file. */ if (file->kind != svn_node_file) return svn_error_createf (SVN_ERR_FS_NOT_FILE, NULL, "Attempted to get length of a *non*-file node"); /* Go get a fresh node-revision for FILE, and . */ SVN_ERR(get_node_revision(&noderev, file)); return svn_fs_x__file_length(length, noderev, pool); }
svn_error_t * svn_fs_x__dag_has_descendants_with_mergeinfo(svn_boolean_t *do_they, dag_node_t *node) { node_revision_t *noderev; if (node->kind != svn_node_dir) { *do_they = FALSE; return SVN_NO_ERROR; } SVN_ERR(get_node_revision(&noderev, node)); if (noderev->mergeinfo_count > 1) *do_they = TRUE; else if (noderev->mergeinfo_count == 1 && !noderev->has_mergeinfo) *do_they = TRUE; else *do_they = FALSE; return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__dag_set_proplist(dag_node_t *node, apr_hash_t *proplist, apr_pool_t *pool) { node_revision_t *noderev; /* Sanity check: this node better be mutable! */ if (! svn_fs_x__dag_check_mutable(node)) { svn_string_t *idstr = svn_fs_x__id_unparse(node->id, pool); return svn_error_createf (SVN_ERR_FS_NOT_MUTABLE, NULL, "Can't set proplist on *immutable* node-revision %s", idstr->data); } /* Go get a fresh NODE-REVISION for this node. */ SVN_ERR(get_node_revision(&noderev, node)); /* Set the new proplist. */ return svn_fs_x__set_proplist(node->fs, noderev, proplist, pool); }
svn_error_t * svn_fs_x__dag_clone_child(dag_node_t **child_p, dag_node_t *parent, const char *parent_path, const char *name, const svn_fs_x__id_part_t *copy_id, const svn_fs_x__id_part_t *txn_id, svn_boolean_t is_parent_copyroot, apr_pool_t *pool) { dag_node_t *cur_entry; /* parent's current entry named NAME */ const svn_fs_id_t *new_node_id; /* node id we'll put into NEW_NODE */ svn_fs_t *fs = svn_fs_x__dag_get_fs(parent); apr_pool_t *subpool = svn_pool_create(pool); /* First check that the parent is mutable. */ if (! svn_fs_x__dag_check_mutable(parent)) return svn_error_createf (SVN_ERR_FS_NOT_MUTABLE, NULL, "Attempted to clone child of non-mutable node"); /* Make sure that NAME is a single path component. */ if (! svn_path_is_single_path_component(name)) return svn_error_createf (SVN_ERR_FS_NOT_SINGLE_PATH_COMPONENT, NULL, "Attempted to make a child clone with an illegal name '%s'", name); /* Find the node named NAME in PARENT's entries list if it exists. */ SVN_ERR(svn_fs_x__dag_open(&cur_entry, parent, name, pool, subpool)); /* Check for mutability in the node we found. If it's mutable, we don't need to clone it. */ if (svn_fs_x__dag_check_mutable(cur_entry)) { /* This has already been cloned */ new_node_id = cur_entry->id; } else { node_revision_t *noderev, *parent_noderev; /* Go get a fresh NODE-REVISION for current child node. */ SVN_ERR(get_node_revision(&noderev, cur_entry)); if (is_parent_copyroot) { SVN_ERR(get_node_revision(&parent_noderev, parent)); noderev->copyroot_rev = parent_noderev->copyroot_rev; noderev->copyroot_path = apr_pstrdup(pool, parent_noderev->copyroot_path); } noderev->copyfrom_path = NULL; noderev->copyfrom_rev = SVN_INVALID_REVNUM; noderev->predecessor_id = svn_fs_x__id_copy(cur_entry->id, pool); if (noderev->predecessor_count != -1) noderev->predecessor_count++; noderev->created_path = svn_fspath__join(parent_path, name, pool); SVN_ERR(svn_fs_x__create_successor(&new_node_id, fs, cur_entry->id, noderev, copy_id, txn_id, pool)); /* Replace the ID in the parent's ENTRY list with the ID which refers to the mutable clone of this child. */ SVN_ERR(set_entry(parent, name, new_node_id, noderev->kind, txn_id, pool)); } /* Initialize the youngster. */ svn_pool_destroy(subpool); return svn_fs_x__dag_get_node(child_p, fs, new_node_id, pool); }