📄 dag.c
字号:
{
/* This has already been cloned */
new_node_id = cur_entry->id;
}
else
{
node_revision_t *noderev;
/* Go get a fresh NODE-REVISION for current child node. */
SVN_ERR (get_node_revision (&noderev, cur_entry, trail));
/* Do the clone thingy here. */
noderev->predecessor_id = svn_fs_base__id_copy (cur_entry->id,
trail->pool);
if (noderev->predecessor_count != -1)
noderev->predecessor_count++;
noderev->created_path = svn_path_join (parent_path, name, trail->pool);
SVN_ERR (svn_fs_base__create_successor (&new_node_id, fs, cur_entry->id,
noderev, copy_id, txn_id,
trail));
/* 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, txn_id, trail));
}
/* Initialize the youngster. */
return svn_fs_base__dag_get_node (child_p, fs, new_node_id, trail);
}
svn_error_t *
svn_fs_base__dag_clone_root (dag_node_t **root_p,
svn_fs_t *fs,
const char *txn_id,
trail_t *trail)
{
const svn_fs_id_t *base_root_id, *root_id;
node_revision_t *noderev;
/* Get the node ID's of the root directories of the transaction and
its base revision. */
SVN_ERR (svn_fs_base__get_txn_ids (&root_id, &base_root_id, fs, txn_id,
trail));
/* Oh, give me a clone...
(If they're the same, we haven't cloned the transaction's root
directory yet.) */
if (svn_fs_base__id_eq (root_id, base_root_id))
{
const char *base_copy_id = svn_fs_base__id_copy_id (base_root_id);
/* Of my own flesh and bone...
(Get the NODE-REVISION for the base node, and then write
it back out as the clone.) */
SVN_ERR (svn_fs_bdb__get_node_revision (&noderev, fs, base_root_id,
trail));
/* Store it. */
/* ### todo: Does it even makes sense to have a different copy id for
the root node? That is, does this function need a copy_id
passed in? */
noderev->predecessor_id = svn_fs_base__id_copy (base_root_id,
trail->pool);
if (noderev->predecessor_count != -1)
noderev->predecessor_count++;
SVN_ERR (svn_fs_base__create_successor (&root_id, fs, base_root_id,
noderev, base_copy_id,
txn_id, trail));
/* ... And when it is grown
* Then my own little clone
* Will be of the opposite sex!
*/
SVN_ERR (svn_fs_base__set_txn_root (fs, txn_id, root_id, trail));
}
/* One way or another, root_id now identifies a cloned root node. */
SVN_ERR (svn_fs_base__dag_get_node (root_p, fs, root_id, trail));
/*
* (Sung to the tune of "Home, Home on the Range", with thanks to
* Randall Garrett and Isaac Asimov.)
*/
return SVN_NO_ERROR;
}
/* Delete the directory entry named NAME from PARENT, as part of
TRAIL. PARENT must be mutable. NAME must be a single path
component. If REQUIRE_EMPTY is true and the node being deleted is
a directory, it must be empty.
If return SVN_ERR_FS_NO_SUCH_ENTRY, then there is no entry NAME in
PARENT. */
svn_error_t *
svn_fs_base__dag_delete (dag_node_t *parent,
const char *name,
const char *txn_id,
trail_t *trail)
{
node_revision_t *parent_noderev;
const char *rep_key, *mutable_rep_key;
apr_hash_t *entries = NULL;
skel_t *entries_skel;
svn_fs_t *fs = parent->fs;
svn_string_t str;
svn_fs_id_t *id = NULL;
dag_node_t *node;
/* 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_base__dag_check_mutable (parent, txn_id))
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, trail));
/* Get the key for the parent's entries list (data) representation. */
rep_key = parent_noderev->data_key;
/* No REP_KEY means no representation, and no representation means
no data, and no data means no entries...there's nothing here to
delete! */
if (! rep_key)
return svn_error_createf
(SVN_ERR_FS_NO_SUCH_ENTRY, NULL,
"Delete failed--directory has no entry '%s'", name);
/* Ensure we have a key to a mutable representation of the entries
list. We'll have to update the NODE-REVISION if it points to an
immutable version. */
SVN_ERR (svn_fs_base__get_mutable_rep (&mutable_rep_key, rep_key,
fs, txn_id, trail));
if (! svn_fs_base__same_keys (mutable_rep_key, rep_key))
{
node_revision_t *new_noderev =
copy_node_revision (parent_noderev, trail->pool);
new_noderev->data_key = mutable_rep_key;
SVN_ERR (set_node_revision (parent, new_noderev, trail));
}
/* Read the representation, then use it to get the string that holds
the entries list. Parse that list into a skel, and parse *that*
into a hash. */
SVN_ERR (svn_fs_base__rep_contents (&str, fs, rep_key, trail));
entries_skel = svn_fs_base__parse_skel (str.data, str.len, trail->pool);
if (entries_skel)
SVN_ERR (svn_fs_base__parse_entries_skel (&entries, entries_skel,
trail->pool));
/* Find NAME in the ENTRIES skel. */
if (entries)
id = apr_hash_get (entries, name, APR_HASH_KEY_STRING);
/* 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 (! id)
return svn_error_createf
(SVN_ERR_FS_NO_SUCH_ENTRY, NULL,
"Delete failed--directory has no entry '%s'", name);
/* Use the ID of this ENTRY to get the entry's node. */
SVN_ERR (svn_fs_base__dag_get_node (&node, svn_fs_base__dag_get_fs (parent),
id, trail));
/* If mutable, remove it and any mutable children from db. */
SVN_ERR (svn_fs_base__dag_delete_if_mutable (parent->fs, id, txn_id, trail));
/* Remove this entry from its parent's entries list. */
apr_hash_set (entries, name, APR_HASH_KEY_STRING, NULL);
/* Replace the old entries list with the new one. */
{
svn_stream_t *ws;
svn_stringbuf_t *unparsed_entries;
apr_size_t len;
SVN_ERR (svn_fs_base__unparse_entries_skel (&entries_skel, entries,
trail->pool));
unparsed_entries = svn_fs_base__unparse_skel (entries_skel, trail->pool);
SVN_ERR (svn_fs_base__rep_contents_write_stream (&ws, fs, mutable_rep_key,
txn_id, TRUE, trail,
trail->pool));
len = unparsed_entries->len;
SVN_ERR (svn_stream_write (ws, unparsed_entries->data, &len));
SVN_ERR (svn_stream_close (ws));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__dag_remove_node (svn_fs_t *fs,
const svn_fs_id_t *id,
const char *txn_id,
trail_t *trail)
{
dag_node_t *node;
node_revision_t *noderev;
/* Fetch the node. */
SVN_ERR (svn_fs_base__dag_get_node (&node, fs, id, trail));
/* If immutable, do nothing and return immediately. */
if (! svn_fs_base__dag_check_mutable (node, txn_id))
return svn_error_createf (SVN_ERR_FS_NOT_MUTABLE, NULL,
"Attempted removal of immutable node");
/* Get a fresh node-revision. */
SVN_ERR (svn_fs_bdb__get_node_revision (&noderev, fs, id, trail));
/* Delete any mutable property representation. */
if (noderev->prop_key)
SVN_ERR (svn_fs_base__delete_rep_if_mutable (fs, noderev->prop_key,
txn_id, trail));
/* Delete any mutable data representation. */
if (noderev->data_key)
SVN_ERR (svn_fs_base__delete_rep_if_mutable (fs, noderev->data_key,
txn_id, trail));
/* Delete any mutable edit representation (files only). */
if (noderev->edit_key)
SVN_ERR (svn_fs_base__delete_rep_if_mutable (fs, noderev->edit_key,
txn_id, trail));
/* Delete the node revision itself. */
SVN_ERR (svn_fs_base__delete_node_revision (fs, id, trail));
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__dag_delete_if_mutable (svn_fs_t *fs,
const svn_fs_id_t *id,
const char *txn_id,
trail_t *trail)
{
dag_node_t *node;
/* Get the node. */
SVN_ERR (svn_fs_base__dag_get_node (&node, fs, id, trail));
/* If immutable, do nothing and return immediately. */
if (! svn_fs_base__dag_check_mutable (node, txn_id))
return SVN_NO_ERROR;
/* Else it's mutable. Recurse on directories... */
if (node->kind == svn_node_dir)
{
apr_hash_t *entries;
apr_hash_index_t *hi;
apr_pool_t *pool = trail->pool;
/* Loop over hash entries */
SVN_ERR (svn_fs_base__dag_dir_entries (&entries, node, trail));
if (entries)
{
for (hi = apr_hash_first (pool, entries);
hi;
hi = apr_hash_next (hi))
{
void *val;
svn_fs_dirent_t *dirent;
apr_hash_this (hi, NULL, NULL, &val);
dirent = val;
SVN_ERR (svn_fs_base__dag_delete_if_mutable (fs, dirent->id,
txn_id, trail));
}
}
}
/* ... then delete the node itself, after deleting any mutable
representations and strings it points to. */
SVN_ERR (svn_fs_base__dag_remove_node (fs, id, txn_id, trail));
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__dag_make_file (dag_node_t **child_p,
dag_node_t *parent,
const char *parent_path,
const char *name,
const char *txn_id,
trail_t *trail)
{
/* Call our little helper function */
return make_entry (child_p, parent, parent_path, name, FALSE, txn_id, trail);
}
svn_error_t *
svn_fs_base__dag_make_dir (dag_node_t **child_p,
dag_node_t *parent,
const char *parent_path,
const char *name,
const char *txn_id,
trail_t *trail)
{
/* Call our little helper function */
return make_entry (child_p, parent, parent_path, name, TRUE, txn_id, trail);
}
svn_error_t *
svn_fs_base__dag_get_contents (svn_stream_t **contents,
dag_node_t *file,
apr_pool_t *pool,
trail_t *trail)
{
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 textual contents of a *non*-file node");
/* Go get a fresh node-revision for FILE. */
SVN_ERR (get_node_revision (&noderev, file, trail));
/* Our job is to _return_ a stream on the file's contents, so the
stream has to be trail-independent. Here, we pass NULL to tell
the stream that we're not providing it a trail that lives across
reads. This means the stream will do each read in a one-off,
temporary trail. */
SVN_ERR (svn_fs_base__rep_contents_read_stream (contents, file->fs,
noderev->data_key,
FALSE, trail, pool));
/* Note that we're not registering any `close' func, because there's
nothing to cleanup outside of our trail. When the trail is
freed, the stream/baton will be too. */
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__dag_file_length (svn_filesize_t *length,
dag_node_t *file,
trail_t *trail)
{
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, trail));
if (noderev->data_key)
SVN_ERR (svn_fs_base__rep_contents_size (length, file->fs,
noderev->data_key, trail));
else
*length = 0;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__dag_file_checksum (unsigned char digest[],
dag_node_t *file,
trail_t *trail)
{
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, trail));
if (noderev->data_key)
SVN_ERR (svn_fs_base__rep_contents_checksum (digest, file->fs,
noderev->data_key, trail));
else
memset (digest, 0, APR_MD5_DIGESTSIZE);
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_base__dag_get_edit_stream (svn_stream_t **contents,
dag_node_t *file,
apr_pool_t *pool,
const char *txn_id,
trail_t *trail)
{
svn_fs_t *fs = file->fs; /* just for nicer indentation */
node_revision_t *noderev;
const char *mutable_rep_key;
svn_stream_t *ws;
/* Make sure our node is a file. */
if (file->kind != svn_node_file)
return svn_error_createf
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -