📄 fs_fs.c
字号:
}
else if (strcmp (str, KIND_DIR) == 0)
{
dirent->kind = svn_node_dir;
}
else
{
return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
_("Directory entry corrupt"));
}
str = apr_strtok (NULL, " ", &last_str);
if (str == NULL)
return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
_("Directory entry corrupt"));
dirent->id = svn_fs_fs__id_parse (str, strlen (str),
ffd->dir_cache_pool);
apr_hash_set (ffd->dir_cache, dirent->name, APR_HASH_KEY_STRING, dirent);
}
/* Mark which directory we've cached and return it. */
ffd->dir_cache_id = svn_fs_fs__id_copy (noderev->id, ffd->dir_cache_pool);
*entries_p = ffd->dir_cache;
return SVN_NO_ERROR;
}
apr_hash_t *
svn_fs_fs__copy_dir_entries (apr_hash_t *entries,
apr_pool_t *pool)
{
apr_hash_t *new_entries = apr_hash_make (pool);
apr_hash_index_t *hi;
for (hi = apr_hash_first (pool, entries); hi; hi = apr_hash_next (hi))
{
void *val;
svn_fs_dirent_t *dirent, *new_dirent;
apr_hash_this (hi, NULL, NULL, &val);
dirent = val;
new_dirent = apr_palloc (pool, sizeof (*new_dirent));
new_dirent->name = apr_pstrdup (pool, dirent->name);
new_dirent->kind = dirent->kind;
new_dirent->id = svn_fs_fs__id_copy (dirent->id, pool);
apr_hash_set (new_entries, new_dirent->name, APR_HASH_KEY_STRING,
new_dirent);
}
return new_entries;
}
svn_error_t *
svn_fs_fs__get_proplist (apr_hash_t **proplist_p,
svn_fs_t *fs,
node_revision_t *noderev,
apr_pool_t *pool)
{
apr_hash_t *proplist;
svn_stream_t *stream;
proplist = apr_hash_make (pool);
if (noderev->prop_rep && noderev->prop_rep->txn_id)
{
apr_file_t *props_file;
const char *filename = path_txn_node_props (fs, noderev->id, pool);
SVN_ERR (svn_io_file_open (&props_file, filename,
APR_READ | APR_BUFFERED, APR_OS_DEFAULT,
pool));
stream = svn_stream_from_aprfile (props_file, pool);
SVN_ERR (svn_hash_read2 (proplist, stream, SVN_HASH_TERMINATOR, pool));
SVN_ERR (svn_io_file_close (props_file, pool));
}
else if (noderev->prop_rep)
{
SVN_ERR (read_representation (&stream, fs, noderev->prop_rep, pool));
SVN_ERR (svn_hash_read2 (proplist, stream, SVN_HASH_TERMINATOR, pool));
SVN_ERR (svn_stream_close (stream));
}
*proplist_p = proplist;
return SVN_NO_ERROR;
}
svn_error_t *
svn_fs_fs__file_length (svn_filesize_t *length,
node_revision_t *noderev,
apr_pool_t *pool)
{
if (noderev->data_rep)
*length = noderev->data_rep->expanded_size;
else
*length = 0;
return SVN_NO_ERROR;
}
svn_boolean_t
svn_fs_fs__noderev_same_rep_key (representation_t *a,
representation_t *b)
{
if (a == b)
return TRUE;
if (a && (! b))
return FALSE;
if (b && (! a))
return FALSE;
if (a->offset != b->offset)
return FALSE;
if (a->revision != b->revision)
return FALSE;
return TRUE;
}
svn_error_t *
svn_fs_fs__file_checksum (unsigned char digest[],
node_revision_t *noderev,
apr_pool_t *pool)
{
if (noderev->data_rep)
memcpy (digest, noderev->data_rep->checksum, APR_MD5_DIGESTSIZE);
else
memset (digest, 0, APR_MD5_DIGESTSIZE);
return SVN_NO_ERROR;
}
representation_t *
svn_fs_fs__rep_copy (representation_t *rep,
apr_pool_t *pool)
{
representation_t *rep_new;
if (rep == NULL)
return NULL;
rep_new = apr_pcalloc (pool, sizeof (*rep_new));
memcpy (rep_new, rep, sizeof (*rep_new));
return rep_new;
}
/* Merge the internal-use-only CHANGE into a hash of public-FS
svn_fs_path_change_t CHANGES, collapsing multiple changes into a
single summarical (is that real word?) change per path. Also keep
the COPYFROM_HASH up to date with new adds and replaces. */
static svn_error_t *
fold_change (apr_hash_t *changes,
const change_t *change,
apr_hash_t *copyfrom_hash)
{
apr_pool_t *pool = apr_hash_pool_get (changes);
apr_pool_t *copyfrom_pool = apr_hash_pool_get (copyfrom_hash);
svn_fs_path_change_t *old_change, *new_change;
const char *path, *copyfrom_string, *copyfrom_path = NULL;
if ((old_change = apr_hash_get (changes, change->path, APR_HASH_KEY_STRING)))
{
/* This path already exists in the hash, so we have to merge
this change into the already existing one. */
/* Get the existing copyfrom entry for this path. */
copyfrom_string = apr_hash_get (copyfrom_hash, change->path,
APR_HASH_KEY_STRING);
/* If this entry existed in the copyfrom hash, we don't need to
copy it. */
if (copyfrom_string)
copyfrom_path = change->path;
/* Since the path already exists in the hash, we don't have to
dup the allocation for the path itself. */
path = change->path;
/* Sanity check: only allow NULL node revision ID in the
`reset' case. */
if ((! change->noderev_id) && (change->kind != svn_fs_path_change_reset))
return svn_error_create
(SVN_ERR_FS_CORRUPT, NULL,
_("Missing required node revision ID"));
/* Sanity check: we should be talking about the same node
revision ID as our last change except where the last change
was a deletion. */
if (change->noderev_id
&& (! svn_fs_fs__id_eq (old_change->node_rev_id, change->noderev_id))
&& (old_change->change_kind != svn_fs_path_change_delete))
return svn_error_create
(SVN_ERR_FS_CORRUPT, NULL,
_("Invalid change ordering: new node revision ID "
"without delete"));
/* Sanity check: an add, replacement, or reset must be the first
thing to follow a deletion. */
if ((old_change->change_kind == svn_fs_path_change_delete)
&& (! ((change->kind == svn_fs_path_change_replace)
|| (change->kind == svn_fs_path_change_reset)
|| (change->kind == svn_fs_path_change_add))))
return svn_error_create
(SVN_ERR_FS_CORRUPT, NULL,
_("Invalid change ordering: non-add change on deleted path"));
/* Now, merge that change in. */
switch (change->kind)
{
case svn_fs_path_change_reset:
/* A reset here will simply remove the path change from the
hash. */
old_change = NULL;
copyfrom_string = NULL;
break;
case svn_fs_path_change_delete:
if (old_change->change_kind == svn_fs_path_change_add)
{
/* If the path was introduced in this transaction via an
add, and we are deleting it, just remove the path
altogether. */
old_change = NULL;
}
else
{
/* A deletion overrules all previous changes. */
old_change->change_kind = svn_fs_path_change_delete;
old_change->text_mod = change->text_mod;
old_change->prop_mod = change->prop_mod;
}
copyfrom_string = NULL;
break;
case svn_fs_path_change_add:
case svn_fs_path_change_replace:
/* An add at this point must be following a previous delete,
so treat it just like a replace. */
old_change->change_kind = svn_fs_path_change_replace;
old_change->node_rev_id = svn_fs_fs__id_copy (change->noderev_id,
pool);
old_change->text_mod = change->text_mod;
old_change->prop_mod = change->prop_mod;
if (change->copyfrom_rev == SVN_INVALID_REVNUM)
{
copyfrom_string = apr_pstrdup (copyfrom_pool, "");
}
else
{
copyfrom_string = apr_psprintf (copyfrom_pool,
"%ld %s",
change->copyfrom_rev,
change->copyfrom_path);
}
break;
case svn_fs_path_change_modify:
default:
if (change->text_mod)
old_change->text_mod = TRUE;
if (change->prop_mod)
old_change->prop_mod = TRUE;
break;
}
/* Point our new_change to our (possibly modified) old_change. */
new_change = old_change;
}
else
{
/* This change is new to the hash, so make a new public change
structure from the internal one (in the hash's pool), and dup
the path into the hash's pool, too. */
new_change = apr_pcalloc (pool, sizeof (*new_change));
new_change->node_rev_id = svn_fs_fs__id_copy (change->noderev_id, pool);
new_change->change_kind = change->kind;
new_change->text_mod = change->text_mod;
new_change->prop_mod = change->prop_mod;
if (change->copyfrom_rev != SVN_INVALID_REVNUM)
{
copyfrom_string = apr_psprintf (copyfrom_pool, "%ld %s",
change->copyfrom_rev,
change->copyfrom_path);
}
else
{
copyfrom_string = apr_pstrdup (copyfrom_pool, "");
}
path = apr_pstrdup (pool, change->path);
}
/* Add (or update) this path. */
apr_hash_set (changes, path, APR_HASH_KEY_STRING, new_change);
/* If we don't yet have a path string allocated in the copyfrom_hash
get something to use. If we are adding an entry, allocate
something new, otherwise we just need a key and the one allocated
for the changes hash will work. */
if (! copyfrom_path)
{
copyfrom_path = copyfrom_string ? apr_pstrdup (copyfrom_pool, path)
: path;
}
apr_hash_set (copyfrom_hash, copyfrom_path, APR_HASH_KEY_STRING,
copyfrom_string);
return SVN_NO_ERROR;
}
/* Read the next entry in the changes record from file FILE and store
the resulting change in *CHANGE_P. If there is no next record,
store NULL there. Perform all allocations from POOL. */
static svn_error_t *
read_change (change_t **change_p,
apr_file_t *file,
apr_pool_t *pool)
{
char buf[4096];
apr_size_t len = sizeof (buf);
change_t *change;
char *str, *last_str;
svn_error_t *err;
/* Default return value. */
*change_p = NULL;
err = svn_io_read_length_line (file, buf, &len, pool);
/* Check for a blank line. */
if (err || (len == 0))
{
if (err && APR_STATUS_IS_EOF (err->apr_err))
{
svn_error_clear (err);
return SVN_NO_ERROR;
}
if ((len == 0) && (! err))
return SVN_NO_ERROR;
return err;
}
change = apr_pcalloc (pool, sizeof (*change));
/* Get the node-id of the change. */
str = apr_strtok (buf, " ", &last_str);
if (str == NULL)
return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
_("Invalid changes line in rev-file"));
change->noderev_id = svn_fs_fs__id_parse (str, strlen (str), pool);
/* Get the change type. */
str = apr_strtok (NULL, " ", &last_str);
if (str == NULL)
return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
_("Invalid changes line in rev-file"));
if (strcmp (str, ACTION_MODIFY) == 0)
{
change->kind = svn_fs_path_change_modify;
}
else if (strcmp (str, ACTION_ADD) == 0)
{
change->kind = svn_fs_path_change_add;
}
else if (strcmp (str, ACTION_DELETE) == 0)
{
change->kind = svn_fs_path_change_delete;
}
else if (strcmp (str, ACTION_REPLACE) == 0)
{
change->kind = svn_fs_path_change_replace;
}
else if (strcmp (str, ACTION_RESET) == 0)
{
change->kind = svn_fs_path_change_reset;
}
else
{
return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
_("Invalid change kind in rev file"));
}
/* Get the text-mod flag. */
str = apr_strtok (NULL, " ", &last_str);
if (str == NULL)
return svn_error_create (SVN_ERR_FS_CO
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -