📄 lock.c
字号:
svn_boolean_t under_construction,
apr_pool_t *pool)
{
svn_wc_adm_access_t *lock;
int wc_format;
svn_error_t *err;
if (associated)
{
adm_ensure_set (associated);
lock = apr_hash_get (associated->set, path, APR_HASH_KEY_STRING);
if (lock && lock != &missing)
/* Already locked. The reason we don't return the existing baton
here is that the user is supposed to know whether a directory is
locked: if it's not locked call svn_wc_adm_open, if it is locked
call svn_wc_adm_retrieve. */
return svn_error_createf (SVN_ERR_WC_LOCKED, NULL,
_("Working copy '%s' locked"),
path);
}
if (! under_construction)
{
/* By reading the format file we check both that PATH is a directory
and that it is a working copy. */
err = svn_io_read_version_file (&wc_format,
svn_wc__adm_path (path, FALSE, pool,
SVN_WC__ADM_FORMAT,
NULL),
pool);
if (err)
{
/* Should we attempt to distinguish certain errors? */
svn_error_clear (err);
return svn_error_createf (SVN_ERR_WC_NOT_DIRECTORY, NULL,
_("'%s' is not a working copy"),
svn_path_local_style (path, pool));
}
SVN_ERR (svn_wc__check_format (wc_format,
svn_path_local_style (path, pool),
pool));
}
/* Need to create a new lock */
if (write_lock)
{
lock = adm_access_alloc (svn_wc__adm_access_write_lock, path, pool);
SVN_ERR (create_lock (lock, 0, pool));
lock->lock_exists = TRUE;
}
else
{
lock = adm_access_alloc (svn_wc__adm_access_unlocked, path, pool);
}
if (! under_construction)
{
lock->wc_format = wc_format;
if (write_lock)
SVN_ERR (maybe_upgrade_format (lock, pool));
}
if (depth != 0)
{
apr_hash_t *entries;
apr_hash_index_t *hi;
apr_pool_t *subpool = svn_pool_create (pool);
/* Reduce depth since we are about to recurse */
if (depth > 0)
depth--;
/* Ask for the deleted entries because most operations request them
at some stage, getting them now avoids a second file parse. */
SVN_ERR (svn_wc_entries_read (&entries, lock, TRUE, subpool));
/* Use a temporary hash until all children have been opened. */
if (associated)
lock->set = apr_hash_make (subpool);
/* Open the tree */
for (hi = apr_hash_first (subpool, entries); hi; hi = apr_hash_next (hi))
{
void *val;
const svn_wc_entry_t *entry;
svn_wc_adm_access_t *entry_access;
const char *entry_path;
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->kind != svn_node_dir
|| ! strcmp (entry->name, SVN_WC_ENTRY_THIS_DIR))
continue;
entry_path = svn_path_join (lock->path, entry->name, subpool);
/* Don't use the subpool pool here, the lock needs to persist */
err = do_open (&entry_access, lock, entry_path, write_lock, depth,
FALSE, lock->pool);
if (err)
{
if (err->apr_err != SVN_ERR_WC_NOT_DIRECTORY)
{
/* This closes all the children in temporary hash as well */
svn_error_clear (svn_wc_adm_close (lock));
svn_pool_destroy (subpool);
return err;
}
/* It's missing or obstructed, so store a placeholder */
svn_error_clear (err);
adm_ensure_set (lock);
apr_hash_set (lock->set, apr_pstrdup (lock->pool, entry_path),
APR_HASH_KEY_STRING, &missing);
continue;
}
/* ### Perhaps we should verify that the parent and child agree
### about the URL of the child? */
}
/* Switch from temporary hash to permanent hash */
if (associated)
{
for (hi = apr_hash_first (subpool, lock->set);
hi;
hi = apr_hash_next (hi))
{
const void *key;
void *val;
const char *entry_path;
svn_wc_adm_access_t *entry_access;
apr_hash_this (hi, &key, NULL, &val);
entry_path = key;
entry_access = val;
apr_hash_set (associated->set, entry_path, APR_HASH_KEY_STRING,
entry_access);
entry_access->set = associated->set;
}
lock->set = associated->set;
}
svn_pool_destroy (subpool);
}
if (associated)
{
lock->set = associated->set;
apr_hash_set (lock->set, lock->path, APR_HASH_KEY_STRING, lock);
}
/* It's important that the cleanup handler is registered *after* at least
one UTF8 conversion has been done, since such a conversion may create
the apr_xlate_t object in the pool, and that object must be around
when the cleanup handler runs. If the apr_xlate_t cleanup handler
were to run *before* the access baton cleanup handler, then the access
baton's handler won't work. */
apr_pool_cleanup_register (lock->pool, lock, pool_cleanup,
pool_cleanup_child);
*adm_access = lock;
return SVN_NO_ERROR;
}
/* To preserve API compatibility with Subversion 1.0.0 */
svn_error_t *
svn_wc_adm_open (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_open2 (adm_access, associated, path, write_lock,
(tree_lock ? -1 : 0), pool);
}
svn_error_t *
svn_wc_adm_open2 (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)
{
return do_open (adm_access, associated, path, write_lock, depth, FALSE,
pool);
}
svn_error_t *
svn_wc__adm_pre_open (svn_wc_adm_access_t **adm_access,
const char *path,
apr_pool_t *pool)
{
return do_open (adm_access, NULL, path, TRUE, 0, TRUE, pool);
}
/* To preserve API compatibility with Subversion 1.0.0 */
svn_error_t *
svn_wc_adm_probe_open (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_open2 (adm_access, associated, path,
write_lock, (tree_lock ? -1 : 0), pool);
}
svn_error_t *
svn_wc_adm_probe_open2 (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;
const char *dir;
int wc_format;
SVN_ERR (probe (&dir, path, &wc_format, pool));
/* If we moved up a directory, then the path is not a directory, or it
is not under version control. In either case, the notion of a depth
does not apply to the provided path. Disable it so that we don't end
up trying to lock more than we need. */
if (dir != path)
depth = 0;
err = svn_wc_adm_open2 (adm_access, associated, dir, write_lock,
depth, pool);
if (err)
{
svn_error_t *err2;
/* If we got an error on the parent dir, that means we failed to
get an access baton for the child in the first place. And if
the reason we couldn't get the child access baton is that the
child is not a versioned directory, then return an error
about the child, not the parent. */
svn_node_kind_t child_kind;
if ((err2 = svn_io_check_path (path, &child_kind, pool)))
{
svn_error_compose (err, err2);
return err;
}
if ((dir != path)
&& (child_kind == svn_node_dir)
&& (err->apr_err == SVN_ERR_WC_NOT_DIRECTORY))
{
svn_error_clear (err);
return svn_error_createf (SVN_ERR_WC_NOT_DIRECTORY, NULL,
_("'%s' is not a working copy"),
svn_path_local_style (path, pool));
}
else
{
return err;
}
}
if (wc_format && ! (*adm_access)->wc_format)
(*adm_access)->wc_format = wc_format;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__adm_retrieve_internal (svn_wc_adm_access_t **adm_access,
svn_wc_adm_access_t *associated,
const char *path,
apr_pool_t *pool)
{
if (associated->set)
*adm_access = apr_hash_get (associated->set, path, APR_HASH_KEY_STRING);
else if (! strcmp (associated->path, path))
*adm_access = associated;
else
*adm_access = NULL;
if (*adm_access == &missing)
*adm_access = NULL;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_adm_retrieve (svn_wc_adm_access_t **adm_access,
svn_wc_adm_access_t *associated,
const char *path,
apr_pool_t *pool)
{
SVN_ERR (svn_wc__adm_retrieve_internal (adm_access, associated, path, pool));
/* Most of the code expects access batons to exist, so returning an error
generally makes the calling code simpler as it doesn't need to check
for NULL batons. */
if (! *adm_access)
return svn_error_createf (SVN_ERR_WC_NOT_LOCKED, NULL,
_("Working copy '%s' is missing or not locked"),
path);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_adm_probe_retrieve (svn_wc_adm_access_t **adm_access,
svn_wc_adm_access_t *associated,
const char *path,
apr_pool_t *pool)
{
const char *dir;
int wc_format;
SVN_ERR (probe (&dir, path, &wc_format, pool));
SVN_ERR (svn_wc_adm_retrieve (adm_access, associated, dir, pool));
if (wc_format && ! (*adm_access)->wc_format)
(*adm_access)->wc_format = wc_format;
return SVN_NO_ERROR;
}
/* To preserve API compatibility with Subversion 1.0.0 */
svn_error_t *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -