📄 lock.c
字号:
svn_wc_adm_probe_try (svn_wc_adm_access_t **adm_access,
svn_wc_adm_access_t *associated,
const char *path,
svn_boolean_t write_lock,
svn_boolean_t tree_lock,
apr_pool_t *pool)
{
return svn_wc_adm_probe_try2 (adm_access, associated, path, write_lock,
(tree_lock ? -1 : 0), pool);
}
svn_error_t *
svn_wc_adm_probe_try2 (svn_wc_adm_access_t **adm_access,
svn_wc_adm_access_t *associated,
const char *path,
svn_boolean_t write_lock,
int depth,
apr_pool_t *pool)
{
svn_error_t *err;
err = svn_wc_adm_probe_retrieve (adm_access, associated, path, pool);
/* SVN_ERR_WC_NOT_LOCKED would mean there was no access baton for
path in associated, in which case we want to open an access
baton and add it to associated. */
if (err && (err->apr_err == SVN_ERR_WC_NOT_LOCKED))
{
svn_error_clear (err);
err = svn_wc_adm_probe_open2 (adm_access, associated,
path, write_lock, depth,
svn_wc_adm_access_pool (associated));
/* If the path is not a versioned directory, we just return a
null access baton with no error. Note that of the errors we
do report, the most important (and probably most likely) is
SVN_ERR_WC_LOCKED. That error would mean that someone else
has this area locked, and we definitely want to bail in that
case. */
if (err && (err->apr_err == SVN_ERR_WC_NOT_DIRECTORY))
{
svn_error_clear (err);
*adm_access = NULL;
err = NULL;
}
}
return err;
}
/* Does the work of closing the access baton ADM_ACCESS. Any physical
locks are removed from the working copy if PRESERVE_LOCK is FALSE, or
are left if PRESERVE_LOCK is TRUE. Any associated access batons that
are direct descendents will also be closed.
### FIXME: If the set has a "hole", say it contains locks for the
### directories A, A/B, A/B/C/X but not A/B/C then closing A/B will not
### reach A/B/C/X .
*/
static svn_error_t *
do_close (svn_wc_adm_access_t *adm_access,
svn_boolean_t preserve_lock)
{
apr_hash_index_t *hi;
if (adm_access->type == svn_wc__adm_access_closed)
return SVN_NO_ERROR;
apr_pool_cleanup_kill (adm_access->pool, adm_access, pool_cleanup);
/* Close children */
if (adm_access->set)
{
/* The documentation says that modifying a hash while iterating over
it is allowed but unpredictable! So, first loop to identify and
copy direct descendents, second loop to close them. */
int i;
apr_array_header_t *children = apr_array_make (adm_access->pool, 1,
sizeof (adm_access));
for (hi = apr_hash_first (adm_access->pool, adm_access->set);
hi;
hi = apr_hash_next (hi))
{
const void *key;
void *val;
const char *path;
svn_wc_adm_access_t *associated;
const char *name;
apr_hash_this (hi, &key, NULL, &val);
path = key;
associated = val;
name = svn_path_is_child (adm_access->path, path, adm_access->pool);
if (name && svn_path_is_single_path_component (name))
{
if (associated != &missing)
*(svn_wc_adm_access_t**)apr_array_push (children) = associated;
/* Deleting current element is allowed and predictable */
apr_hash_set (adm_access->set, path, APR_HASH_KEY_STRING, NULL);
}
}
for (i = 0; i < children->nelts; ++i)
{
svn_wc_adm_access_t *child = APR_ARRAY_IDX(children, i,
svn_wc_adm_access_t*);
SVN_ERR (do_close (child, preserve_lock));
}
}
/* Physically unlock if required */
if (adm_access->type == svn_wc__adm_access_write_lock)
{
if (adm_access->lock_exists && ! preserve_lock)
{
SVN_ERR (remove_lock (adm_access->path, adm_access->pool));
adm_access->lock_exists = FALSE;
}
/* Reset to prevent further use of the write lock. */
adm_access->type = svn_wc__adm_access_closed;
}
/* Detach from set */
if (adm_access->set)
{
apr_hash_set (adm_access->set, adm_access->path, APR_HASH_KEY_STRING,
NULL);
assert (! adm_access->set_owner || apr_hash_count (adm_access->set) == 0);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_adm_close (svn_wc_adm_access_t *adm_access)
{
return do_close (adm_access, FALSE);
}
svn_boolean_t
svn_wc_adm_locked (svn_wc_adm_access_t *adm_access)
{
return adm_access->type == svn_wc__adm_access_write_lock;
}
svn_error_t *
svn_wc__adm_write_check (svn_wc_adm_access_t *adm_access)
{
if (adm_access->type == svn_wc__adm_access_write_lock)
{
if (adm_access->lock_exists)
{
/* Check physical lock still exists and hasn't been stolen. This
really is paranoia, I have only ever seen one report of this
triggering (from someone using the 0.25 release) and that was
never reproduced. The check accesses the physical filesystem
so it is expensive, but it only runs when we are going to
modify the admin area. If it ever proves to be a bottleneck
the physical check could be removed, just leaving the logical
check. */
svn_boolean_t locked;
SVN_ERR (svn_wc_locked (&locked, adm_access->path, adm_access->pool));
if (! locked)
return svn_error_createf (SVN_ERR_WC_NOT_LOCKED, NULL,
_("Write-lock stolen in '%s'"),
adm_access->path);
}
}
else
{
return svn_error_createf (SVN_ERR_WC_NOT_LOCKED, NULL,
_("No write-lock in '%s'"), adm_access->path);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_locked (svn_boolean_t *locked, const char *path, apr_pool_t *pool)
{
svn_node_kind_t kind;
const char *lockfile
= svn_wc__adm_path (path, 0, pool, SVN_WC__ADM_LOCK, NULL);
SVN_ERR (svn_io_check_path (lockfile, &kind, pool));
if (kind == svn_node_file)
*locked = TRUE;
else if (kind == svn_node_none)
*locked = FALSE;
else
return svn_error_createf (SVN_ERR_WC_LOCKED, NULL,
_("Lock file '%s' is not a regular file"),
lockfile);
return SVN_NO_ERROR;
}
const char *
svn_wc_adm_access_path (svn_wc_adm_access_t *adm_access)
{
return adm_access->path;
}
apr_pool_t *
svn_wc_adm_access_pool (svn_wc_adm_access_t *adm_access)
{
return adm_access->pool;
}
svn_error_t *
svn_wc__adm_is_cleanup_required (svn_boolean_t *cleanup,
svn_wc_adm_access_t *adm_access,
apr_pool_t *pool)
{
svn_node_kind_t kind;
const char *log_path = svn_wc__adm_path (svn_wc_adm_access_path (adm_access),
FALSE, pool, SVN_WC__ADM_LOG, NULL);
/* The presence of a log file demands cleanup */
SVN_ERR (svn_io_check_path (log_path, &kind, pool));
*cleanup = (kind == svn_node_file);
return SVN_NO_ERROR;
}
/* Ensure that the cache for the pruned hash (no deleted entries) in
ADM_ACCESS is valid if the full hash is cached. POOL is used for
local, short term, memory allocation.
### Should this sort of processing be in entries.c? */
static void
prune_deleted (svn_wc_adm_access_t *adm_access,
apr_pool_t *pool)
{
if (! adm_access->entries && adm_access->entries_hidden)
{
apr_hash_index_t *hi;
/* I think it will be common for there to be no deleted entries, so
it is worth checking for that case as we can optimise it. */
for (hi = apr_hash_first (pool, adm_access->entries_hidden);
hi;
hi = apr_hash_next (hi))
{
void *val;
const svn_wc_entry_t *entry;
apr_hash_this (hi, NULL, NULL, &val);
entry = val;
if ((entry->deleted
&& (entry->schedule != svn_wc_schedule_add)
&& (entry->schedule != svn_wc_schedule_replace))
|| entry->absent)
break;
}
if (! hi)
{
/* There are no deleted entries, so we can use the full hash */
adm_access->entries = adm_access->entries_hidden;
return;
}
/* Construct pruned hash without deleted entries */
adm_access->entries = apr_hash_make (adm_access->pool);
for (hi = apr_hash_first (pool, adm_access->entries_hidden);
hi;
hi = apr_hash_next (hi))
{
void *val;
const void *key;
const svn_wc_entry_t *entry;
apr_hash_this (hi, &key, NULL, &val);
entry = val;
if (((entry->deleted == FALSE) && (entry->absent == FALSE))
|| (entry->schedule == svn_wc_schedule_add)
|| (entry->schedule == svn_wc_schedule_replace))
{
apr_hash_set (adm_access->entries, key,
APR_HASH_KEY_STRING, entry);
}
}
}
}
void
svn_wc__adm_access_set_entries (svn_wc_adm_access_t *adm_access,
svn_boolean_t show_hidden,
apr_hash_t *entries)
{
if (show_hidden)
adm_access->entries_hidden = entries;
else
adm_access->entries = entries;
}
apr_hash_t *
svn_wc__adm_access_entries (svn_wc_adm_access_t *adm_access,
svn_boolean_t show_hidden,
apr_pool_t *pool)
{
if (! show_hidden)
{
prune_deleted (adm_access, pool);
return adm_access->entries;
}
else
return adm_access->entries_hidden;
}
int
svn_wc__adm_wc_format (svn_wc_adm_access_t *adm_access)
{
return adm_access->wc_format;
}
svn_boolean_t
svn_wc__adm_missing (svn_wc_adm_access_t *adm_access,
const char *path)
{
if (adm_access->set
&& apr_hash_get (adm_access->set, path, APR_HASH_KEY_STRING) == &missing)
return TRUE;
return FALSE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -