#include <string.h>
#include <stdlib.h>
#include <apr_pools.h>
#include <apr_tables.h>
#include <apr_hash.h>
#include <apr_file_io.h>
#include <apr_time.h>
#include <apr_errno.h>
#include "svn_types.h"
#include "svn_pools.h"
#include "svn_string.h"
#include "svn_error.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_hash.h"
#include "svn_wc.h"
#include "svn_io.h"
#include "svn_time.h"
#include "svn_sorts.h"
#include "wc.h"
#include "adm_files.h"
#include "props.h"
#include "translate.h"
#include "workqueue.h"
#include "svn_private_config.h"
#include "private/svn_io_private.h"
#include "private/svn_wc_private.h"
struct svn_wc_committed_queue_t
{
apr_pool_t *pool;
apr_hash_t *queue;
svn_boolean_t have_recursive;
};
typedef struct committed_queue_item_t
{
const char *local_abspath;
svn_boolean_t recurse;
svn_boolean_t no_unlock;
svn_boolean_t keep_changelist;
const svn_checksum_t *sha1_checksum;
apr_hash_t *new_dav_cache;
} committed_queue_item_t;
apr_pool_t *
svn_wc__get_committed_queue_pool(const struct svn_wc_committed_queue_t *queue)
{
return queue->pool;
}
static svn_error_t *
process_committed_leaf(svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t via_recurse,
svn_revnum_t new_revnum,
apr_time_t new_changed_date,
const char *new_changed_author,
apr_hash_t *new_dav_cache,
svn_boolean_t no_unlock,
svn_boolean_t keep_changelist,
const svn_checksum_t *checksum,
apr_pool_t *scratch_pool)
{
svn_wc__db_status_t status;
svn_wc__db_kind_t kind;
const svn_checksum_t *copied_checksum;
svn_revnum_t new_changed_rev = new_revnum;
svn_boolean_t have_base;
svn_boolean_t have_work;
svn_boolean_t had_props;
svn_boolean_t prop_mods;
svn_skel_t *work_item = NULL;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, &copied_checksum,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, &had_props, &prop_mods,
&have_base, NULL, &have_work,
db, local_abspath,
scratch_pool, scratch_pool));
{
const char *adm_abspath;
if (kind == svn_wc__db_kind_dir)
adm_abspath = local_abspath;
else
adm_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
SVN_ERR(svn_wc__write_check(db, adm_abspath, scratch_pool));
}
if (status == svn_wc__db_status_deleted)
{
return svn_error_trace(
svn_wc__db_op_remove_node(
db, local_abspath,
(have_base && !via_recurse)
? new_revnum : SVN_INVALID_REVNUM,
kind,
scratch_pool));
}
else if (status == svn_wc__db_status_not_present)
{
return SVN_NO_ERROR;
}
SVN_ERR_ASSERT(status == svn_wc__db_status_normal
|| status == svn_wc__db_status_incomplete
|| status == svn_wc__db_status_added);
if (kind != svn_wc__db_kind_dir)
{
if (checksum == NULL)
{
SVN_ERR_ASSERT(copied_checksum != NULL);
checksum = copied_checksum;
if (via_recurse && !prop_mods)
{
SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL,
NULL, &new_changed_rev,
&new_changed_date,
&new_changed_author, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
db, local_abspath,
scratch_pool, scratch_pool));
}
}
SVN_ERR(svn_wc__wq_build_file_commit(&work_item,
db, local_abspath,
prop_mods,
scratch_pool, scratch_pool));
}
SVN_ERR(svn_wc__db_global_commit(db, local_abspath,
new_revnum, new_changed_rev,
new_changed_date, new_changed_author,
checksum,
NULL ,
new_dav_cache,
keep_changelist,
no_unlock,
work_item,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__process_committed_internal(svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t recurse,
svn_boolean_t top_of_recurse,
svn_revnum_t new_revnum,
apr_time_t new_date,
const char *rev_author,
apr_hash_t *new_dav_cache,
svn_boolean_t no_unlock,
svn_boolean_t keep_changelist,
const svn_checksum_t *sha1_checksum,
const svn_wc_committed_queue_t *queue,
apr_pool_t *scratch_pool)
{
svn_wc__db_kind_t kind;
SVN_ERR(process_committed_leaf(db, local_abspath, !top_of_recurse,
new_revnum, new_date, rev_author,
new_dav_cache,
no_unlock, keep_changelist,
sha1_checksum,
scratch_pool));
SVN_ERR(svn_wc__db_read_kind(&kind, db, local_abspath, TRUE, scratch_pool));
if (recurse && kind == svn_wc__db_kind_dir)
{
const apr_array_header_t *children;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
int i;
SVN_ERR(svn_wc__db_read_children(&children, db, local_abspath,
scratch_pool, iterpool));
for (i = 0; i < children->nelts; i++)
{
const char *name = APR_ARRAY_IDX(children, i, const char *);
const char *this_abspath;
svn_wc__db_status_t status;
svn_pool_clear(iterpool);
this_abspath = svn_dirent_join(local_abspath, name, iterpool);
SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
db, this_abspath,
iterpool, iterpool));
if (status == svn_wc__db_status_excluded)
continue;
sha1_checksum = NULL;
if (kind != svn_wc__db_kind_dir && queue != NULL)
{
const committed_queue_item_t *cqi;
cqi = apr_hash_get(queue->queue, this_abspath,
APR_HASH_KEY_STRING);
if (cqi != NULL)
{
sha1_checksum = cqi->sha1_checksum;
}
}
SVN_ERR(svn_wc__process_committed_internal(
db, this_abspath,
TRUE ,
FALSE ,
new_revnum, new_date,
rev_author,
NULL ,
TRUE ,
keep_changelist,
sha1_checksum,
queue,
iterpool));
}
svn_pool_destroy(iterpool);
}
return SVN_NO_ERROR;
}
apr_hash_t *
svn_wc__prop_array_to_hash(const apr_array_header_t *props,
apr_pool_t *result_pool)
{
int i;
apr_hash_t *prophash;
if (props == NULL || props->nelts == 0)
return NULL;
prophash = apr_hash_make(result_pool);
for (i = 0; i < props->nelts; i++)
{
const svn_prop_t *prop = APR_ARRAY_IDX(props, i, const svn_prop_t *);
if (prop->value != NULL)
apr_hash_set(prophash, prop->name, APR_HASH_KEY_STRING, prop->value);
}
return prophash;
}
svn_wc_committed_queue_t *
svn_wc_committed_queue_create(apr_pool_t *pool)
{
svn_wc_committed_queue_t *q;
q = apr_palloc(pool, sizeof(*q));
q->pool = pool;
q->queue = apr_hash_make(pool);
q->have_recursive = FALSE;
return q;
}
svn_error_t *
svn_wc_queue_committed3(svn_wc_committed_queue_t *queue,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_boolean_t recurse,
const apr_array_header_t *wcprop_changes,
svn_boolean_t remove_lock,
svn_boolean_t remove_changelist,
const svn_checksum_t *sha1_checksum,
apr_pool_t *scratch_pool)
{
committed_queue_item_t *cqi;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
queue->have_recursive |= recurse;
cqi = apr_palloc(queue->pool, sizeof(*cqi));
cqi->local_abspath = local_abspath;
cqi->recurse = recurse;
cqi->no_unlock = !remove_lock;
cqi->keep_changelist = !remove_changelist;
cqi->sha1_checksum = sha1_checksum;
cqi->new_dav_cache = svn_wc__prop_array_to_hash(wcprop_changes, queue->pool);
apr_hash_set(queue->queue, local_abspath, APR_HASH_KEY_STRING, cqi);
return SVN_NO_ERROR;
}
static svn_boolean_t
have_recursive_parent(apr_hash_t *queue,
const committed_queue_item_t *item,
apr_pool_t *scratch_pool)
{
apr_hash_index_t *hi;
const char *local_abspath = item->local_abspath;
for (hi = apr_hash_first(scratch_pool, queue); hi; hi = apr_hash_next(hi))
{
const committed_queue_item_t *qi = svn__apr_hash_index_val(hi);
if (qi == item)
continue;
if (qi->recurse && svn_dirent_is_child(qi->local_abspath, local_abspath,
NULL))
return TRUE;
}
return FALSE;
}
svn_error_t *
svn_wc_process_committed_queue2(svn_wc_committed_queue_t *queue,
svn_wc_context_t *wc_ctx,
svn_revnum_t new_revnum,
const char *rev_date,
const char *rev_author,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
apr_array_header_t *sorted_queue;
int i;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
apr_time_t new_date;
apr_hash_t *run_wqs = apr_hash_make(scratch_pool);
apr_hash_index_t *hi;
if (rev_date)
SVN_ERR(svn_time_from_cstring(&new_date, rev_date, iterpool));
else
new_date = 0;
sorted_queue = svn_sort__hash(queue->queue, svn_sort_compare_items_as_paths,
scratch_pool);
for (i = 0; i < sorted_queue->nelts; i++)
{
const svn_sort__item_t *sort_item
= &APR_ARRAY_IDX(sorted_queue, i, svn_sort__item_t);
const committed_queue_item_t *cqi = sort_item->value;
const char *wcroot_abspath;
svn_pool_clear(iterpool);
if (queue->have_recursive && have_recursive_parent(queue->queue, cqi,
iterpool))
continue;
SVN_ERR(svn_wc__process_committed_internal(
wc_ctx->db, cqi->local_abspath,
cqi->recurse,
TRUE ,
new_revnum, new_date, rev_author,
cqi->new_dav_cache,
cqi->no_unlock,
cqi->keep_changelist,
cqi->sha1_checksum, queue,
iterpool));
SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath,
wc_ctx->db, cqi->local_abspath,
iterpool, iterpool));
if (! apr_hash_get(run_wqs, wcroot_abspath, APR_HASH_KEY_STRING))
{
wcroot_abspath = apr_pstrdup(scratch_pool, wcroot_abspath);
apr_hash_set(run_wqs, wcroot_abspath, APR_HASH_KEY_STRING,
wcroot_abspath);
}
}
SVN_ERR(svn_hash__clear(queue->queue, iterpool));
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
for (hi = apr_hash_first(scratch_pool, run_wqs);
hi;
hi = apr_hash_next(hi))
{
const char *wcroot_abspath = svn__apr_hash_index_key(hi);
svn_pool_clear(iterpool);
SVN_ERR(svn_wc__wq_run(wc_ctx->db, wcroot_abspath,
cancel_func, cancel_baton,
iterpool));
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
static svn_error_t *
erase_unversioned_from_wc(const char *path,
svn_boolean_t ignore_enoent,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_error_t *err;
err = svn_io_remove_file2(path, ignore_enoent, scratch_pool);
if (err)
{
svn_error_clear(err);
err = svn_io_remove_dir2(path, ignore_enoent, cancel_func, cancel_baton,
scratch_pool);
if (err)
{
svn_node_kind_t kind;
svn_error_clear(err);
SVN_ERR(svn_io_check_path(path, &kind, scratch_pool));
if (kind == svn_node_file)
SVN_ERR(svn_io_remove_file2(path, ignore_enoent, scratch_pool));
else if (kind == svn_node_dir)
SVN_ERR(svn_io_remove_dir2(path, ignore_enoent,
cancel_func, cancel_baton,
scratch_pool));
else if (kind == svn_node_none)
return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL,
_("'%s' does not exist"),
svn_dirent_local_style(path,
scratch_pool));
else
return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Unsupported node kind for path '%s'"),
svn_dirent_local_style(path,
scratch_pool));
}
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_delete4(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_boolean_t keep_local,
svn_boolean_t delete_unversioned_target,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
apr_pool_t *pool = scratch_pool;
svn_wc__db_t *db = wc_ctx->db;
svn_error_t *err;
svn_wc__db_status_t status;
svn_wc__db_kind_t kind;
svn_boolean_t conflicted;
const apr_array_header_t *conflicts;
err = svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, &conflicted,
NULL, NULL, NULL, NULL, NULL, NULL,
db, local_abspath, pool, pool);
if (delete_unversioned_target &&
err != NULL && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
{
svn_error_clear(err);
if (!keep_local)
SVN_ERR(erase_unversioned_from_wc(local_abspath, FALSE,
cancel_func, cancel_baton,
pool));
return SVN_NO_ERROR;
}
else
SVN_ERR(err);
switch (status)
{
case svn_wc__db_status_excluded:
case svn_wc__db_status_not_present:
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("'%s' cannot be deleted"),
svn_dirent_local_style(local_abspath, pool));
default:
break;
}
if (status == svn_wc__db_status_normal
&& kind == svn_wc__db_kind_dir)
{
svn_boolean_t is_wcroot;
SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, db, local_abspath, pool));
if (is_wcroot)
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
_("'%s' is the root of a working copy and "
"cannot be deleted"),
svn_dirent_local_style(local_abspath, pool));
}
SVN_ERR(svn_wc__write_check(db, svn_dirent_dirname(local_abspath, pool),
pool));
if (!keep_local && conflicted)
SVN_ERR(svn_wc__db_read_conflicts(&conflicts, db, local_abspath,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__db_op_delete(db, local_abspath,
notify_func, notify_baton,
cancel_func, cancel_baton,
pool));
if (!keep_local && conflicted && conflicts != NULL)
{
int i;
for (i = 0; i < conflicts->nelts; i++)
{
const svn_wc_conflict_description2_t *desc;
desc = APR_ARRAY_IDX(conflicts, i,
const svn_wc_conflict_description2_t*);
if (desc->kind == svn_wc_conflict_kind_text)
{
if (desc->base_abspath != NULL)
{
SVN_ERR(svn_io_remove_file2(desc->base_abspath, TRUE,
scratch_pool));
}
if (desc->their_abspath != NULL)
{
SVN_ERR(svn_io_remove_file2(desc->their_abspath, TRUE,
scratch_pool));
}
if (desc->my_abspath != NULL)
{
SVN_ERR(svn_io_remove_file2(desc->my_abspath, TRUE,
scratch_pool));
}
}
else if (desc->kind == svn_wc_conflict_kind_property
&& desc->their_abspath != NULL)
{
SVN_ERR(svn_io_remove_file2(desc->their_abspath, TRUE,
scratch_pool));
}
}
}
if (!keep_local)
{
SVN_ERR(erase_unversioned_from_wc(local_abspath, TRUE,
cancel_func, cancel_baton,
pool));
}
return SVN_NO_ERROR;
}
static svn_error_t *
add_from_disk(svn_wc__db_t *db,
const char *local_abspath,
svn_node_kind_t kind,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
if (kind == svn_node_file)
{
SVN_ERR(svn_wc__db_op_add_file(db, local_abspath, NULL, scratch_pool));
}
else
{
SVN_ERR(svn_wc__db_op_add_directory(db, local_abspath, NULL,
scratch_pool));
}
return SVN_NO_ERROR;
}
static svn_error_t *
check_can_add_to_parent(const char **repos_root_url,
const char **repos_uuid,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
svn_wc__db_status_t parent_status;
svn_wc__db_kind_t parent_kind;
svn_error_t *err;
SVN_ERR(svn_wc__write_check(db, parent_abspath, scratch_pool));
err = svn_wc__db_read_info(&parent_status, &parent_kind, NULL,
NULL, repos_root_url, repos_uuid, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
db, parent_abspath, result_pool, scratch_pool);
if (err
|| parent_status == svn_wc__db_status_not_present
|| parent_status == svn_wc__db_status_excluded
|| parent_status == svn_wc__db_status_server_excluded)
{
return
svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, err,
_("Can't find parent directory's node while"
" trying to add '%s'"),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
else if (parent_status == svn_wc__db_status_deleted)
{
return
svn_error_createf(SVN_ERR_WC_SCHEDULE_CONFLICT, NULL,
_("Can't add '%s' to a parent directory"
" scheduled for deletion"),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
else if (parent_kind != svn_wc__db_kind_dir)
return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
_("Can't schedule an addition of '%s'"
" below a not-directory node"),
svn_dirent_local_style(local_abspath,
scratch_pool));
if ((repos_root_url && ! *repos_root_url)
|| (repos_uuid && ! *repos_uuid))
{
if (parent_status == svn_wc__db_status_added)
SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL,
repos_root_url, repos_uuid, NULL,
NULL, NULL, NULL,
db, parent_abspath,
result_pool, scratch_pool));
else
SVN_ERR(svn_wc__db_scan_base_repos(NULL,
repos_root_url, repos_uuid,
db, parent_abspath,
result_pool, scratch_pool));
}
return SVN_NO_ERROR;
}
static svn_error_t *
check_can_add_node(svn_node_kind_t *kind_p,
svn_boolean_t *db_row_exists_p,
svn_boolean_t *is_wc_root_p,
svn_wc__db_t *db,
const char *local_abspath,
const char *copyfrom_url,
svn_revnum_t copyfrom_rev,
apr_pool_t *scratch_pool)
{
const char *base_name = svn_dirent_basename(local_abspath, scratch_pool);
svn_boolean_t is_wc_root;
svn_node_kind_t kind;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(!copyfrom_url || (svn_uri_is_canonical(copyfrom_url,
scratch_pool)
&& SVN_IS_VALID_REVNUM(copyfrom_rev)));
if (svn_wc_is_adm_dir(base_name, scratch_pool))
return svn_error_createf
(SVN_ERR_ENTRY_FORBIDDEN, NULL,
_("Can't create an entry with a reserved name while trying to add '%s'"),
svn_dirent_local_style(local_abspath, scratch_pool));
SVN_ERR(svn_path_check_valid(local_abspath, scratch_pool));
SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
if (kind == svn_node_none)
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("'%s' not found"),
svn_dirent_local_style(local_abspath,
scratch_pool));
if (kind == svn_node_unknown)
return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Unsupported node kind for path '%s'"),
svn_dirent_local_style(local_abspath,
scratch_pool));
if (kind_p)
*kind_p = kind;
{
svn_wc__db_status_t status;
svn_boolean_t conflicted;
svn_boolean_t exists;
svn_error_t *err
= svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
&conflicted,
NULL, NULL, NULL, NULL, NULL, NULL,
db, local_abspath,
scratch_pool, scratch_pool);
if (err)
{
if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
return svn_error_trace(err);
svn_error_clear(err);
exists = FALSE;
is_wc_root = FALSE;
}
else
{
is_wc_root = FALSE;
exists = TRUE;
if (conflicted)
return svn_error_createf(SVN_ERR_WC_FOUND_CONFLICT, NULL,
_("'%s' is an existing item in conflict; "
"please mark the conflict as resolved "
"before adding a new item here"),
svn_dirent_local_style(local_abspath,
scratch_pool));
switch (status)
{
case svn_wc__db_status_not_present:
break;
case svn_wc__db_status_deleted:
SVN_ERR_ASSERT(!is_wc_root);
break;
case svn_wc__db_status_normal:
if (copyfrom_url)
{
SVN_ERR(svn_wc__check_wc_root(&is_wc_root, NULL, NULL,
db, local_abspath,
scratch_pool));
if (is_wc_root)
break;
}
default:
return svn_error_createf(
SVN_ERR_ENTRY_EXISTS, NULL,
_("'%s' is already under version control"),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
}
if (db_row_exists_p)
*db_row_exists_p = exists;
if (is_wc_root_p)
*is_wc_root_p = is_wc_root;
}
return SVN_NO_ERROR;
}
static svn_error_t *
integrate_nested_wc_as_copy(svn_wc_context_t *wc_ctx,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_t *db = wc_ctx->db;
const char *moved_abspath;
SVN_ERR(svn_wc__db_drop_root(db, local_abspath, scratch_pool));
{
const char *tmpdir_abspath;
const char *moved_adm_abspath;
const char *adm_abspath;
SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmpdir_abspath, db,
svn_dirent_dirname(local_abspath,
scratch_pool),
scratch_pool, scratch_pool));
SVN_ERR(svn_io_open_unique_file3(NULL, &moved_abspath, tmpdir_abspath,
svn_io_file_del_on_close,
scratch_pool, scratch_pool));
SVN_ERR(svn_io_dir_make(moved_abspath, APR_OS_DEFAULT, scratch_pool));
adm_abspath = svn_wc__adm_child(local_abspath, "", scratch_pool);
moved_adm_abspath = svn_wc__adm_child(moved_abspath, "", scratch_pool);
SVN_ERR(svn_io_file_move(adm_abspath, moved_adm_abspath, scratch_pool));
}
SVN_ERR(svn_wc_copy3(wc_ctx, moved_abspath, local_abspath,
TRUE ,
NULL, NULL, NULL, NULL, scratch_pool));
SVN_ERR(svn_wc__db_drop_root(db, moved_abspath, scratch_pool));
SVN_ERR(svn_io_remove_dir2(moved_abspath, FALSE, NULL, NULL,
scratch_pool));
{
svn_boolean_t owns_lock;
SVN_ERR(svn_wc__db_wclock_owns_lock(&owns_lock, db, local_abspath,
FALSE, scratch_pool));
if (!owns_lock)
SVN_ERR(svn_wc__db_wclock_obtain(db, local_abspath, 0, FALSE,
scratch_pool));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_add4(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_depth_t depth,
const char *copyfrom_url,
svn_revnum_t copyfrom_rev,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
svn_wc__db_t *db = wc_ctx->db;
svn_node_kind_t kind;
svn_boolean_t db_row_exists;
svn_boolean_t is_wc_root;
const char *repos_root_url;
const char *repos_uuid;
SVN_ERR(check_can_add_node(&kind, &db_row_exists, &is_wc_root,
db, local_abspath, copyfrom_url, copyfrom_rev,
scratch_pool));
SVN_ERR(check_can_add_to_parent(&repos_root_url, &repos_uuid,
db, local_abspath, scratch_pool,
scratch_pool));
if (copyfrom_url && !svn_uri__is_ancestor(repos_root_url, copyfrom_url))
return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("The URL '%s' has a different repository "
"root than its parent"), copyfrom_url);
if (is_wc_root)
{
const char *repos_relpath, *inner_repos_root_url, *inner_repos_uuid;
const char *inner_url;
SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath,
&inner_repos_root_url,
&inner_repos_uuid,
db, local_abspath,
scratch_pool, scratch_pool));
if (strcmp(inner_repos_uuid, repos_uuid)
|| strcmp(repos_root_url, inner_repos_root_url))
return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Can't schedule the working copy at '%s' "
"from repository '%s' with uuid '%s' "
"for addition under a working copy from "
"repository '%s' with uuid '%s'."),
svn_dirent_local_style(local_abspath,
scratch_pool),
inner_repos_root_url, inner_repos_uuid,
repos_root_url, repos_uuid);
inner_url = svn_path_url_add_component2(repos_root_url, repos_relpath,
scratch_pool);
if (strcmp(copyfrom_url, inner_url))
return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Can't add '%s' with URL '%s', but with "
"the data from '%s'"),
svn_dirent_local_style(local_abspath,
scratch_pool),
copyfrom_url, inner_url);
}
if (!copyfrom_url)
{
SVN_ERR(add_from_disk(db, local_abspath, kind, notify_func, notify_baton,
scratch_pool));
if (kind == svn_node_dir && !db_row_exists)
{
svn_boolean_t owns_lock;
SVN_ERR(svn_wc__db_wclock_owns_lock(&owns_lock, db, local_abspath,
FALSE, scratch_pool));
if (!owns_lock)
SVN_ERR(svn_wc__db_wclock_obtain(db, local_abspath, 0, FALSE,
scratch_pool));
}
}
else if (!is_wc_root)
{
if (kind == svn_node_file)
{
svn_stream_t *content = svn_stream_empty(scratch_pool);
SVN_ERR(svn_wc_add_repos_file4(wc_ctx, local_abspath,
content, NULL, NULL, NULL,
copyfrom_url, copyfrom_rev,
cancel_func, cancel_baton,
scratch_pool));
}
else
{
const char *repos_relpath =
svn_uri_skip_ancestor(repos_root_url, copyfrom_url, scratch_pool);
SVN_ERR(svn_wc__db_op_copy_dir(db, local_abspath,
apr_hash_make(scratch_pool),
copyfrom_rev, 0, NULL,
repos_relpath,
repos_root_url, repos_uuid,
copyfrom_rev,
NULL , depth,
NULL ,
NULL ,
scratch_pool));
}
}
else
{
SVN_ERR(integrate_nested_wc_as_copy(wc_ctx, local_abspath,
scratch_pool));
}
if (notify_func != NULL)
{
svn_wc_notify_t *notify = svn_wc_create_notify(local_abspath,
svn_wc_notify_add,
scratch_pool);
notify->kind = kind;
(*notify_func)(notify_baton, notify, scratch_pool);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_add_from_disk(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
svn_node_kind_t kind;
SVN_ERR(check_can_add_node(&kind, NULL, NULL, wc_ctx->db, local_abspath,
NULL, SVN_INVALID_REVNUM, scratch_pool));
SVN_ERR(check_can_add_to_parent(NULL, NULL, wc_ctx->db, local_abspath,
scratch_pool, scratch_pool));
SVN_ERR(add_from_disk(wc_ctx->db, local_abspath, kind,
notify_func, notify_baton,
scratch_pool));
if (notify_func != NULL)
{
svn_wc_notify_t *notify = svn_wc_create_notify(local_abspath,
svn_wc_notify_add,
scratch_pool);
notify->kind = kind;
(*notify_func)(notify_baton, notify, scratch_pool);
}
return SVN_NO_ERROR;
}
static svn_error_t *
remove_conflict_file(svn_boolean_t *notify_required,
const char *conflict_abspath,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
if (conflict_abspath)
{
svn_error_t *err = svn_io_remove_file2(conflict_abspath, FALSE,
scratch_pool);
if (err)
svn_error_clear(err);
else
*notify_required = TRUE;
}
return SVN_NO_ERROR;
}
static int
compare_revert_list_copied_children(const void *a, const void *b)
{
const svn_wc__db_revert_list_copied_child_info_t * const *ca = a;
const svn_wc__db_revert_list_copied_child_info_t * const *cb = b;
int i;
i = svn_path_compare_paths(ca[0]->abspath, cb[0]->abspath);
return -i;
}
static svn_error_t *
revert_restore_handle_copied_dirs(svn_boolean_t *removed_self,
svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t remove_self,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
const apr_array_header_t *copied_children;
svn_wc__db_revert_list_copied_child_info_t *child_info;
int i;
svn_node_kind_t on_disk;
apr_pool_t *iterpool;
svn_error_t *err;
if (removed_self)
*removed_self = FALSE;
SVN_ERR(svn_wc__db_revert_list_read_copied_children(&copied_children,
db, local_abspath,
scratch_pool,
scratch_pool));
iterpool = svn_pool_create(scratch_pool);
for (i = 0; i < copied_children->nelts; i++)
{
child_info = APR_ARRAY_IDX(
copied_children, i,
svn_wc__db_revert_list_copied_child_info_t *);
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
if (child_info->kind != svn_wc__db_kind_file)
continue;
svn_pool_clear(iterpool);
SVN_ERR(svn_io_check_path(child_info->abspath, &on_disk, iterpool));
if (on_disk != svn_node_file)
continue;
SVN_ERR(svn_io_remove_file2(child_info->abspath, TRUE, iterpool));
}
qsort(copied_children->elts, copied_children->nelts,
sizeof(svn_wc__db_revert_list_copied_child_info_t *),
compare_revert_list_copied_children);
for (i = 0; i < copied_children->nelts; i++)
{
child_info = APR_ARRAY_IDX(
copied_children, i,
svn_wc__db_revert_list_copied_child_info_t *);
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
if (child_info->kind != svn_wc__db_kind_dir)
continue;
svn_pool_clear(iterpool);
err = svn_io_dir_remove_nonrecursive(child_info->abspath, iterpool);
if (err)
{
if (APR_STATUS_IS_ENOENT(err->apr_err) ||
SVN__APR_STATUS_IS_ENOTDIR(err->apr_err) ||
APR_STATUS_IS_ENOTEMPTY(err->apr_err))
svn_error_clear(err);
else
return svn_error_trace(err);
}
}
if (remove_self)
{
err = svn_io_dir_remove_nonrecursive(local_abspath, iterpool);
if (err)
{
if (APR_STATUS_IS_ENOTEMPTY(err->apr_err))
svn_error_clear(err);
else
return svn_error_trace(err);
}
else if (removed_self)
*removed_self = TRUE;
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
static svn_error_t *
revert_restore(svn_wc__db_t *db,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t use_commit_times,
svn_boolean_t revert_root,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
svn_error_t *err;
svn_wc__db_status_t status;
svn_wc__db_kind_t kind;
svn_node_kind_t on_disk;
svn_boolean_t notify_required;
const char *conflict_old;
const char *conflict_new;
const char *conflict_working;
const char *prop_reject;
svn_filesize_t recorded_size;
apr_time_t recorded_mod_time;
apr_finfo_t finfo;
#ifdef HAVE_SYMLINK
svn_boolean_t special;
#endif
svn_boolean_t copied_here;
svn_wc__db_kind_t reverted_kind;
svn_boolean_t is_wcroot;
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, db, local_abspath, scratch_pool));
if (is_wcroot && !revert_root)
{
if (notify_func)
{
svn_wc_notify_t *notify = svn_wc_create_notify(
local_abspath,
svn_wc_notify_update_skip_obstruction,
scratch_pool);
notify_func(notify_baton, notify, scratch_pool);
}
return SVN_NO_ERROR;
}
SVN_ERR(svn_wc__db_revert_list_read(¬ify_required,
&conflict_old, &conflict_new,
&conflict_working, &prop_reject,
&copied_here, &reverted_kind,
db, local_abspath,
scratch_pool, scratch_pool));
err = svn_wc__db_read_info(&status, &kind,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&recorded_size, &recorded_mod_time, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
db, local_abspath, scratch_pool, scratch_pool);
if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
{
svn_error_clear(err);
if (!copied_here)
{
if (notify_func && notify_required)
notify_func(notify_baton,
svn_wc_create_notify(local_abspath,
svn_wc_notify_revert,
scratch_pool),
scratch_pool);
if (notify_func)
SVN_ERR(svn_wc__db_revert_list_notify(notify_func, notify_baton,
db, local_abspath,
scratch_pool));
return SVN_NO_ERROR;
}
else
{
status = svn_wc__db_status_normal;
kind = svn_wc__db_kind_unknown;
recorded_size = SVN_INVALID_FILESIZE;
recorded_mod_time = 0;
}
}
else if (err)
return svn_error_trace(err);
err = svn_io_stat(&finfo, local_abspath,
APR_FINFO_TYPE | APR_FINFO_LINK
| APR_FINFO_SIZE | APR_FINFO_MTIME
| SVN__APR_FINFO_EXECUTABLE
| SVN__APR_FINFO_READONLY,
scratch_pool);
if (err && (APR_STATUS_IS_ENOENT(err->apr_err)
|| SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)))
{
svn_error_clear(err);
on_disk = svn_node_none;
#ifdef HAVE_SYMLINK
special = FALSE;
#endif
}
else
{
if (finfo.filetype == APR_REG || finfo.filetype == APR_LNK)
on_disk = svn_node_file;
else if (finfo.filetype == APR_DIR)
on_disk = svn_node_dir;
else
on_disk = svn_node_unknown;
#ifdef HAVE_SYMLINK
special = (finfo.filetype == APR_LNK);
#endif
}
if (copied_here)
{
if (reverted_kind == svn_wc__db_kind_file && on_disk == svn_node_file)
{
SVN_ERR(svn_io_remove_file2(local_abspath, TRUE, scratch_pool));
on_disk = svn_node_none;
}
else if (reverted_kind == svn_wc__db_kind_dir && on_disk == svn_node_dir)
{
svn_boolean_t removed;
SVN_ERR(revert_restore_handle_copied_dirs(&removed, db,
local_abspath, TRUE,
cancel_func, cancel_baton,
scratch_pool));
if (removed)
on_disk = svn_node_none;
}
}
if (on_disk != svn_node_none
&& status != svn_wc__db_status_server_excluded
&& status != svn_wc__db_status_deleted
&& status != svn_wc__db_status_excluded
&& status != svn_wc__db_status_not_present)
{
if (on_disk == svn_node_dir && kind != svn_wc__db_kind_dir)
{
SVN_ERR(svn_io_remove_dir2(local_abspath, FALSE,
cancel_func, cancel_baton, scratch_pool));
on_disk = svn_node_none;
}
else if (on_disk == svn_node_file && kind != svn_wc__db_kind_file)
{
#ifdef HAVE_SYMLINK
if (!(special && kind == svn_wc__db_kind_dir))
#endif
{
SVN_ERR(svn_io_remove_file2(local_abspath, FALSE, scratch_pool));
on_disk = svn_node_none;
}
}
else if (on_disk == svn_node_file)
{
svn_boolean_t modified;
apr_hash_t *props;
#ifdef HAVE_SYMLINK
svn_string_t *special_prop;
#endif
SVN_ERR(svn_wc__db_read_pristine_props(&props, db, local_abspath,
scratch_pool, scratch_pool));
#ifdef HAVE_SYMLINK
special_prop = apr_hash_get(props, SVN_PROP_SPECIAL,
APR_HASH_KEY_STRING);
if ((special_prop != NULL) != special)
{
SVN_ERR(svn_io_remove_file2(local_abspath, FALSE, scratch_pool));
on_disk = svn_node_none;
}
else
#endif
{
if (recorded_size != SVN_INVALID_FILESIZE
&& recorded_mod_time != 0
&& recorded_size == finfo.size
&& recorded_mod_time == finfo.mtime)
{
modified = FALSE;
}
else
SVN_ERR(svn_wc__internal_file_modified_p(&modified,
db, local_abspath,
TRUE, scratch_pool));
if (modified)
{
SVN_ERR(svn_io_remove_file2(local_abspath, FALSE,
scratch_pool));
on_disk = svn_node_none;
}
else
{
svn_boolean_t read_only;
svn_string_t *needs_lock_prop;
SVN_ERR(svn_io__is_finfo_read_only(&read_only, &finfo,
scratch_pool));
needs_lock_prop = apr_hash_get(props, SVN_PROP_NEEDS_LOCK,
APR_HASH_KEY_STRING);
if (needs_lock_prop && !read_only)
{
SVN_ERR(svn_io_set_file_read_only(local_abspath,
FALSE, scratch_pool));
notify_required = TRUE;
}
else if (!needs_lock_prop && read_only)
{
SVN_ERR(svn_io_set_file_read_write(local_abspath,
FALSE, scratch_pool));
notify_required = TRUE;
}
#if !defined(WIN32) && !defined(__OS2__)
#ifdef HAVE_SYMLINK
if (!special)
#endif
{
svn_boolean_t executable;
svn_string_t *executable_prop;
SVN_ERR(svn_io__is_finfo_executable(&executable, &finfo,
scratch_pool));
executable_prop = apr_hash_get(props, SVN_PROP_EXECUTABLE,
APR_HASH_KEY_STRING);
if (executable_prop && !executable)
{
SVN_ERR(svn_io_set_file_executable(local_abspath,
TRUE, FALSE,
scratch_pool));
notify_required = TRUE;
}
else if (!executable_prop && executable)
{
SVN_ERR(svn_io_set_file_executable(local_abspath,
FALSE, FALSE,
scratch_pool));
notify_required = TRUE;
}
}
#endif
}
}
}
}
if (on_disk == svn_node_none
&& status != svn_wc__db_status_server_excluded
&& status != svn_wc__db_status_deleted
&& status != svn_wc__db_status_excluded
&& status != svn_wc__db_status_not_present)
{
if (kind == svn_wc__db_kind_dir)
SVN_ERR(svn_io_dir_make(local_abspath, APR_OS_DEFAULT, scratch_pool));
if (kind == svn_wc__db_kind_file)
{
svn_skel_t *work_item;
SVN_ERR(svn_wc__wq_build_file_install(&work_item, db, local_abspath,
NULL, use_commit_times, TRUE,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item,
scratch_pool));
SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
scratch_pool));
}
notify_required = TRUE;
}
SVN_ERR(remove_conflict_file(¬ify_required, conflict_old,
local_abspath, scratch_pool));
SVN_ERR(remove_conflict_file(¬ify_required, conflict_new,
local_abspath, scratch_pool));
SVN_ERR(remove_conflict_file(¬ify_required, conflict_working,
local_abspath, scratch_pool));
SVN_ERR(remove_conflict_file(¬ify_required, prop_reject,
local_abspath, scratch_pool));
if (notify_func && notify_required)
notify_func(notify_baton,
svn_wc_create_notify(local_abspath, svn_wc_notify_revert,
scratch_pool),
scratch_pool);
if (depth == svn_depth_infinity && kind == svn_wc__db_kind_dir)
{
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
const apr_array_header_t *children;
int i;
SVN_ERR(revert_restore_handle_copied_dirs(NULL, db, local_abspath, FALSE,
cancel_func, cancel_baton,
iterpool));
SVN_ERR(svn_wc__db_read_children_of_working_node(&children, db,
local_abspath,
scratch_pool,
iterpool));
for (i = 0; i < children->nelts; ++i)
{
const char *child_abspath;
svn_pool_clear(iterpool);
child_abspath = svn_dirent_join(local_abspath,
APR_ARRAY_IDX(children, i,
const char *),
iterpool);
SVN_ERR(revert_restore(db, child_abspath, depth,
use_commit_times, FALSE ,
cancel_func, cancel_baton,
notify_func, notify_baton,
iterpool));
}
svn_pool_destroy(iterpool);
}
if (notify_func)
SVN_ERR(svn_wc__db_revert_list_notify(notify_func, notify_baton,
db, local_abspath, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
new_revert_internal(svn_wc__db_t *db,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t use_commit_times,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
svn_error_t *err;
SVN_ERR_ASSERT(depth == svn_depth_empty || depth == svn_depth_infinity);
{
const char *dir_abspath;
SVN_ERR(svn_wc__db_get_wcroot(&dir_abspath, db, local_abspath,
scratch_pool, scratch_pool));
if (svn_dirent_is_child(dir_abspath, local_abspath, NULL))
dir_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
SVN_ERR(svn_wc__write_check(db, dir_abspath, scratch_pool));
}
err = svn_wc__db_op_revert(db, local_abspath, depth,
scratch_pool, scratch_pool);
if (!err)
err = revert_restore(db, local_abspath, depth,
use_commit_times, TRUE ,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool);
err = svn_error_compose_create(err,
svn_wc__db_revert_list_done(db,
local_abspath,
scratch_pool));
return err;
}
static svn_error_t *
new_revert_changelist(svn_wc__db_t *db,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t use_commit_times,
apr_hash_t *changelist_hash,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
apr_pool_t *iterpool;
const apr_array_header_t *children;
int i;
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
if (svn_wc__internal_changelist_match(db, local_abspath, changelist_hash,
scratch_pool))
SVN_ERR(new_revert_internal(db, local_abspath,
svn_depth_empty, use_commit_times,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool));
if (depth == svn_depth_empty)
return SVN_NO_ERROR;
iterpool = svn_pool_create(scratch_pool);
if (depth == svn_depth_files || depth == svn_depth_immediates)
depth = svn_depth_empty;
SVN_ERR(svn_wc__db_read_children_of_working_node(&children, db,
local_abspath,
scratch_pool,
iterpool));
for (i = 0; i < children->nelts; ++i)
{
const char *child_abspath;
svn_pool_clear(iterpool);
child_abspath = svn_dirent_join(local_abspath,
APR_ARRAY_IDX(children, i,
const char *),
iterpool);
SVN_ERR(new_revert_changelist(db, child_abspath, depth,
use_commit_times, changelist_hash,
cancel_func, cancel_baton,
notify_func, notify_baton,
iterpool));
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
static svn_error_t *
new_revert_partial(svn_wc__db_t *db,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t use_commit_times,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
apr_pool_t *iterpool;
const apr_array_header_t *children;
int i;
SVN_ERR_ASSERT(depth == svn_depth_files || depth == svn_depth_immediates);
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
iterpool = svn_pool_create(scratch_pool);
SVN_ERR(new_revert_internal(db, local_abspath, svn_depth_empty,
use_commit_times, cancel_func, cancel_baton,
notify_func, notify_baton, iterpool));
SVN_ERR(svn_wc__db_read_children_of_working_node(&children, db,
local_abspath,
scratch_pool,
iterpool));
for (i = 0; i < children->nelts; ++i)
{
const char *child_abspath;
svn_pool_clear(iterpool);
child_abspath = svn_dirent_join(local_abspath,
APR_ARRAY_IDX(children, i, const char *),
iterpool);
if (depth == svn_depth_files)
{
svn_wc__db_kind_t kind;
SVN_ERR(svn_wc__db_read_kind(&kind, db, child_abspath, TRUE,
iterpool));
if (kind != svn_wc__db_kind_file)
continue;
}
SVN_ERR(new_revert_internal(db, child_abspath,
svn_depth_empty, use_commit_times,
cancel_func, cancel_baton,
notify_func, notify_baton,
iterpool));
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_revert4(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t use_commit_times,
const apr_array_header_t *changelist_filter,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
if (changelist_filter && changelist_filter->nelts)
{
apr_hash_t *changelist_hash;
SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
scratch_pool));
return svn_error_trace(new_revert_changelist(wc_ctx->db, local_abspath,
depth, use_commit_times,
changelist_hash,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool));
}
if (depth == svn_depth_empty || depth == svn_depth_infinity)
return svn_error_trace(new_revert_internal(wc_ctx->db, local_abspath,
depth, use_commit_times,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool));
if (depth == svn_depth_files || depth == svn_depth_immediates)
return svn_error_trace(new_revert_partial(wc_ctx->db, local_abspath,
depth, use_commit_times,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool));
return svn_error_create(SVN_ERR_WC_INVALID_OPERATION_DEPTH, NULL, NULL);
}
static const char *
nonexistent_path(const char *wcroot_abspath, apr_pool_t *scratch_pool)
{
return svn_wc__adm_child(wcroot_abspath, SVN_WC__ADM_NONEXISTENT_PATH,
scratch_pool);
}
svn_error_t *
svn_wc_get_pristine_copy_path(const char *path,
const char **pristine_path,
apr_pool_t *pool)
{
svn_wc__db_t *db;
const char *local_abspath;
svn_error_t *err;
SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
SVN_ERR(svn_wc__db_open(&db, NULL, TRUE, TRUE, pool, pool));
err = svn_wc__text_base_path_to_read(pristine_path, db, local_abspath,
pool, pool);
if (err && err->apr_err == SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
{
const char *wcroot_abspath;
svn_error_clear(err);
err = svn_wc__db_get_wcroot(&wcroot_abspath, db, local_abspath,
pool, pool);
if (err == NULL)
*pristine_path = nonexistent_path(wcroot_abspath, pool);
}
return svn_error_compose_create(err, svn_wc__db_close(db));
}
svn_error_t *
svn_wc_get_pristine_contents2(svn_stream_t **contents,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
return svn_error_trace(svn_wc__get_pristine_contents(contents, NULL,
wc_ctx->db,
local_abspath,
result_pool,
scratch_pool));
}
svn_error_t *
svn_wc__internal_remove_from_revision_control(svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t destroy_wf,
svn_boolean_t instant_error,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_error_t *err;
svn_boolean_t left_something = FALSE;
svn_wc__db_status_t status;
svn_wc__db_kind_t kind;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
db, local_abspath, scratch_pool, scratch_pool));
if (kind == svn_wc__db_kind_file || kind == svn_wc__db_kind_symlink)
{
svn_boolean_t text_modified_p = FALSE;
if (instant_error || destroy_wf)
{
svn_node_kind_t on_disk;
SVN_ERR(svn_io_check_path(local_abspath, &on_disk, scratch_pool));
if (on_disk == svn_node_file)
{
SVN_ERR(svn_wc__internal_file_modified_p(&text_modified_p, db,
local_abspath, FALSE,
scratch_pool));
if (text_modified_p && instant_error)
return svn_error_createf(SVN_ERR_WC_LEFT_LOCAL_MOD, NULL,
_("File '%s' has local modifications"),
svn_dirent_local_style(local_abspath, scratch_pool));
}
}
SVN_ERR(svn_wc__db_op_remove_node(db, local_abspath,
SVN_INVALID_REVNUM,
svn_wc__db_kind_unknown,
scratch_pool));
if (destroy_wf)
{
if (text_modified_p)
return svn_error_create(SVN_ERR_WC_LEFT_LOCAL_MOD, NULL, NULL);
else
SVN_ERR(svn_io_remove_file2(local_abspath, TRUE, scratch_pool));
}
}
else
{
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
const apr_array_header_t *children;
int i;
SVN_ERR(svn_wc__db_read_children(&children, db, local_abspath,
scratch_pool, iterpool));
for (i = 0; i < children->nelts; i++)
{
const char *node_name = APR_ARRAY_IDX(children, i, const char*);
const char *node_abspath;
svn_wc__db_status_t node_status;
svn_wc__db_kind_t node_kind;
svn_pool_clear(iterpool);
node_abspath = svn_dirent_join(local_abspath, node_name, iterpool);
SVN_ERR(svn_wc__db_read_info(&node_status, &node_kind, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
db, node_abspath,
iterpool, iterpool));
if (node_status == svn_wc__db_status_normal
&& node_kind == svn_wc__db_kind_dir)
{
svn_boolean_t is_root;
SVN_ERR(svn_wc__check_wc_root(&is_root, NULL, NULL,
db, node_abspath, iterpool));
if (is_root)
continue;
}
if (node_status != svn_wc__db_status_normal
&& node_status != svn_wc__db_status_added
&& node_status != svn_wc__db_status_incomplete)
{
SVN_ERR(svn_wc__db_op_remove_node(db, node_abspath,
SVN_INVALID_REVNUM,
svn_wc__db_kind_unknown,
iterpool));
continue;
}
err = svn_wc__internal_remove_from_revision_control(
db, node_abspath,
destroy_wf, instant_error,
cancel_func, cancel_baton,
iterpool);
if (err && (err->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD))
{
if (instant_error)
return svn_error_trace(err);
else
{
svn_error_clear(err);
left_something = TRUE;
}
}
else if (err)
return svn_error_trace(err);
}
{
svn_boolean_t is_root;
SVN_ERR(svn_wc__check_wc_root(&is_root, NULL, NULL,
db, local_abspath, iterpool));
if (! is_root)
{
SVN_ERR(svn_wc__db_op_remove_node(db, local_abspath,
SVN_INVALID_REVNUM,
svn_wc__db_kind_unknown,
iterpool));
}
else
{
SVN_ERR(svn_wc__adm_destroy(db, local_abspath,
cancel_func, cancel_baton, iterpool));
}
}
if (destroy_wf && (! left_something))
{
err = svn_io_dir_remove_nonrecursive(local_abspath, iterpool);
if (err)
{
if (!APR_STATUS_IS_ENOENT(err->apr_err))
left_something = TRUE;
svn_error_clear(err);
}
}
svn_pool_destroy(iterpool);
}
if (left_something)
return svn_error_create(SVN_ERR_WC_LEFT_LOCAL_MOD, NULL, NULL);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_remove_from_revision_control2(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_boolean_t destroy_wf,
svn_boolean_t instant_error,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
return svn_error_trace(
svn_wc__internal_remove_from_revision_control(wc_ctx->db,
local_abspath,
destroy_wf,
instant_error,
cancel_func,
cancel_baton,
scratch_pool));
}
svn_error_t *
svn_wc_add_lock2(svn_wc_context_t *wc_ctx,
const char *local_abspath,
const svn_lock_t *lock,
apr_pool_t *scratch_pool)
{
svn_wc__db_lock_t db_lock;
svn_error_t *err;
const svn_string_t *needs_lock;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
db_lock.token = lock->token;
db_lock.owner = lock->owner;
db_lock.comment = lock->comment;
db_lock.date = lock->creation_date;
err = svn_wc__db_lock_add(wc_ctx->db, local_abspath, &db_lock, scratch_pool);
if (err)
{
if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
return svn_error_trace(err);
svn_error_clear(err);
return svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, NULL,
_("'%s' is not under version control"),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
SVN_ERR(svn_wc__internal_propget(&needs_lock, wc_ctx->db, local_abspath,
SVN_PROP_NEEDS_LOCK, scratch_pool,
scratch_pool));
if (needs_lock)
SVN_ERR(svn_io_set_file_read_write(local_abspath, FALSE, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_remove_lock2(svn_wc_context_t *wc_ctx,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_error_t *err;
const svn_string_t *needs_lock;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
err = svn_wc__db_lock_remove(wc_ctx->db, local_abspath, scratch_pool);
if (err)
{
if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
return svn_error_trace(err);
svn_error_clear(err);
return svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, NULL,
_("'%s' is not under version control"),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
SVN_ERR(svn_wc__internal_propget(&needs_lock, wc_ctx->db, local_abspath,
SVN_PROP_NEEDS_LOCK, scratch_pool,
scratch_pool));
if (needs_lock)
SVN_ERR(svn_io_set_file_read_only(local_abspath, FALSE, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_set_changelist2(svn_wc_context_t *wc_ctx,
const char *local_abspath,
const char *new_changelist,
svn_depth_t depth,
const apr_array_header_t *changelist_filter,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
SVN_ERR_ASSERT(! (new_changelist && new_changelist[0] == '\0'));
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_op_set_changelist(wc_ctx->db, local_abspath,
new_changelist, changelist_filter,
depth, notify_func, notify_baton,
cancel_func, cancel_baton,
scratch_pool));
return SVN_NO_ERROR;
}
struct get_cl_fn_baton
{
svn_wc__db_t *db;
apr_hash_t *clhash;
svn_changelist_receiver_t callback_func;
void *callback_baton;
};
static svn_error_t *
get_node_changelist(const char *local_abspath,
svn_node_kind_t kind,
void *baton,
apr_pool_t *scratch_pool)
{
struct get_cl_fn_baton *b = baton;
const char *changelist;
SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, &changelist,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
b->db, local_abspath,
scratch_pool, scratch_pool));
if (svn_wc__internal_changelist_match(b->db, local_abspath, b->clhash,
scratch_pool))
SVN_ERR(b->callback_func(b->callback_baton, local_abspath,
changelist, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_get_changelists(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_depth_t depth,
const apr_array_header_t *changelist_filter,
svn_changelist_receiver_t callback_func,
void *callback_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
struct get_cl_fn_baton gnb;
gnb.db = wc_ctx->db;
gnb.clhash = NULL;
gnb.callback_func = callback_func;
gnb.callback_baton = callback_baton;
if (changelist_filter)
SVN_ERR(svn_hash_from_cstring_keys(&gnb.clhash, changelist_filter,
scratch_pool));
return svn_error_trace(
svn_wc__internal_walk_children(wc_ctx->db, local_abspath, FALSE,
changelist_filter, get_node_changelist,
&gnb, depth,
cancel_func, cancel_baton,
scratch_pool));
}
svn_boolean_t
svn_wc__internal_changelist_match(svn_wc__db_t *db,
const char *local_abspath,
const apr_hash_t *clhash,
apr_pool_t *scratch_pool)
{
svn_error_t *err;
const char *changelist;
if (clhash == NULL)
return TRUE;
err = svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, &changelist,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
db, local_abspath, scratch_pool, scratch_pool);
if (err)
{
svn_error_clear(err);
return FALSE;
}
return (changelist
&& apr_hash_get((apr_hash_t *)clhash, changelist,
APR_HASH_KEY_STRING) != NULL);
}
svn_boolean_t
svn_wc__changelist_match(svn_wc_context_t *wc_ctx,
const char *local_abspath,
const apr_hash_t *clhash,
apr_pool_t *scratch_pool)
{
return svn_wc__internal_changelist_match(wc_ctx->db, local_abspath, clhash,
scratch_pool);
}