#define SVN_WC__I_AM_WC_DB
#include <assert.h>
#include <apr_pools.h>
#include <apr_hash.h>
#include "svn_private_config.h"
#include "svn_types.h"
#include "svn_error.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_hash.h"
#include "svn_sorts.h"
#include "svn_wc.h"
#include "svn_checksum.h"
#include "svn_pools.h"
#include "wc.h"
#include "wc_db.h"
#include "adm_files.h"
#include "wc-queries.h"
#include "entries.h"
#include "lock.h"
#include "conflicts.h"
#include "wc_db_private.h"
#include "workqueue.h"
#include "token-map.h"
#include "private/svn_sorts_private.h"
#include "private/svn_sqlite.h"
#include "private/svn_skel.h"
#include "private/svn_wc_private.h"
#include "private/svn_token.h"
#define NOT_IMPLEMENTED() SVN__NOT_IMPLEMENTED()
#define SDB_FILE "wc.db"
#define WCROOT_TEMPDIR_RELPATH "tmp"
#define INVALID_REPOS_ID ((apr_int64_t) -1)
#define UNKNOWN_WC_ID ((apr_int64_t) -1)
#define FORMAT_FROM_SDB (-1)
#define SQLITE_PROPERTIES_AVAILABLE(stmt, i) \
(svn_sqlite__column_bytes(stmt, i) > 2)
int
svn_wc__db_op_depth_for_upgrade(const char *local_relpath)
{
return relpath_depth(local_relpath);
}
typedef struct insert_base_baton_t {
svn_wc__db_status_t status;
svn_node_kind_t kind;
apr_int64_t repos_id;
const char *repos_relpath;
svn_revnum_t revision;
const char *repos_root_url;
const char *repos_uuid;
const apr_hash_t *props;
svn_revnum_t changed_rev;
apr_time_t changed_date;
const char *changed_author;
const apr_hash_t *dav_cache;
const apr_array_header_t *children;
svn_depth_t depth;
const svn_checksum_t *checksum;
const char *target;
svn_boolean_t file_external;
const svn_skel_t *conflict;
svn_boolean_t update_actual_props;
const apr_hash_t *new_actual_props;
apr_array_header_t *iprops;
svn_boolean_t keep_recorded_info;
svn_boolean_t insert_base_deleted;
svn_boolean_t delete_working;
const svn_skel_t *work_items;
} insert_base_baton_t;
typedef struct insert_working_baton_t {
svn_wc__db_status_t presence;
svn_node_kind_t kind;
int op_depth;
const apr_hash_t *props;
svn_revnum_t changed_rev;
apr_time_t changed_date;
const char *changed_author;
apr_int64_t original_repos_id;
const char *original_repos_relpath;
svn_revnum_t original_revnum;
svn_boolean_t moved_here;
const apr_array_header_t *children;
svn_depth_t depth;
const svn_checksum_t *checksum;
const char *target;
svn_boolean_t update_actual_props;
const apr_hash_t *new_actual_props;
const svn_skel_t *work_items;
const svn_skel_t *conflict;
int not_present_op_depth;
} insert_working_baton_t;
typedef struct insert_external_baton_t {
svn_node_kind_t kind;
svn_wc__db_status_t presence;
apr_int64_t repos_id;
const char *repos_relpath;
svn_revnum_t revision;
const char *repos_root_url;
const char *repos_uuid;
const apr_hash_t *props;
apr_array_header_t *iprops;
svn_revnum_t changed_rev;
apr_time_t changed_date;
const char *changed_author;
const apr_hash_t *dav_cache;
const svn_checksum_t *checksum;
const char *target;
const char *record_ancestor_relpath;
const char *recorded_repos_relpath;
svn_revnum_t recorded_peg_revision;
svn_revnum_t recorded_revision;
const svn_skel_t *conflict;
svn_boolean_t update_actual_props;
const apr_hash_t *new_actual_props;
svn_boolean_t keep_recorded_info;
const svn_skel_t *work_items;
} insert_external_baton_t;
static svn_error_t *
add_work_items(svn_sqlite__db_t *sdb,
const svn_skel_t *skel,
apr_pool_t *scratch_pool);
static svn_error_t *
set_actual_props(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_hash_t *props,
apr_pool_t *scratch_pool);
static svn_error_t *
insert_incomplete_children(svn_sqlite__db_t *sdb,
apr_int64_t wc_id,
const char *local_relpath,
apr_int64_t repos_id,
const char *repos_relpath,
svn_revnum_t revision,
const apr_array_header_t *children,
int op_depth,
apr_pool_t *scratch_pool);
static svn_error_t *
db_read_pristine_props(apr_hash_t **props,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_boolean_t deleted_ok,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
static svn_error_t *
read_info(svn_wc__db_status_t *status,
svn_node_kind_t *kind,
svn_revnum_t *revision,
const char **repos_relpath,
apr_int64_t *repos_id,
svn_revnum_t *changed_rev,
apr_time_t *changed_date,
const char **changed_author,
svn_depth_t *depth,
const svn_checksum_t **checksum,
const char **target,
const char **original_repos_relpath,
apr_int64_t *original_repos_id,
svn_revnum_t *original_revision,
svn_wc__db_lock_t **lock,
svn_filesize_t *recorded_size,
apr_time_t *recorded_time,
const char **changelist,
svn_boolean_t *conflicted,
svn_boolean_t *op_root,
svn_boolean_t *had_props,
svn_boolean_t *props_mod,
svn_boolean_t *have_base,
svn_boolean_t *have_more_work,
svn_boolean_t *have_work,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
static svn_error_t *
scan_addition(svn_wc__db_status_t *status,
const char **op_root_relpath,
const char **repos_relpath,
apr_int64_t *repos_id,
const char **original_repos_relpath,
apr_int64_t *original_repos_id,
svn_revnum_t *original_revision,
const char **moved_from_relpath,
const char **moved_from_op_root_relpath,
int *moved_from_op_depth,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
static svn_error_t *
convert_to_working_status(svn_wc__db_status_t *working_status,
svn_wc__db_status_t status);
static svn_error_t *
db_is_switched(svn_boolean_t *is_switched,
svn_node_kind_t *kind,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool);
static const char *
path_for_error_message(const svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool)
{
const char *local_abspath
= svn_dirent_join(wcroot->abspath, local_relpath, result_pool);
return svn_dirent_local_style(local_abspath, result_pool);
}
static svn_filesize_t
get_recorded_size(svn_sqlite__stmt_t *stmt, int slot)
{
if (svn_sqlite__column_is_null(stmt, slot))
return SVN_INVALID_FILESIZE;
return svn_sqlite__column_int64(stmt, slot);
}
static svn_wc__db_lock_t *
lock_from_columns(svn_sqlite__stmt_t *stmt,
int col_token,
int col_owner,
int col_comment,
int col_date,
apr_pool_t *result_pool)
{
svn_wc__db_lock_t *lock;
if (svn_sqlite__column_is_null(stmt, col_token))
{
lock = NULL;
}
else
{
lock = apr_pcalloc(result_pool, sizeof(svn_wc__db_lock_t));
lock->token = svn_sqlite__column_text(stmt, col_token, result_pool);
lock->owner = svn_sqlite__column_text(stmt, col_owner, result_pool);
lock->comment = svn_sqlite__column_text(stmt, col_comment, result_pool);
lock->date = svn_sqlite__column_int64(stmt, col_date);
}
return lock;
}
svn_error_t *
svn_wc__db_fetch_repos_info(const char **repos_root_url,
const char **repos_uuid,
svn_wc__db_wcroot_t *wcroot,
apr_int64_t repos_id,
apr_pool_t *result_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
if (!repos_root_url && !repos_uuid)
return SVN_NO_ERROR;
if (repos_id == INVALID_REPOS_ID)
{
if (repos_root_url)
*repos_root_url = NULL;
if (repos_uuid)
*repos_uuid = NULL;
return SVN_NO_ERROR;
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_REPOSITORY_BY_ID));
SVN_ERR(svn_sqlite__bindf(stmt, "i", repos_id));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
return svn_error_createf(SVN_ERR_WC_CORRUPT, svn_sqlite__reset(stmt),
_("No REPOSITORY table entry for id '%ld'"),
(long int)repos_id);
if (repos_root_url)
*repos_root_url = svn_sqlite__column_text(stmt, 0, result_pool);
if (repos_uuid)
*repos_uuid = svn_sqlite__column_text(stmt, 1, result_pool);
return svn_error_trace(svn_sqlite__reset(stmt));
}
static void
repos_location_from_columns(apr_int64_t *repos_id,
svn_revnum_t *revision,
const char **repos_relpath,
svn_sqlite__stmt_t *stmt,
int col_repos_id,
int col_revision,
int col_repos_relpath,
apr_pool_t *result_pool)
{
if (repos_id)
{
if (svn_sqlite__column_is_null(stmt, col_repos_id))
*repos_id = INVALID_REPOS_ID;
else
*repos_id = svn_sqlite__column_int64(stmt, col_repos_id);
}
if (revision)
{
*revision = svn_sqlite__column_revnum(stmt, col_revision);
}
if (repos_relpath)
{
*repos_relpath = svn_sqlite__column_text(stmt, col_repos_relpath,
result_pool);
}
}
static svn_error_t *
create_repos_id(apr_int64_t *repos_id,
const char *repos_root_url,
const char *repos_uuid,
svn_sqlite__db_t *sdb,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *get_stmt;
svn_sqlite__stmt_t *insert_stmt;
svn_boolean_t have_row;
SVN_ERR(svn_sqlite__get_statement(&get_stmt, sdb, STMT_SELECT_REPOSITORY));
SVN_ERR(svn_sqlite__bindf(get_stmt, "s", repos_root_url));
SVN_ERR(svn_sqlite__step(&have_row, get_stmt));
if (have_row)
{
*repos_id = svn_sqlite__column_int64(get_stmt, 0);
return svn_error_trace(svn_sqlite__reset(get_stmt));
}
SVN_ERR(svn_sqlite__reset(get_stmt));
SVN_ERR(svn_sqlite__get_statement(&insert_stmt, sdb,
STMT_INSERT_REPOSITORY));
SVN_ERR(svn_sqlite__bindf(insert_stmt, "ss", repos_root_url, repos_uuid));
return svn_error_trace(svn_sqlite__insert(repos_id, insert_stmt));
}
static void
blank_ibb(insert_base_baton_t *pibb)
{
memset(pibb, 0, sizeof(*pibb));
pibb->revision = SVN_INVALID_REVNUM;
pibb->changed_rev = SVN_INVALID_REVNUM;
pibb->depth = svn_depth_infinity;
pibb->repos_id = INVALID_REPOS_ID;
}
static svn_error_t *
db_extend_parent_delete(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_node_kind_t kind,
int op_depth,
apr_pool_t *scratch_pool)
{
svn_boolean_t have_row;
svn_sqlite__stmt_t *stmt;
int parent_op_depth;
const char *parent_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
SVN_ERR_ASSERT(local_relpath[0]);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_LOWEST_WORKING_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, parent_relpath,
op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
parent_op_depth = svn_sqlite__column_int(stmt, 0);
SVN_ERR(svn_sqlite__reset(stmt));
if (have_row)
{
int existing_op_depth;
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
existing_op_depth = svn_sqlite__column_int(stmt, 0);
SVN_ERR(svn_sqlite__reset(stmt));
if (!have_row || parent_op_depth < existing_op_depth)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_INSTALL_WORKING_NODE_FOR_DELETE));
SVN_ERR(svn_sqlite__bindf(stmt, "isdst", wcroot->wc_id,
local_relpath, parent_op_depth,
parent_relpath, kind_map, kind));
SVN_ERR(svn_sqlite__update(NULL, stmt));
}
}
return SVN_NO_ERROR;
}
static svn_error_t *
db_retract_parent_delete(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
int op_depth,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
int working_depth;
svn_wc__db_status_t presence;
const char *moved_to;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_LOWEST_WORKING_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
return svn_error_trace(svn_sqlite__reset(stmt));
working_depth = svn_sqlite__column_int(stmt, 0);
presence = svn_sqlite__column_token(stmt, 1, presence_map);
moved_to = svn_sqlite__column_text(stmt, 3, scratch_pool);
SVN_ERR(svn_sqlite__reset(stmt));
if (moved_to)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_CLEAR_MOVED_HERE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
moved_to, relpath_depth(moved_to)));
SVN_ERR(svn_sqlite__step_done(stmt));
}
if (presence == svn_wc__db_status_base_deleted)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_DELETE_NODE));
}
else if (moved_to)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_CLEAR_MOVED_TO_RELPATH));
}
else
{
return SVN_NO_ERROR;
}
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
working_depth));
return svn_error_trace(svn_sqlite__update(NULL, stmt));
}
static svn_error_t *
insert_base_node(const insert_base_baton_t *pibb,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
apr_int64_t repos_id = pibb->repos_id;
svn_sqlite__stmt_t *stmt;
svn_filesize_t recorded_size = SVN_INVALID_FILESIZE;
apr_int64_t recorded_time;
svn_boolean_t present;
const char *parent_relpath =
(*local_relpath == '\0') ? NULL
: svn_relpath_dirname(local_relpath, scratch_pool);
if (pibb->repos_id == INVALID_REPOS_ID)
SVN_ERR(create_repos_id(&repos_id, pibb->repos_root_url, pibb->repos_uuid,
wcroot->sdb, scratch_pool));
SVN_ERR_ASSERT(repos_id != INVALID_REPOS_ID);
SVN_ERR_ASSERT(pibb->repos_relpath != NULL);
if (pibb->keep_recorded_info)
{
svn_boolean_t have_row;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_BASE_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
recorded_size = get_recorded_size(stmt, 6);
recorded_time = svn_sqlite__column_int64(stmt, 12);
}
SVN_ERR(svn_sqlite__reset(stmt));
}
present = (pibb->status == svn_wc__db_status_normal
|| pibb->status == svn_wc__db_status_incomplete);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "isdsisr"
"tstr"
"isnnnnns",
wcroot->wc_id,
local_relpath,
0,
parent_relpath,
repos_id,
pibb->repos_relpath,
pibb->revision,
presence_map, pibb->status,
(pibb->kind == svn_node_dir && present)
? svn_token__to_word(depth_map, pibb->depth)
: NULL,
kind_map, pibb->kind,
pibb->changed_rev,
pibb->changed_date,
pibb->changed_author,
(pibb->kind == svn_node_symlink && present) ?
pibb->target : NULL));
if (pibb->kind == svn_node_file && present)
{
if (!pibb->checksum
&& pibb->status != svn_wc__db_status_not_present
&& pibb->status != svn_wc__db_status_excluded
&& pibb->status != svn_wc__db_status_server_excluded)
return svn_error_createf(SVN_ERR_WC_CORRUPT, svn_sqlite__reset(stmt),
_("The file '%s' has no checksum."),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, pibb->checksum,
scratch_pool));
if (recorded_size != SVN_INVALID_FILESIZE)
{
SVN_ERR(svn_sqlite__bind_int64(stmt, 16, recorded_size));
SVN_ERR(svn_sqlite__bind_int64(stmt, 17, recorded_time));
}
}
assert(pibb->status == svn_wc__db_status_normal
|| pibb->status == svn_wc__db_status_incomplete
|| pibb->props == NULL);
if (present)
{
SVN_ERR(svn_sqlite__bind_properties(stmt, 15, pibb->props,
scratch_pool));
SVN_ERR(svn_sqlite__bind_iprops(stmt, 23, pibb->iprops,
scratch_pool));
}
if (pibb->dav_cache)
SVN_ERR(svn_sqlite__bind_properties(stmt, 18, pibb->dav_cache,
scratch_pool));
if (pibb->file_external)
SVN_ERR(svn_sqlite__bind_int(stmt, 20, 1));
SVN_ERR(svn_sqlite__insert(NULL, stmt));
if (pibb->update_actual_props)
{
apr_hash_t *base_props = (apr_hash_t *)pibb->props;
apr_hash_t *new_actual_props = (apr_hash_t *)pibb->new_actual_props;
if (base_props != NULL
&& new_actual_props != NULL
&& (apr_hash_count(base_props) == apr_hash_count(new_actual_props)))
{
apr_array_header_t *diffs;
SVN_ERR(svn_prop_diffs(&diffs, new_actual_props, base_props,
scratch_pool));
if (diffs->nelts == 0)
new_actual_props = NULL;
}
SVN_ERR(set_actual_props(wcroot, local_relpath, new_actual_props,
scratch_pool));
}
if (pibb->kind == svn_node_dir && pibb->children)
SVN_ERR(insert_incomplete_children(wcroot->sdb, wcroot->wc_id,
local_relpath,
repos_id,
pibb->repos_relpath,
pibb->revision,
pibb->children,
0 ,
scratch_pool));
if (*local_relpath)
{
if (parent_relpath
&& ((pibb->status == svn_wc__db_status_normal)
|| (pibb->status == svn_wc__db_status_incomplete))
&& ! pibb->file_external)
{
SVN_ERR(db_extend_parent_delete(wcroot, local_relpath,
pibb->kind, 0,
scratch_pool));
}
else if (pibb->status == svn_wc__db_status_not_present
|| pibb->status == svn_wc__db_status_server_excluded
|| pibb->status == svn_wc__db_status_excluded)
{
SVN_ERR(db_retract_parent_delete(wcroot, local_relpath, 0,
scratch_pool));
}
}
if (pibb->delete_working)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_WORKING_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
if (pibb->insert_base_deleted)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_INSERT_DELETE_FROM_BASE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd",
wcroot->wc_id, local_relpath,
relpath_depth(local_relpath)));
SVN_ERR(svn_sqlite__step_done(stmt));
}
SVN_ERR(add_work_items(wcroot->sdb, pibb->work_items, scratch_pool));
if (pibb->conflict)
SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
pibb->conflict, scratch_pool));
return SVN_NO_ERROR;
}
static void
blank_iwb(insert_working_baton_t *piwb)
{
memset(piwb, 0, sizeof(*piwb));
piwb->changed_rev = SVN_INVALID_REVNUM;
piwb->depth = svn_depth_infinity;
}
static svn_error_t *
insert_incomplete_children(svn_sqlite__db_t *sdb,
apr_int64_t wc_id,
const char *local_relpath,
apr_int64_t repos_id,
const char *repos_path,
svn_revnum_t revision,
const apr_array_header_t *children,
int op_depth,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
int i;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
apr_hash_t *moved_to_relpaths = apr_hash_make(scratch_pool);
SVN_ERR_ASSERT(repos_path != NULL || op_depth > 0);
SVN_ERR_ASSERT((repos_id != INVALID_REPOS_ID)
== (repos_path != NULL));
if (op_depth > 0)
{
for (i = children->nelts; i--; )
{
const char *name = APR_ARRAY_IDX(children, i, const char *);
svn_boolean_t have_row;
svn_pool_clear(iterpool);
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
STMT_SELECT_WORKING_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id,
svn_relpath_join(local_relpath, name,
iterpool)));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row && !svn_sqlite__column_is_null(stmt, 14))
svn_hash_sets(moved_to_relpaths, name,
svn_sqlite__column_text(stmt, 14, scratch_pool));
SVN_ERR(svn_sqlite__reset(stmt));
}
}
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_NODE));
for (i = children->nelts; i--; )
{
const char *name = APR_ARRAY_IDX(children, i, const char *);
svn_pool_clear(iterpool);
SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnrsnsnnnnnnnnnnsn",
wc_id,
svn_relpath_join(local_relpath, name,
iterpool),
op_depth,
local_relpath,
revision,
"incomplete",
"unknown",
svn_hash_gets(moved_to_relpaths, name)));
if (repos_id != INVALID_REPOS_ID)
{
SVN_ERR(svn_sqlite__bind_int64(stmt, 5, repos_id));
SVN_ERR(svn_sqlite__bind_text(stmt, 6,
svn_relpath_join(repos_path, name,
iterpool)));
}
SVN_ERR(svn_sqlite__insert(NULL, stmt));
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
static svn_error_t *
insert_working_node(const insert_working_baton_t *piwb,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
const char *parent_relpath;
const char *moved_to_relpath = NULL;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
svn_boolean_t present;
SVN_ERR_ASSERT(piwb->op_depth > 0);
SVN_ERR_ASSERT(*local_relpath != '\0');
parent_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_MOVED_TO));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
piwb->op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
moved_to_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
SVN_ERR(svn_sqlite__reset(stmt));
present = (piwb->presence == svn_wc__db_status_normal
|| piwb->presence == svn_wc__db_status_incomplete);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnntstrisn"
"nnnn"
"sns",
wcroot->wc_id, local_relpath,
piwb->op_depth,
parent_relpath,
presence_map, piwb->presence,
(piwb->kind == svn_node_dir && present)
? svn_token__to_word(depth_map, piwb->depth) : NULL,
kind_map, piwb->kind,
piwb->changed_rev,
piwb->changed_date,
piwb->changed_author,
(piwb->kind == svn_node_symlink && present)
? piwb->target : NULL,
moved_to_relpath));
if (piwb->moved_here)
{
SVN_ERR(svn_sqlite__bind_int(stmt, 8, TRUE));
}
if (piwb->kind == svn_node_file && present)
{
SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, piwb->checksum,
scratch_pool));
}
if (piwb->original_repos_relpath != NULL)
{
SVN_ERR(svn_sqlite__bind_int64(stmt, 5, piwb->original_repos_id));
SVN_ERR(svn_sqlite__bind_text(stmt, 6, piwb->original_repos_relpath));
SVN_ERR(svn_sqlite__bind_revnum(stmt, 7, piwb->original_revnum));
}
assert(piwb->presence == svn_wc__db_status_normal
|| piwb->presence == svn_wc__db_status_incomplete
|| piwb->props == NULL);
if (present && piwb->original_repos_relpath)
SVN_ERR(svn_sqlite__bind_properties(stmt, 15, piwb->props, scratch_pool));
SVN_ERR(svn_sqlite__insert(NULL, stmt));
if (piwb->kind == svn_node_dir && piwb->children)
SVN_ERR(insert_incomplete_children(wcroot->sdb, wcroot->wc_id,
local_relpath,
INVALID_REPOS_ID ,
NULL ,
piwb->original_revnum,
piwb->children,
piwb->op_depth,
scratch_pool));
if (piwb->update_actual_props)
{
apr_hash_t *base_props = (apr_hash_t *)piwb->props;
apr_hash_t *new_actual_props = (apr_hash_t *)piwb->new_actual_props;
if (base_props != NULL
&& new_actual_props != NULL
&& (apr_hash_count(base_props) == apr_hash_count(new_actual_props)))
{
apr_array_header_t *diffs;
SVN_ERR(svn_prop_diffs(&diffs, new_actual_props, base_props,
scratch_pool));
if (diffs->nelts == 0)
new_actual_props = NULL;
}
SVN_ERR(set_actual_props(wcroot, local_relpath, new_actual_props,
scratch_pool));
}
if (piwb->kind == svn_node_dir)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_ACTUAL_CLEAR_CHANGELIST));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_EMPTY));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
if (piwb->not_present_op_depth > 0
&& piwb->not_present_op_depth < piwb->op_depth)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_INSERT_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "isdsisrtnt",
wcroot->wc_id, local_relpath,
piwb->not_present_op_depth, parent_relpath,
piwb->original_repos_id,
piwb->original_repos_relpath,
piwb->original_revnum,
presence_map, svn_wc__db_status_not_present,
kind_map, piwb->kind));
SVN_ERR(svn_sqlite__step_done(stmt));
}
SVN_ERR(add_work_items(wcroot->sdb, piwb->work_items, scratch_pool));
if (piwb->conflict)
SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
piwb->conflict, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
gather_children(const apr_array_header_t **children,
svn_wc__db_wcroot_t *wcroot,
const char *parent_relpath,
int stmt_idx,
int op_depth,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
apr_array_header_t *result;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
result = apr_array_make(result_pool, 16, sizeof(const char*));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, stmt_idx));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath));
if (op_depth >= 0)
SVN_ERR(svn_sqlite__bind_int(stmt, 3, op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
const char *name = svn_relpath_basename(child_relpath, result_pool);
APR_ARRAY_PUSH(result, const char *) = name;
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
*children = result;
return SVN_NO_ERROR;
}
static svn_boolean_t
is_immediate_child_path(const char *parent_abspath, const char *child_abspath)
{
const char *local_relpath = svn_dirent_skip_ancestor(parent_abspath,
child_abspath);
return local_relpath && *local_relpath && !strchr(local_relpath, '/');
}
static void
remove_from_access_cache(apr_hash_t *access_cache,
const char *local_abspath)
{
svn_wc_adm_access_t *adm_access;
adm_access = svn_hash_gets(access_cache, local_abspath);
if (adm_access)
svn_wc__adm_access_set_entries(adm_access, NULL);
}
static svn_error_t *
flush_entries(svn_wc__db_wcroot_t *wcroot,
const char *local_abspath,
svn_depth_t depth,
apr_pool_t *scratch_pool)
{
const char *parent_abspath;
if (apr_hash_count(wcroot->access_cache) == 0)
return SVN_NO_ERROR;
remove_from_access_cache(wcroot->access_cache, local_abspath);
if (depth > svn_depth_empty)
{
apr_hash_index_t *hi;
for (hi = apr_hash_first(scratch_pool, wcroot->access_cache);
hi;
hi = apr_hash_next(hi))
{
const char *item_abspath = apr_hash_this_key(hi);
if ((depth == svn_depth_files || depth == svn_depth_immediates) &&
is_immediate_child_path(local_abspath, item_abspath))
{
remove_from_access_cache(wcroot->access_cache, item_abspath);
}
else if (depth == svn_depth_infinity &&
svn_dirent_is_ancestor(local_abspath, item_abspath))
{
remove_from_access_cache(wcroot->access_cache, item_abspath);
}
}
}
parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
remove_from_access_cache(wcroot->access_cache, parent_abspath);
return SVN_NO_ERROR;
}
static svn_error_t *
add_single_work_item(svn_sqlite__db_t *sdb,
const svn_skel_t *work_item,
apr_pool_t *scratch_pool)
{
svn_stringbuf_t *serialized;
svn_sqlite__stmt_t *stmt;
serialized = svn_skel__unparse(work_item, scratch_pool);
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_WORK_ITEM));
SVN_ERR(svn_sqlite__bind_blob(stmt, 1, serialized->data, serialized->len));
return svn_error_trace(svn_sqlite__insert(NULL, stmt));
}
static svn_error_t *
add_work_items(svn_sqlite__db_t *sdb,
const svn_skel_t *skel,
apr_pool_t *scratch_pool)
{
apr_pool_t *iterpool;
if (skel == NULL)
return SVN_NO_ERROR;
SVN_ERR_ASSERT(!skel->is_atom);
if (SVN_WC__SINGLE_WORK_ITEM(skel))
return svn_error_trace(add_single_work_item(sdb, skel, scratch_pool));
iterpool = svn_pool_create(scratch_pool);
for (skel = skel->children; skel; skel = skel->next)
{
svn_pool_clear(iterpool);
SVN_ERR(add_single_work_item(sdb, skel, iterpool));
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
static svn_error_t *
does_node_exist(svn_boolean_t *exists,
const svn_wc__db_wcroot_t *wcroot,
const char *local_relpath)
{
svn_sqlite__stmt_t *stmt;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_DOES_NODE_EXIST));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(exists, stmt));
return svn_error_trace(svn_sqlite__reset(stmt));
}
svn_error_t *
svn_wc__db_install_schema_statistics(svn_sqlite__db_t *sdb,
apr_pool_t *scratch_pool)
{
SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_INSTALL_SCHEMA_STATISTICS));
return SVN_NO_ERROR;
}
static svn_error_t *
init_db(
apr_int64_t *repos_id,
apr_int64_t *wc_id,
svn_sqlite__db_t *db,
const char *repos_root_url,
const char *repos_uuid,
const char *root_node_repos_relpath,
svn_revnum_t root_node_revision,
svn_depth_t root_node_depth,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
SVN_ERR(svn_sqlite__exec_statements(db, STMT_CREATE_SCHEMA));
SVN_ERR(svn_wc__db_install_schema_statistics(db, scratch_pool));
SVN_ERR(create_repos_id(repos_id, repos_root_url, repos_uuid,
db, scratch_pool));
SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_WCROOT));
SVN_ERR(svn_sqlite__insert(wc_id, stmt));
if (root_node_repos_relpath)
{
svn_wc__db_status_t status = svn_wc__db_status_normal;
if (root_node_revision > 0)
status = svn_wc__db_status_incomplete;
SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "isdsisrtst",
*wc_id,
"",
0,
SVN_VA_NULL,
*repos_id,
root_node_repos_relpath,
root_node_revision,
presence_map, status,
svn_token__to_word(depth_map,
root_node_depth),
kind_map, svn_node_dir ));
SVN_ERR(svn_sqlite__insert(NULL, stmt));
}
return SVN_NO_ERROR;
}
static svn_error_t *
create_db(svn_sqlite__db_t **sdb,
apr_int64_t *repos_id,
apr_int64_t *wc_id,
const char *dir_abspath,
const char *repos_root_url,
const char *repos_uuid,
const char *sdb_fname,
const char *root_node_repos_relpath,
svn_revnum_t root_node_revision,
svn_depth_t root_node_depth,
svn_boolean_t exclusive,
apr_int32_t timeout,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
SVN_ERR(svn_wc__db_util_open_db(sdb, dir_abspath, sdb_fname,
svn_sqlite__mode_rwcreate, exclusive,
timeout,
NULL ,
result_pool, scratch_pool));
SVN_SQLITE__WITH_LOCK(init_db(repos_id, wc_id,
*sdb, repos_root_url, repos_uuid,
root_node_repos_relpath, root_node_revision,
root_node_depth, scratch_pool),
*sdb);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_init(svn_wc__db_t *db,
const char *local_abspath,
const char *repos_relpath,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t initial_rev,
svn_depth_t depth,
apr_pool_t *scratch_pool)
{
svn_sqlite__db_t *sdb;
apr_int64_t repos_id;
apr_int64_t wc_id;
svn_wc__db_wcroot_t *wcroot;
svn_boolean_t sqlite_exclusive = FALSE;
apr_int32_t sqlite_timeout = 0;
apr_hash_index_t *hi;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(repos_relpath != NULL);
SVN_ERR_ASSERT(depth == svn_depth_empty
|| depth == svn_depth_files
|| depth == svn_depth_immediates
|| depth == svn_depth_infinity);
SVN_ERR(svn_config_get_bool(db->config, &sqlite_exclusive,
SVN_CONFIG_SECTION_WORKING_COPY,
SVN_CONFIG_OPTION_SQLITE_EXCLUSIVE,
FALSE));
SVN_ERR(create_db(&sdb, &repos_id, &wc_id, local_abspath, repos_root_url,
repos_uuid, SDB_FILE,
repos_relpath, initial_rev, depth, sqlite_exclusive,
sqlite_timeout,
db->state_pool, scratch_pool));
SVN_ERR(svn_wc__db_pdh_create_wcroot(&wcroot,
apr_pstrdup(db->state_pool, local_abspath),
sdb, wc_id, FORMAT_FROM_SDB,
FALSE ,
db->state_pool, scratch_pool));
for (hi = apr_hash_first(scratch_pool, db->dir_data);
hi;
hi = apr_hash_next(hi))
{
const char *abspath = apr_hash_this_key(hi);
if (svn_dirent_is_ancestor(wcroot->abspath, abspath))
svn_hash_sets(db->dir_data, abspath, NULL);
}
svn_hash_sets(db->dir_data, wcroot->abspath, wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_to_relpath(const char **local_relpath,
svn_wc__db_t *db,
const char *wri_abspath,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &relpath, db,
wri_abspath, result_pool, scratch_pool));
CHECK_MINIMAL_WCROOT(wcroot, wri_abspath, scratch_pool);
if (svn_dirent_is_ancestor(wcroot->abspath, local_abspath))
{
*local_relpath = apr_pstrdup(result_pool,
svn_dirent_skip_ancestor(wcroot->abspath,
local_abspath));
}
else
*local_relpath = apr_pstrdup(result_pool, local_abspath);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_from_relpath(const char **local_abspath,
svn_wc__db_t *db,
const char *wri_abspath,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *unused_relpath;
#if 0
SVN_ERR_ASSERT(svn_relpath_is_canonical(local_relpath));
#endif
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &unused_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
CHECK_MINIMAL_WCROOT(wcroot, wri_abspath, scratch_pool);
*local_abspath = svn_dirent_join(wcroot->abspath,
local_relpath,
result_pool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_get_wcroot(const char **wcroot_abspath,
svn_wc__db_t *db,
const char *wri_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *unused_relpath;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &unused_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
CHECK_MINIMAL_WCROOT(wcroot, wri_abspath, scratch_pool);
*wcroot_abspath = apr_pstrdup(result_pool, wcroot->abspath);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_base_add_directory(svn_wc__db_t *db,
const char *local_abspath,
const char *wri_abspath,
const char *repos_relpath,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t revision,
const apr_hash_t *props,
svn_revnum_t changed_rev,
apr_time_t changed_date,
const char *changed_author,
const apr_array_header_t *children,
svn_depth_t depth,
apr_hash_t *dav_cache,
svn_boolean_t update_actual_props,
apr_hash_t *new_actual_props,
apr_array_header_t *new_iprops,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
insert_base_baton_t ibb;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(repos_relpath != NULL);
SVN_ERR_ASSERT(svn_uri_is_canonical(repos_root_url, scratch_pool));
SVN_ERR_ASSERT(repos_uuid != NULL);
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
SVN_ERR_ASSERT(props != NULL);
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(changed_rev));
#if 0
SVN_ERR_ASSERT(children != NULL);
#endif
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
local_relpath = svn_dirent_skip_ancestor(wcroot->abspath, local_abspath);
blank_ibb(&ibb);
ibb.repos_root_url = repos_root_url;
ibb.repos_uuid = repos_uuid;
ibb.status = svn_wc__db_status_normal;
ibb.kind = svn_node_dir;
ibb.repos_relpath = repos_relpath;
ibb.revision = revision;
ibb.iprops = new_iprops;
ibb.props = props;
ibb.changed_rev = changed_rev;
ibb.changed_date = changed_date;
ibb.changed_author = changed_author;
ibb.children = children;
ibb.depth = depth;
ibb.dav_cache = dav_cache;
ibb.conflict = conflict;
ibb.work_items = work_items;
if (update_actual_props)
{
ibb.update_actual_props = TRUE;
ibb.new_actual_props = new_actual_props;
}
SVN_WC__DB_WITH_TXN(
insert_base_node(&ibb, wcroot, local_relpath, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, depth, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_base_add_incomplete_directory(svn_wc__db_t *db,
const char *local_abspath,
const char *repos_relpath,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t revision,
svn_depth_t depth,
svn_boolean_t insert_base_deleted,
svn_boolean_t delete_working,
svn_skel_t *conflict,
svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
struct insert_base_baton_t ibb;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
SVN_ERR_ASSERT(repos_relpath && repos_root_url && repos_uuid);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
blank_ibb(&ibb);
ibb.repos_root_url = repos_root_url;
ibb.repos_uuid = repos_uuid;
ibb.status = svn_wc__db_status_incomplete;
ibb.kind = svn_node_dir;
ibb.repos_relpath = repos_relpath;
ibb.revision = revision;
ibb.depth = depth;
ibb.insert_base_deleted = insert_base_deleted;
ibb.delete_working = delete_working;
ibb.conflict = conflict;
ibb.work_items = work_items;
SVN_WC__DB_WITH_TXN(
insert_base_node(&ibb, wcroot, local_relpath, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_base_add_file(svn_wc__db_t *db,
const char *local_abspath,
const char *wri_abspath,
const char *repos_relpath,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t revision,
const apr_hash_t *props,
svn_revnum_t changed_rev,
apr_time_t changed_date,
const char *changed_author,
const svn_checksum_t *checksum,
apr_hash_t *dav_cache,
svn_boolean_t delete_working,
svn_boolean_t update_actual_props,
apr_hash_t *new_actual_props,
apr_array_header_t *new_iprops,
svn_boolean_t keep_recorded_info,
svn_boolean_t insert_base_deleted,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
insert_base_baton_t ibb;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(repos_relpath != NULL);
SVN_ERR_ASSERT(svn_uri_is_canonical(repos_root_url, scratch_pool));
SVN_ERR_ASSERT(repos_uuid != NULL);
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
SVN_ERR_ASSERT(props != NULL);
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(changed_rev));
SVN_ERR_ASSERT(checksum != NULL);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
local_relpath = svn_dirent_skip_ancestor(wcroot->abspath, local_abspath);
blank_ibb(&ibb);
ibb.repos_root_url = repos_root_url;
ibb.repos_uuid = repos_uuid;
ibb.status = svn_wc__db_status_normal;
ibb.kind = svn_node_file;
ibb.repos_relpath = repos_relpath;
ibb.revision = revision;
ibb.props = props;
ibb.changed_rev = changed_rev;
ibb.changed_date = changed_date;
ibb.changed_author = changed_author;
ibb.checksum = checksum;
ibb.dav_cache = dav_cache;
ibb.iprops = new_iprops;
if (update_actual_props)
{
ibb.update_actual_props = TRUE;
ibb.new_actual_props = new_actual_props;
}
ibb.keep_recorded_info = keep_recorded_info;
ibb.insert_base_deleted = insert_base_deleted;
ibb.delete_working = delete_working;
ibb.conflict = conflict;
ibb.work_items = work_items;
SVN_WC__DB_WITH_TXN(
insert_base_node(&ibb, wcroot, local_relpath, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_infinity,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_base_add_symlink(svn_wc__db_t *db,
const char *local_abspath,
const char *wri_abspath,
const char *repos_relpath,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t revision,
const apr_hash_t *props,
svn_revnum_t changed_rev,
apr_time_t changed_date,
const char *changed_author,
const char *target,
apr_hash_t *dav_cache,
svn_boolean_t delete_working,
svn_boolean_t update_actual_props,
apr_hash_t *new_actual_props,
apr_array_header_t *new_iprops,
svn_boolean_t keep_recorded_info,
svn_boolean_t insert_base_deleted,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
insert_base_baton_t ibb;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(repos_relpath != NULL);
SVN_ERR_ASSERT(svn_uri_is_canonical(repos_root_url, scratch_pool));
SVN_ERR_ASSERT(repos_uuid != NULL);
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
SVN_ERR_ASSERT(props != NULL);
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(changed_rev));
SVN_ERR_ASSERT(target != NULL);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
local_relpath = svn_dirent_skip_ancestor(wcroot->abspath, local_abspath);
blank_ibb(&ibb);
ibb.repos_root_url = repos_root_url;
ibb.repos_uuid = repos_uuid;
ibb.status = svn_wc__db_status_normal;
ibb.kind = svn_node_symlink;
ibb.repos_relpath = repos_relpath;
ibb.revision = revision;
ibb.props = props;
ibb.changed_rev = changed_rev;
ibb.changed_date = changed_date;
ibb.changed_author = changed_author;
ibb.target = target;
ibb.dav_cache = dav_cache;
ibb.iprops = new_iprops;
if (update_actual_props)
{
ibb.update_actual_props = TRUE;
ibb.new_actual_props = new_actual_props;
}
ibb.keep_recorded_info = keep_recorded_info;
ibb.insert_base_deleted = insert_base_deleted;
ibb.delete_working = delete_working;
ibb.conflict = conflict;
ibb.work_items = work_items;
SVN_WC__DB_WITH_TXN(
insert_base_node(&ibb, wcroot, local_relpath, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_infinity,
scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
add_excluded_or_not_present_node(svn_wc__db_t *db,
const char *local_abspath,
const char *repos_relpath,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t revision,
svn_node_kind_t kind,
svn_wc__db_status_t status,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
insert_base_baton_t ibb;
const char *dir_abspath, *name;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(repos_relpath != NULL);
SVN_ERR_ASSERT(svn_uri_is_canonical(repos_root_url, scratch_pool));
SVN_ERR_ASSERT(repos_uuid != NULL);
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
SVN_ERR_ASSERT(status == svn_wc__db_status_server_excluded
|| status == svn_wc__db_status_excluded
|| status == svn_wc__db_status_not_present);
svn_dirent_split(&dir_abspath, &name, local_abspath, scratch_pool);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
dir_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
local_relpath = svn_relpath_join(local_relpath, name, scratch_pool);
blank_ibb(&ibb);
ibb.repos_root_url = repos_root_url;
ibb.repos_uuid = repos_uuid;
ibb.status = status;
ibb.kind = kind;
ibb.repos_relpath = repos_relpath;
ibb.revision = revision;
ibb.children = NULL;
ibb.depth = svn_depth_unknown;
ibb.checksum = NULL;
ibb.target = NULL;
ibb.conflict = conflict;
ibb.work_items = work_items;
SVN_WC__DB_WITH_TXN(
insert_base_node(&ibb, wcroot, local_relpath, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_infinity,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_base_add_excluded_node(svn_wc__db_t *db,
const char *local_abspath,
const char *repos_relpath,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t revision,
svn_node_kind_t kind,
svn_wc__db_status_t status,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
SVN_ERR_ASSERT(status == svn_wc__db_status_server_excluded
|| status == svn_wc__db_status_excluded);
return add_excluded_or_not_present_node(
db, local_abspath, repos_relpath, repos_root_url, repos_uuid, revision,
kind, status, conflict, work_items, scratch_pool);
}
svn_error_t *
svn_wc__db_base_add_not_present_node(svn_wc__db_t *db,
const char *local_abspath,
const char *repos_relpath,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t revision,
svn_node_kind_t kind,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
return add_excluded_or_not_present_node(
db, local_abspath, repos_relpath, repos_root_url, repos_uuid, revision,
kind, svn_wc__db_status_not_present, conflict, work_items, scratch_pool);
}
static svn_error_t *
clear_moved_here(svn_wc__db_wcroot_t *wcroot,
const char *moved_to_relpath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
int affected_rows;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_CLEAR_MOVED_HERE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, moved_to_relpath,
relpath_depth(moved_to_relpath)));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
if (affected_rows == 0)
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot, moved_to_relpath,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_break_move_internal(svn_wc__db_wcroot_t *wcroot,
const char *src_relpath,
int delete_op_depth,
const char *dst_relpath,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
int affected;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_CLEAR_MOVED_TO_RELPATH));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, src_relpath,
delete_op_depth));
SVN_ERR(svn_sqlite__update(&affected, stmt));
if (affected != 1)
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
_("Path '%s' is not moved"),
path_for_error_message(wcroot, src_relpath,
scratch_pool));
SVN_ERR(clear_moved_here(wcroot, dst_relpath, scratch_pool));
SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
db_base_remove(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_wc__db_t *db,
svn_boolean_t keep_as_working,
svn_boolean_t mark_not_present,
svn_boolean_t mark_excluded,
svn_revnum_t marker_revision,
svn_skel_t *conflict,
svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
svn_wc__db_status_t status;
svn_revnum_t revision;
apr_int64_t repos_id;
const char *repos_relpath;
svn_node_kind_t kind;
svn_boolean_t keep_working;
int op_depth;
svn_node_kind_t wrk_kind;
svn_boolean_t no_delete_wc = FALSE;
svn_boolean_t file_external;
SVN_ERR(svn_wc__db_base_get_info_internal(&status, &kind, &revision,
&repos_relpath, &repos_id,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
&file_external,
wcroot, local_relpath,
scratch_pool, scratch_pool));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
return svn_error_trace(svn_sqlite__reset(stmt));
op_depth = svn_sqlite__column_int(stmt, 0);
wrk_kind = svn_sqlite__column_token(stmt, 4, kind_map);
if (op_depth > 0
&& op_depth == relpath_depth(local_relpath))
{
svn_wc__db_status_t presence;
presence = svn_sqlite__column_token(stmt, 3, presence_map);
if (presence == svn_wc__db_status_base_deleted)
{
keep_working = FALSE;
no_delete_wc = TRUE;
}
else
{
keep_working = TRUE;
}
}
else
keep_working = FALSE;
SVN_ERR(svn_sqlite__reset(stmt));
if (keep_as_working && op_depth == 0)
{
if (status == svn_wc__db_status_normal
|| status == svn_wc__db_status_incomplete)
{
SVN_ERR(svn_wc__db_op_make_copy_internal(wcroot, local_relpath, TRUE,
NULL, NULL,
scratch_pool));
}
keep_working = TRUE;
}
if (!keep_working && !no_delete_wc)
{
svn_skel_t *work_item;
const char *local_abspath;
local_abspath = svn_dirent_join(wcroot->abspath, local_relpath,
scratch_pool);
if (wrk_kind == svn_node_dir)
{
apr_pool_t *iterpool;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_WORKING_PRESENT));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
iterpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
const char *node_relpath = svn_sqlite__column_text(stmt, 0, NULL);
svn_node_kind_t node_kind = svn_sqlite__column_token(stmt, 1,
kind_map);
const char *node_abspath;
svn_error_t *err;
svn_pool_clear(iterpool);
node_abspath = svn_dirent_join(wcroot->abspath, node_relpath,
iterpool);
if (node_kind == svn_node_dir)
err = svn_wc__wq_build_dir_remove(&work_item,
db, wcroot->abspath,
node_abspath, FALSE,
iterpool, iterpool);
else
err = svn_wc__wq_build_file_remove(&work_item,
db,
wcroot->abspath,
node_abspath,
iterpool, iterpool);
if (!err)
err = add_work_items(wcroot->sdb, work_item, iterpool);
if (err)
return svn_error_compose_create(err, svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(svn_wc__wq_build_dir_remove(&work_item,
db, wcroot->abspath,
local_abspath, FALSE,
scratch_pool, iterpool));
svn_pool_destroy(iterpool);
}
else
SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
db, wcroot->abspath,
local_abspath,
scratch_pool, scratch_pool));
SVN_ERR(add_work_items(wcroot->sdb, work_item, scratch_pool));
}
if (! keep_working)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_NODE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
else if (! keep_as_working)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_FOR_BASE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
if (!keep_working)
{
apr_pool_t *iterpool;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MOVED_OUTSIDE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
local_relpath,
relpath_depth(local_relpath)));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
iterpool = svn_pool_create(scratch_pool);
while (have_row)
{
const char *moved_to_relpath;
svn_error_t *err;
svn_pool_clear(iterpool);
moved_to_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
err = clear_moved_here(wcroot, moved_to_relpath, iterpool);
if (err)
return svn_error_compose_create(err, svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
svn_pool_destroy(iterpool);
SVN_ERR(svn_sqlite__reset(stmt));
}
else
{
apr_pool_t *iterpool;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MOVED_DESCENDANTS_SRC));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
local_relpath, 0));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
iterpool = svn_pool_create(scratch_pool);
while (have_row)
{
int delete_op_depth = svn_sqlite__column_int(stmt, 0);
const char *src_relpath;
const char *dst_relpath;
svn_error_t *err;
svn_pool_clear(iterpool);
src_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
dst_relpath = svn_sqlite__column_text(stmt, 4, iterpool);
err = svn_wc__db_op_break_move_internal(wcroot, src_relpath,
delete_op_depth,
dst_relpath,
NULL,
iterpool);
if (err)
return svn_error_compose_create(err, svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
svn_pool_destroy(iterpool);
SVN_ERR(svn_sqlite__reset(stmt));
}
if (keep_working)
{
SVN_ERR(svn_sqlite__get_statement(
&stmt, wcroot->sdb,
STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, 0));
SVN_ERR(svn_sqlite__step_done(stmt));
}
else
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_WORKING_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_BASE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(db_retract_parent_delete(wcroot, local_relpath, 0, scratch_pool));
if (mark_not_present || mark_excluded)
{
struct insert_base_baton_t ibb;
svn_boolean_t no_marker = FALSE;
if (file_external)
{
const char *parent_local_relpath;
const char *name;
svn_error_t *err;
svn_relpath_split(&parent_local_relpath, &name, local_relpath,
scratch_pool);
err = svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
&repos_relpath, &repos_id,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
wcroot, parent_local_relpath,
scratch_pool, scratch_pool);
if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
return svn_error_trace(err);
else if (err)
{
svn_error_clear(err);
no_marker = TRUE;
}
else
{
repos_relpath = svn_relpath_join(repos_relpath, name, scratch_pool);
}
}
if (!no_marker)
{
blank_ibb(&ibb);
ibb.repos_id = repos_id;
ibb.status = mark_excluded ? svn_wc__db_status_excluded
: svn_wc__db_status_not_present;
ibb.kind = kind;
ibb.repos_relpath = repos_relpath;
ibb.revision = SVN_IS_VALID_REVNUM(marker_revision)
? marker_revision
: revision;
ibb.children = NULL;
ibb.depth = svn_depth_unknown;
ibb.checksum = NULL;
ibb.target = NULL;
SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool));
}
}
SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
if (conflict)
SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
conflict, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_base_remove(svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t keep_as_working,
svn_boolean_t mark_not_present,
svn_boolean_t mark_excluded,
svn_revnum_t marker_revision,
svn_skel_t *conflict,
svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(db_base_remove(wcroot, local_relpath,
db, keep_as_working,
mark_not_present, mark_excluded,
marker_revision,
conflict, work_items, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_infinity,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_base_get_info_internal(svn_wc__db_status_t *status,
svn_node_kind_t *kind,
svn_revnum_t *revision,
const char **repos_relpath,
apr_int64_t *repos_id,
svn_revnum_t *changed_rev,
apr_time_t *changed_date,
const char **changed_author,
svn_depth_t *depth,
const svn_checksum_t **checksum,
const char **target,
svn_wc__db_lock_t **lock,
svn_boolean_t *had_props,
apr_hash_t **props,
svn_boolean_t *update_root,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
svn_error_t *err = SVN_NO_ERROR;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
lock ? STMT_SELECT_BASE_NODE_WITH_LOCK
: STMT_SELECT_BASE_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
svn_wc__db_status_t node_status = svn_sqlite__column_token(stmt, 2,
presence_map);
svn_node_kind_t node_kind = svn_sqlite__column_token(stmt, 3, kind_map);
if (kind)
{
*kind = node_kind;
}
if (status)
{
*status = node_status;
}
repos_location_from_columns(repos_id, revision, repos_relpath,
stmt, 0, 4, 1, result_pool);
SVN_ERR_ASSERT(!repos_id || *repos_id != INVALID_REPOS_ID);
SVN_ERR_ASSERT(!repos_relpath || *repos_relpath);
if (lock)
{
*lock = lock_from_columns(stmt, 15, 16, 17, 18, result_pool);
}
if (changed_rev)
{
*changed_rev = svn_sqlite__column_revnum(stmt, 7);
}
if (changed_date)
{
*changed_date = svn_sqlite__column_int64(stmt, 8);
}
if (changed_author)
{
*changed_author = svn_sqlite__column_text(stmt, 9, result_pool);
}
if (depth)
{
if (node_kind != svn_node_dir)
{
*depth = svn_depth_unknown;
}
else
{
*depth = svn_sqlite__column_token_null(stmt, 10, depth_map,
svn_depth_unknown);
}
}
if (checksum)
{
if (node_kind != svn_node_file)
{
*checksum = NULL;
}
else
{
err = svn_sqlite__column_checksum(checksum, stmt, 5,
result_pool);
if (err != NULL)
err = svn_error_createf(
err->apr_err, err,
_("The node '%s' has a corrupt checksum value."),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
}
}
if (target)
{
if (node_kind != svn_node_symlink)
*target = NULL;
else
*target = svn_sqlite__column_text(stmt, 11, result_pool);
}
if (had_props)
{
*had_props = SQLITE_PROPERTIES_AVAILABLE(stmt, 13);
}
if (props)
{
if (node_status == svn_wc__db_status_normal
|| node_status == svn_wc__db_status_incomplete)
{
SVN_ERR(svn_sqlite__column_properties(props, stmt, 13,
result_pool, scratch_pool));
if (*props == NULL)
*props = apr_hash_make(result_pool);
}
else
{
assert(svn_sqlite__column_is_null(stmt, 13));
*props = NULL;
}
}
if (update_root)
{
*update_root = svn_sqlite__column_boolean(stmt, 14);
}
}
else
{
err = svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
}
return svn_error_compose_create(err, svn_sqlite__reset(stmt));
}
svn_error_t *
svn_wc__db_base_get_info(svn_wc__db_status_t *status,
svn_node_kind_t *kind,
svn_revnum_t *revision,
const char **repos_relpath,
const char **repos_root_url,
const char **repos_uuid,
svn_revnum_t *changed_rev,
apr_time_t *changed_date,
const char **changed_author,
svn_depth_t *depth,
const svn_checksum_t **checksum,
const char **target,
svn_wc__db_lock_t **lock,
svn_boolean_t *had_props,
apr_hash_t **props,
svn_boolean_t *update_root,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
apr_int64_t repos_id;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN4(
svn_wc__db_base_get_info_internal(status, kind, revision,
repos_relpath, &repos_id,
changed_rev, changed_date,
changed_author, depth,
checksum, target, lock,
had_props, props, update_root,
wcroot, local_relpath,
result_pool, scratch_pool),
svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
wcroot, repos_id, result_pool),
SVN_NO_ERROR,
SVN_NO_ERROR,
wcroot);
SVN_ERR_ASSERT(repos_id != INVALID_REPOS_ID);
return SVN_NO_ERROR;
}
static svn_error_t *
base_get_children_info(apr_hash_t **nodes,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_boolean_t obtain_locks,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_int64_t last_repos_id = INVALID_REPOS_ID;
const char *last_repos_root_url = NULL;
*nodes = apr_hash_make(result_pool);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
obtain_locks
? STMT_SELECT_BASE_CHILDREN_INFO_LOCK
: STMT_SELECT_BASE_CHILDREN_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
struct svn_wc__db_base_info_t *info;
apr_int64_t repos_id;
const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
const char *name = svn_relpath_basename(child_relpath, result_pool);
info = apr_pcalloc(result_pool, sizeof(*info));
repos_id = svn_sqlite__column_int64(stmt, 1);
info->repos_relpath = svn_sqlite__column_text(stmt, 2, result_pool);
info->status = svn_sqlite__column_token(stmt, 3, presence_map);
info->kind = svn_sqlite__column_token(stmt, 4, kind_map);
info->revnum = svn_sqlite__column_revnum(stmt, 5);
info->depth = svn_sqlite__column_token_null(stmt, 6, depth_map,
svn_depth_unknown);
info->update_root = svn_sqlite__column_boolean(stmt, 7);
if (obtain_locks)
info->lock = lock_from_columns(stmt, 8, 9, 10, 11, result_pool);
if (repos_id != last_repos_id)
{
svn_error_t *err;
err = svn_wc__db_fetch_repos_info(&last_repos_root_url, NULL,
wcroot, repos_id,
result_pool);
if (err)
return svn_error_trace(
svn_error_compose_create(err,
svn_sqlite__reset(stmt)));
last_repos_id = repos_id;
}
info->repos_root_url = last_repos_root_url;
svn_hash_sets(*nodes, name, info);
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_base_get_children_info(apr_hash_t **nodes,
svn_wc__db_t *db,
const char *dir_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
dir_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
return svn_error_trace(base_get_children_info(nodes,
wcroot,
local_relpath,
TRUE ,
result_pool,
scratch_pool));
}
svn_error_t *
svn_wc__db_base_get_props(apr_hash_t **props,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_status_t presence;
SVN_ERR(svn_wc__db_base_get_info(&presence, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, props, NULL,
db, local_abspath,
result_pool, scratch_pool));
if (presence != svn_wc__db_status_normal
&& presence != svn_wc__db_status_incomplete)
{
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
_("The node '%s' has a BASE status that"
" has no properties."),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_base_get_children(const apr_array_header_t **children,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
return svn_error_trace(
gather_children(children, wcroot, local_relpath,
STMT_SELECT_OP_DEPTH_CHILDREN, 0,
result_pool, scratch_pool));
}
svn_error_t *
svn_wc__db_base_set_dav_cache(svn_wc__db_t *db,
const char *local_abspath,
const apr_hash_t *props,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt;
int affected_rows;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_BASE_NODE_DAV_CACHE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
if (affected_rows != 1)
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
svn_dirent_local_style(local_abspath,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_base_get_dav_cache(apr_hash_t **props,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_BASE_DAV_CACHE));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
svn_sqlite__reset(stmt),
_("The node '%s' was not found."),
svn_dirent_local_style(local_abspath,
scratch_pool));
SVN_ERR(svn_sqlite__column_properties(props, stmt, 0, result_pool,
scratch_pool));
return svn_error_trace(svn_sqlite__reset(stmt));
}
svn_error_t *
svn_wc__db_base_clear_dav_cache_recursive(svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_CLEAR_BASE_NODE_RECURSIVE_DAV_CACHE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_depth_get_info(svn_wc__db_status_t *status,
svn_node_kind_t *kind,
svn_revnum_t *revision,
const char **repos_relpath,
apr_int64_t *repos_id,
svn_revnum_t *changed_rev,
apr_time_t *changed_date,
const char **changed_author,
svn_depth_t *depth,
const svn_checksum_t **checksum,
const char **target,
svn_boolean_t *had_props,
apr_hash_t **props,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
int op_depth,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
svn_error_t *err = SVN_NO_ERROR;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_DEPTH_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd",
wcroot->wc_id, local_relpath, op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
svn_wc__db_status_t node_status = svn_sqlite__column_token(stmt, 2,
presence_map);
svn_node_kind_t node_kind = svn_sqlite__column_token(stmt, 3, kind_map);
if (kind)
{
*kind = node_kind;
}
if (status)
{
*status = node_status;
if (op_depth > 0)
SVN_ERR(convert_to_working_status(status, *status));
}
repos_location_from_columns(repos_id, revision, repos_relpath,
stmt, 0, 4, 1, result_pool);
if (changed_rev)
{
*changed_rev = svn_sqlite__column_revnum(stmt, 7);
}
if (changed_date)
{
*changed_date = svn_sqlite__column_int64(stmt, 8);
}
if (changed_author)
{
*changed_author = svn_sqlite__column_text(stmt, 9, result_pool);
}
if (depth)
{
if (node_kind != svn_node_dir)
{
*depth = svn_depth_unknown;
}
else
{
*depth = svn_sqlite__column_token_null(stmt, 10, depth_map,
svn_depth_unknown);
}
}
if (checksum)
{
if (node_kind != svn_node_file)
{
*checksum = NULL;
}
else
{
err = svn_sqlite__column_checksum(checksum, stmt, 5,
result_pool);
if (err != NULL)
err = svn_error_createf(
err->apr_err, err,
_("The node '%s' has a corrupt checksum value."),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
}
}
if (target)
{
if (node_kind != svn_node_symlink)
*target = NULL;
else
*target = svn_sqlite__column_text(stmt, 11, result_pool);
}
if (had_props)
{
*had_props = SQLITE_PROPERTIES_AVAILABLE(stmt, 12);
}
if (props)
{
if (node_status == svn_wc__db_status_normal
|| node_status == svn_wc__db_status_incomplete)
{
SVN_ERR(svn_sqlite__column_properties(props, stmt, 12,
result_pool, scratch_pool));
if (*props == NULL)
*props = apr_hash_make(result_pool);
}
else
{
assert(svn_sqlite__column_is_null(stmt, 12));
*props = NULL;
}
}
}
else
{
err = svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
}
return svn_error_compose_create(err, svn_sqlite__reset(stmt));
}
typedef svn_error_t *(*svn_wc__db_txn_callback_t)(void *baton,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool);
struct with_triggers_baton_t {
int create_trigger;
int drop_trigger;
svn_wc__db_txn_callback_t cb_func;
void *cb_baton;
};
static svn_error_t *
with_triggers(void *baton,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
struct with_triggers_baton_t *b = baton;
svn_error_t *err1;
svn_error_t *err2;
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, b->create_trigger));
err1 = b->cb_func(b->cb_baton, wcroot, local_relpath, scratch_pool);
err2 = svn_sqlite__exec_statements(wcroot->sdb, b->drop_trigger);
return svn_error_trace(svn_error_compose_create(err1, err2));
}
typedef svn_error_t * (*work_callback_t)(
void *baton,
svn_wc__db_wcroot_t *wcroot,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool);
static svn_error_t *
with_finalization(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_wc__db_txn_callback_t txn_cb,
void *txn_baton,
work_callback_t work_cb,
void *work_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
int finalize_stmt_idx,
apr_pool_t *scratch_pool)
{
svn_error_t *err1;
svn_error_t *err2;
err1 = svn_sqlite__begin_savepoint(wcroot->sdb);
if (!err1)
{
err1 = txn_cb(txn_baton, wcroot, local_relpath, scratch_pool);
err1 = svn_sqlite__finish_savepoint(wcroot->sdb, err1);
}
if (err1 == NULL && notify_func != NULL)
{
err2 = work_cb(work_baton, wcroot,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool);
err1 = svn_error_compose_create(err1, err2);
}
err2 = svn_sqlite__exec_statements(wcroot->sdb, finalize_stmt_idx);
return svn_error_trace(svn_error_compose_create(err1, err2));
}
static void
blank_ieb(insert_external_baton_t *ieb)
{
memset(ieb, 0, sizeof(*ieb));
ieb->revision = SVN_INVALID_REVNUM;
ieb->changed_rev = SVN_INVALID_REVNUM;
ieb->repos_id = INVALID_REPOS_ID;
ieb->recorded_peg_revision = SVN_INVALID_REVNUM;
ieb->recorded_revision = SVN_INVALID_REVNUM;
}
static svn_error_t *
insert_external_node(const insert_external_baton_t *ieb,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
svn_wc__db_status_t status;
svn_error_t *err;
svn_boolean_t update_root;
apr_int64_t repos_id;
svn_sqlite__stmt_t *stmt;
if (ieb->repos_id != INVALID_REPOS_ID)
repos_id = ieb->repos_id;
else
SVN_ERR(create_repos_id(&repos_id, ieb->repos_root_url, ieb->repos_uuid,
wcroot->sdb, scratch_pool));
err = svn_wc__db_base_get_info_internal(&status, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, &update_root,
wcroot, local_relpath,
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);
}
else if (status == svn_wc__db_status_normal && !update_root)
return svn_error_create(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, NULL);
if (ieb->kind == svn_node_file
|| ieb->kind == svn_node_symlink)
{
struct insert_base_baton_t ibb;
blank_ibb(&ibb);
ibb.status = svn_wc__db_status_normal;
ibb.kind = ieb->kind;
ibb.repos_id = repos_id;
ibb.repos_relpath = ieb->repos_relpath;
ibb.revision = ieb->revision;
ibb.props = ieb->props;
ibb.iprops = ieb->iprops;
ibb.changed_rev = ieb->changed_rev;
ibb.changed_date = ieb->changed_date;
ibb.changed_author = ieb->changed_author;
ibb.dav_cache = ieb->dav_cache;
ibb.checksum = ieb->checksum;
ibb.target = ieb->target;
ibb.conflict = ieb->conflict;
ibb.update_actual_props = ieb->update_actual_props;
ibb.new_actual_props = ieb->new_actual_props;
ibb.keep_recorded_info = ieb->keep_recorded_info;
ibb.work_items = ieb->work_items;
ibb.file_external = TRUE;
SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool));
}
else
SVN_ERR(add_work_items(wcroot->sdb, ieb->work_items, scratch_pool));
SVN_ERR_ASSERT(ieb->presence == svn_wc__db_status_normal
|| ieb->presence == svn_wc__db_status_excluded);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_EXTERNAL));
SVN_ERR(svn_sqlite__bindf(stmt, "issttsis",
wcroot->wc_id,
local_relpath,
svn_relpath_dirname(local_relpath,
scratch_pool),
presence_map, ieb->presence,
kind_map, ieb->kind,
ieb->record_ancestor_relpath,
repos_id,
ieb->recorded_repos_relpath));
if (SVN_IS_VALID_REVNUM(ieb->recorded_peg_revision))
SVN_ERR(svn_sqlite__bind_revnum(stmt, 9, ieb->recorded_peg_revision));
if (SVN_IS_VALID_REVNUM(ieb->recorded_revision))
SVN_ERR(svn_sqlite__bind_revnum(stmt, 10, ieb->recorded_revision));
SVN_ERR(svn_sqlite__insert(NULL, stmt));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_external_add_file(svn_wc__db_t *db,
const char *local_abspath,
const char *wri_abspath,
const char *repos_relpath,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t revision,
const apr_hash_t *props,
apr_array_header_t *iprops,
svn_revnum_t changed_rev,
apr_time_t changed_date,
const char *changed_author,
const svn_checksum_t *checksum,
const apr_hash_t *dav_cache,
const char *record_ancestor_abspath,
const char *recorded_repos_relpath,
svn_revnum_t recorded_peg_revision,
svn_revnum_t recorded_revision,
svn_boolean_t update_actual_props,
apr_hash_t *new_actual_props,
svn_boolean_t keep_recorded_info,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
insert_external_baton_t ieb;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
if (! wri_abspath)
wri_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR_ASSERT(svn_dirent_is_ancestor(wcroot->abspath,
record_ancestor_abspath));
SVN_ERR_ASSERT(svn_dirent_is_ancestor(wcroot->abspath, local_abspath));
local_relpath = svn_dirent_skip_ancestor(wcroot->abspath, local_abspath);
blank_ieb(&ieb);
ieb.kind = svn_node_file;
ieb.presence = svn_wc__db_status_normal;
ieb.repos_root_url = repos_root_url;
ieb.repos_uuid = repos_uuid;
ieb.repos_relpath = repos_relpath;
ieb.revision = revision;
ieb.props = props;
ieb.iprops = iprops;
ieb.changed_rev = changed_rev;
ieb.changed_date = changed_date;
ieb.changed_author = changed_author;
ieb.checksum = checksum;
ieb.dav_cache = dav_cache;
ieb.record_ancestor_relpath = svn_dirent_skip_ancestor(
wcroot->abspath,
record_ancestor_abspath);
ieb.recorded_repos_relpath = recorded_repos_relpath;
ieb.recorded_peg_revision = recorded_peg_revision;
ieb.recorded_revision = recorded_revision;
ieb.update_actual_props = update_actual_props;
ieb.new_actual_props = new_actual_props;
ieb.keep_recorded_info = keep_recorded_info;
ieb.conflict = conflict;
ieb.work_items = work_items;
SVN_WC__DB_WITH_TXN(
insert_external_node(&ieb, wcroot, local_relpath, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_external_add_symlink(svn_wc__db_t *db,
const char *local_abspath,
const char *wri_abspath,
const char *repos_relpath,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t revision,
const apr_hash_t *props,
svn_revnum_t changed_rev,
apr_time_t changed_date,
const char *changed_author,
const char *target,
const apr_hash_t *dav_cache,
const char *record_ancestor_abspath,
const char *recorded_repos_relpath,
svn_revnum_t recorded_peg_revision,
svn_revnum_t recorded_revision,
svn_boolean_t update_actual_props,
apr_hash_t *new_actual_props,
svn_boolean_t keep_recorded_info,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
insert_external_baton_t ieb;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
if (! wri_abspath)
wri_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR_ASSERT(svn_dirent_is_ancestor(wcroot->abspath,
record_ancestor_abspath));
SVN_ERR_ASSERT(svn_dirent_is_ancestor(wcroot->abspath, local_abspath));
local_relpath = svn_dirent_skip_ancestor(wcroot->abspath, local_abspath);
blank_ieb(&ieb);
ieb.kind = svn_node_symlink;
ieb.presence = svn_wc__db_status_normal;
ieb.repos_root_url = repos_root_url;
ieb.repos_uuid = repos_uuid;
ieb.repos_relpath = repos_relpath;
ieb.revision = revision;
ieb.props = props;
ieb.changed_rev = changed_rev;
ieb.changed_date = changed_date;
ieb.changed_author = changed_author;
ieb.target = target;
ieb.dav_cache = dav_cache;
ieb.record_ancestor_relpath = svn_dirent_skip_ancestor(
wcroot->abspath,
record_ancestor_abspath);
ieb.recorded_repos_relpath = recorded_repos_relpath;
ieb.recorded_peg_revision = recorded_peg_revision;
ieb.recorded_revision = recorded_revision;
ieb.update_actual_props = update_actual_props;
ieb.new_actual_props = new_actual_props;
ieb.keep_recorded_info = keep_recorded_info;
ieb.work_items = work_items;
SVN_WC__DB_WITH_TXN(
insert_external_node(&ieb, wcroot, local_relpath, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_external_add_dir(svn_wc__db_t *db,
const char *local_abspath,
const char *wri_abspath,
const char *repos_root_url,
const char *repos_uuid,
const char *record_ancestor_abspath,
const char *recorded_repos_relpath,
svn_revnum_t recorded_peg_revision,
svn_revnum_t recorded_revision,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
insert_external_baton_t ieb;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
if (! wri_abspath)
wri_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR_ASSERT(svn_dirent_is_ancestor(wcroot->abspath,
record_ancestor_abspath));
SVN_ERR_ASSERT(svn_dirent_is_ancestor(wcroot->abspath, local_abspath));
local_relpath = svn_dirent_skip_ancestor(wcroot->abspath, local_abspath);
blank_ieb(&ieb);
ieb.kind = svn_node_dir;
ieb.presence = svn_wc__db_status_normal;
ieb.repos_root_url = repos_root_url;
ieb.repos_uuid = repos_uuid;
ieb.record_ancestor_relpath = svn_dirent_skip_ancestor(
wcroot->abspath,
record_ancestor_abspath);
ieb.recorded_repos_relpath = recorded_repos_relpath;
ieb.recorded_peg_revision = recorded_peg_revision;
ieb.recorded_revision = recorded_revision;
ieb.work_items = work_items;
SVN_WC__DB_WITH_TXN(
insert_external_node(&ieb, wcroot, local_relpath, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
static svn_error_t *
db_external_remove(const svn_skel_t *work_items,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
int affected_rows;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_EXTERNAL));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
if (!affected_rows)
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' is not an external."),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_external_remove(svn_wc__db_t *db,
const char *local_abspath,
const char *wri_abspath,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
if (! wri_abspath)
wri_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR_ASSERT(svn_dirent_is_ancestor(wcroot->abspath, local_abspath));
local_relpath = svn_dirent_skip_ancestor(wcroot->abspath, local_abspath);
SVN_WC__DB_WITH_TXN(db_external_remove(work_items, wcroot, local_relpath,
scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_external_read(svn_wc__db_status_t *status,
svn_node_kind_t *kind,
const char **definining_abspath,
const char **repos_root_url,
const char **repos_uuid,
const char **recorded_repos_relpath,
svn_revnum_t *recorded_peg_revision,
svn_revnum_t *recorded_revision,
svn_wc__db_t *db,
const char *local_abspath,
const char *wri_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_info;
svn_error_t *err = NULL;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
if (! wri_abspath)
wri_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR_ASSERT(svn_dirent_is_ancestor(wcroot->abspath, local_abspath));
local_relpath = svn_dirent_skip_ancestor(wcroot->abspath, local_abspath);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_EXTERNAL_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_info, stmt));
if (have_info)
{
if (status)
*status = svn_sqlite__column_token(stmt, 0, presence_map);
if (kind)
*kind = svn_sqlite__column_token(stmt, 1, kind_map);
if (definining_abspath)
{
const char *record_relpath = svn_sqlite__column_text(stmt, 2, NULL);
*definining_abspath = svn_dirent_join(wcroot->abspath,
record_relpath, result_pool);
}
if (repos_root_url || repos_uuid)
{
apr_int64_t repos_id;
repos_id = svn_sqlite__column_int64(stmt, 3);
err = svn_error_compose_create(
err,
svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
wcroot, repos_id,
result_pool));
}
if (recorded_repos_relpath)
*recorded_repos_relpath = svn_sqlite__column_text(stmt, 4,
result_pool);
if (recorded_peg_revision)
*recorded_peg_revision = svn_sqlite__column_revnum(stmt, 5);
if (recorded_revision)
*recorded_revision = svn_sqlite__column_revnum(stmt, 6);
}
else
{
err = svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' is not an external."),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
return svn_error_trace(
svn_error_compose_create(err, svn_sqlite__reset(stmt)));
}
svn_error_t *
svn_wc__db_committable_externals_below(apr_array_header_t **externals,
svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t immediates_only,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
svn_sqlite__stmt_t *stmt;
const char *local_relpath;
svn_boolean_t have_row;
svn_wc__committable_external_info_t *info;
svn_node_kind_t db_kind;
apr_array_header_t *result = NULL;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(
&stmt, wcroot->sdb,
immediates_only
? STMT_SELECT_COMMITTABLE_EXTERNALS_IMMEDIATELY_BELOW
: STMT_SELECT_COMMITTABLE_EXTERNALS_BELOW));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
result = apr_array_make(result_pool, 0,
sizeof(svn_wc__committable_external_info_t *));
while (have_row)
{
info = apr_palloc(result_pool, sizeof(*info));
local_relpath = svn_sqlite__column_text(stmt, 0, NULL);
info->local_abspath = svn_dirent_join(wcroot->abspath, local_relpath,
result_pool);
db_kind = svn_sqlite__column_token(stmt, 1, kind_map);
SVN_ERR_ASSERT(db_kind == svn_node_file || db_kind == svn_node_dir);
info->kind = db_kind;
info->repos_relpath = svn_sqlite__column_text(stmt, 2, result_pool);
info->repos_root_url = svn_sqlite__column_text(stmt, 3, result_pool);
APR_ARRAY_PUSH(result, svn_wc__committable_external_info_t *) = info;
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
*externals = result;
return svn_error_trace(svn_sqlite__reset(stmt));
}
svn_error_t *
svn_wc__db_externals_defined_below(apr_hash_t **externals,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
svn_sqlite__stmt_t *stmt;
const char *local_relpath;
svn_boolean_t have_row;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_EXTERNALS_DEFINED));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
*externals = apr_hash_make(result_pool);
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
const char *def_local_relpath;
local_relpath = svn_sqlite__column_text(stmt, 0, NULL);
def_local_relpath = svn_sqlite__column_text(stmt, 1, NULL);
svn_hash_sets(*externals,
svn_dirent_join(wcroot->abspath, local_relpath,
result_pool),
svn_dirent_join(wcroot->abspath, def_local_relpath,
result_pool));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
return svn_error_trace(svn_sqlite__reset(stmt));
}
svn_error_t *
svn_wc__db_externals_gather_definitions(apr_hash_t **externals,
apr_hash_t **depths,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
svn_sqlite__stmt_t *stmt;
const char *local_relpath;
svn_boolean_t have_row;
svn_error_t *err = NULL;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, iterpool));
VERIFY_USABLE_WCROOT(wcroot);
*externals = apr_hash_make(result_pool);
if (depths != NULL)
*depths = apr_hash_make(result_pool);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_EXTERNAL_PROPERTIES));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
apr_hash_t *node_props;
const char *external_value;
svn_pool_clear(iterpool);
err = svn_sqlite__column_properties(&node_props, stmt, 0, iterpool,
iterpool);
if (err)
break;
external_value = svn_prop_get_value(node_props, SVN_PROP_EXTERNALS);
if (external_value)
{
const char *node_abspath;
const char *node_relpath = svn_sqlite__column_text(stmt, 1, NULL);
node_abspath = svn_dirent_join(wcroot->abspath, node_relpath,
result_pool);
svn_hash_sets(*externals, node_abspath,
apr_pstrdup(result_pool, external_value));
if (depths)
{
svn_depth_t depth
= svn_sqlite__column_token_null(stmt, 2, depth_map,
svn_depth_unknown);
svn_hash_sets(*depths, node_abspath,
svn_token__to_word(depth_map, depth));
}
}
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
svn_pool_destroy(iterpool);
return svn_error_trace(svn_error_compose_create(err,
svn_sqlite__reset(stmt)));
}
static svn_error_t *
copy_actual(svn_wc__db_wcroot_t *src_wcroot,
const char *src_relpath,
svn_wc__db_wcroot_t *dst_wcroot,
const char *dst_relpath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
SVN_ERR(svn_sqlite__get_statement(&stmt, src_wcroot->sdb,
STMT_SELECT_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", src_wcroot->wc_id, src_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
apr_size_t props_size;
const char *changelist;
const char *properties;
changelist = svn_sqlite__column_text(stmt, 0, scratch_pool);
properties = svn_sqlite__column_blob(stmt, 1, &props_size, scratch_pool);
if (changelist || properties)
{
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, dst_wcroot->sdb,
STMT_INSERT_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "issbs",
dst_wcroot->wc_id, dst_relpath,
svn_relpath_dirname(dst_relpath, scratch_pool),
properties, props_size, changelist));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
}
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
static svn_error_t *
cross_db_copy(svn_wc__db_wcroot_t *src_wcroot,
const char *src_relpath,
svn_wc__db_wcroot_t *dst_wcroot,
const char *dst_relpath,
svn_wc__db_status_t dst_status,
int dst_op_depth,
int dst_np_op_depth,
svn_node_kind_t kind,
const apr_array_header_t *children,
apr_int64_t copyfrom_id,
const char *copyfrom_relpath,
svn_revnum_t copyfrom_rev,
apr_pool_t *scratch_pool)
{
insert_working_baton_t iwb;
svn_revnum_t changed_rev;
apr_time_t changed_date;
const char *changed_author;
const svn_checksum_t *checksum;
apr_hash_t *props;
svn_depth_t depth;
SVN_ERR_ASSERT(kind == svn_node_file
|| kind == svn_node_dir
);
SVN_ERR(read_info(NULL, NULL, NULL, NULL, NULL,
&changed_rev, &changed_date, &changed_author, &depth,
&checksum, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
src_wcroot, src_relpath, scratch_pool, scratch_pool));
if (dst_status != svn_wc__db_status_not_present
&& dst_status != svn_wc__db_status_excluded
&& dst_status != svn_wc__db_status_server_excluded)
{
SVN_ERR(db_read_pristine_props(&props, src_wcroot, src_relpath, FALSE,
scratch_pool, scratch_pool));
}
else
props = NULL;
blank_iwb(&iwb);
iwb.presence = dst_status;
iwb.kind = kind;
iwb.props = props;
iwb.changed_rev = changed_rev;
iwb.changed_date = changed_date;
iwb.changed_author = changed_author;
iwb.original_repos_id = copyfrom_id;
iwb.original_repos_relpath = copyfrom_relpath;
iwb.original_revnum = copyfrom_rev;
iwb.moved_here = FALSE;
iwb.op_depth = dst_op_depth;
iwb.checksum = checksum;
iwb.children = children;
iwb.depth = depth;
iwb.not_present_op_depth = dst_np_op_depth;
SVN_ERR(insert_working_node(&iwb, dst_wcroot, dst_relpath, scratch_pool));
SVN_ERR(copy_actual(src_wcroot, src_relpath,
dst_wcroot, dst_relpath, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
get_moved_to(const char **moved_to_relpath_p,
const char **moved_to_op_root_relpath_p,
svn_boolean_t *scan,
svn_sqlite__stmt_t *stmt,
const char *current_relpath,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *moved_to_relpath = svn_sqlite__column_text(stmt, 3, NULL);
if (moved_to_relpath)
{
const char *moved_to_op_root_relpath = moved_to_relpath;
if (strcmp(current_relpath, local_relpath))
{
const char *moved_child_relpath;
moved_child_relpath = svn_relpath_skip_ancestor(current_relpath,
local_relpath);
SVN_ERR_ASSERT(moved_child_relpath &&
strlen(moved_child_relpath) > 0);
moved_to_relpath = svn_relpath_join(moved_to_op_root_relpath,
moved_child_relpath,
result_pool);
}
if (moved_to_op_root_relpath && moved_to_op_root_relpath_p)
*moved_to_op_root_relpath_p
= apr_pstrdup(result_pool, moved_to_op_root_relpath);
if (moved_to_relpath && moved_to_relpath_p)
*moved_to_relpath_p
= apr_pstrdup(result_pool, moved_to_relpath);
*scan = FALSE;
}
return SVN_NO_ERROR;
}
static svn_error_t *
scan_deletion(const char **base_del_relpath,
const char **moved_to_relpath,
const char **work_del_relpath,
const char **moved_to_op_root_relpath,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *current_relpath = local_relpath;
svn_sqlite__stmt_t *stmt;
svn_wc__db_status_t work_presence;
svn_boolean_t have_row, scan, have_base;
int op_depth;
if (base_del_relpath != NULL)
*base_del_relpath = NULL;
if (moved_to_relpath != NULL)
*moved_to_relpath = NULL;
if (work_del_relpath != NULL)
*work_del_relpath = NULL;
if (moved_to_op_root_relpath != NULL)
*moved_to_op_root_relpath = NULL;
scan = (moved_to_op_root_relpath || moved_to_relpath);
SVN_ERR(svn_sqlite__get_statement(
&stmt, wcroot->sdb, STMT_SELECT_DELETION_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, svn_sqlite__reset(stmt),
_("The node '%s' was not found."),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
work_presence = svn_sqlite__column_token(stmt, 1, presence_map);
have_base = !svn_sqlite__column_is_null(stmt, 0);
if (work_presence != svn_wc__db_status_not_present
&& work_presence != svn_wc__db_status_base_deleted)
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS,
svn_sqlite__reset(stmt),
_("Expected node '%s' to be deleted."),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
op_depth = svn_sqlite__column_int(stmt, 2);
if (work_presence == svn_wc__db_status_not_present
&& work_del_relpath && !*work_del_relpath)
{
*work_del_relpath = apr_pstrdup(result_pool, current_relpath);
if (!scan && !base_del_relpath)
{
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
}
while (TRUE)
{
svn_error_t *err;
const char *parent_relpath;
int current_depth = relpath_depth(current_relpath);
while (TRUE)
{
if (scan)
{
err = get_moved_to(moved_to_relpath, moved_to_op_root_relpath,
&scan, stmt, current_relpath,
wcroot, local_relpath,
result_pool, scratch_pool);
if (err || (!scan
&& !base_del_relpath
&& !work_del_relpath))
{
SVN_ERR(svn_sqlite__reset(stmt));
return svn_error_trace(err);
}
}
if (current_depth <= op_depth)
break;
current_relpath = svn_relpath_dirname(current_relpath, scratch_pool);
--current_depth;
if (scan || current_depth == op_depth)
{
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
current_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
SVN_ERR_ASSERT(have_row);
have_base = !svn_sqlite__column_is_null(stmt, 0);
}
}
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR_ASSERT(current_relpath[0] != '\0');
parent_relpath = svn_relpath_dirname(current_relpath, scratch_pool);
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
{
if (have_base && base_del_relpath)
*base_del_relpath = apr_pstrdup(result_pool, current_relpath);
break;
}
if (work_del_relpath && !*work_del_relpath)
{
*work_del_relpath = apr_pstrdup(result_pool, current_relpath);
if (!scan && !base_del_relpath)
break;
}
current_relpath = parent_relpath;
op_depth = svn_sqlite__column_int(stmt, 2);
have_base = !svn_sqlite__column_is_null(stmt, 0);
}
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_scan_deletion_internal(
const char **base_del_relpath,
const char **moved_to_relpath,
const char **work_del_relpath,
const char **moved_to_op_root_relpath,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
return svn_error_trace(
scan_deletion(base_del_relpath, moved_to_relpath, work_del_relpath,
moved_to_op_root_relpath,
wcroot, local_relpath,
result_pool, scratch_pool));
}
svn_error_t *
svn_wc__db_scan_deletion(const char **base_del_abspath,
const char **moved_to_abspath,
const char **work_del_abspath,
const char **moved_to_op_root_abspath,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
const char *base_del_relpath, *moved_to_relpath, *work_del_relpath;
const char *moved_to_op_root_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
scan_deletion(&base_del_relpath, &moved_to_relpath,
&work_del_relpath, &moved_to_op_root_relpath,
wcroot, local_relpath, result_pool, scratch_pool),
wcroot);
if (base_del_abspath)
{
*base_del_abspath = (base_del_relpath
? svn_dirent_join(wcroot->abspath,
base_del_relpath, result_pool)
: NULL);
}
if (moved_to_abspath)
{
*moved_to_abspath = (moved_to_relpath
? svn_dirent_join(wcroot->abspath,
moved_to_relpath, result_pool)
: NULL);
}
if (work_del_abspath)
{
*work_del_abspath = (work_del_relpath
? svn_dirent_join(wcroot->abspath,
work_del_relpath, result_pool)
: NULL);
}
if (moved_to_op_root_abspath)
{
*moved_to_op_root_abspath = (moved_to_op_root_relpath
? svn_dirent_join(wcroot->abspath,
moved_to_op_root_relpath,
result_pool)
: NULL);
}
return SVN_NO_ERROR;
}
static svn_error_t *
get_info_for_copy(apr_int64_t *copyfrom_id,
const char **copyfrom_relpath,
svn_revnum_t *copyfrom_rev,
svn_wc__db_status_t *status,
svn_node_kind_t *kind,
svn_boolean_t *op_root,
svn_wc__db_wcroot_t *src_wcroot,
const char *local_relpath,
svn_wc__db_wcroot_t *dst_wcroot,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *repos_relpath;
svn_revnum_t revision;
svn_wc__db_status_t node_status;
apr_int64_t repos_id;
svn_boolean_t is_op_root;
SVN_ERR(read_info(&node_status, kind, &revision, &repos_relpath, &repos_id,
NULL, NULL, NULL, NULL, NULL, NULL, copyfrom_relpath,
copyfrom_id, copyfrom_rev, NULL, NULL, NULL, NULL,
NULL, &is_op_root, NULL, NULL,
NULL ,
NULL ,
NULL ,
src_wcroot, local_relpath, result_pool, scratch_pool));
if (op_root)
*op_root = is_op_root;
if (node_status == svn_wc__db_status_excluded)
{
const char *parent_relpath, *base_name;
svn_dirent_split(&parent_relpath, &base_name, local_relpath,
scratch_pool);
SVN_ERR(get_info_for_copy(copyfrom_id, copyfrom_relpath, copyfrom_rev,
NULL, NULL, NULL,
src_wcroot, parent_relpath, dst_wcroot,
scratch_pool, scratch_pool));
if (*copyfrom_relpath)
*copyfrom_relpath = svn_relpath_join(*copyfrom_relpath, base_name,
result_pool);
}
else if (node_status == svn_wc__db_status_added)
{
SVN_ERR(scan_addition(&node_status, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, src_wcroot, local_relpath,
scratch_pool, scratch_pool));
}
else if (node_status == svn_wc__db_status_deleted && is_op_root)
{
const char *base_del_relpath, *work_del_relpath;
SVN_ERR(scan_deletion(&base_del_relpath, NULL,
&work_del_relpath,
NULL, src_wcroot, local_relpath,
scratch_pool, scratch_pool));
if (work_del_relpath)
{
const char *op_root_relpath;
const char *parent_del_relpath = svn_relpath_dirname(work_del_relpath,
scratch_pool);
SVN_ERR(scan_addition(NULL, &op_root_relpath,
NULL, NULL,
copyfrom_relpath, copyfrom_id, copyfrom_rev,
NULL, NULL, NULL,
src_wcroot, parent_del_relpath,
scratch_pool, scratch_pool));
*copyfrom_relpath
= svn_relpath_join(*copyfrom_relpath,
svn_relpath_skip_ancestor(op_root_relpath,
local_relpath),
result_pool);
}
else if (base_del_relpath)
{
SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, copyfrom_rev,
copyfrom_relpath,
copyfrom_id, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
src_wcroot, local_relpath,
result_pool,
scratch_pool));
}
else
SVN_ERR_MALFUNCTION();
}
else if (node_status == svn_wc__db_status_deleted)
{
}
else
{
*copyfrom_relpath = repos_relpath;
*copyfrom_rev = revision;
*copyfrom_id = repos_id;
}
if (status)
*status = node_status;
if (src_wcroot != dst_wcroot && *copyfrom_relpath)
{
const char *repos_root_url;
const char *repos_uuid;
SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, &repos_uuid,
src_wcroot, *copyfrom_id,
scratch_pool));
SVN_ERR(create_repos_id(copyfrom_id, repos_root_url, repos_uuid,
dst_wcroot->sdb, scratch_pool));
}
return SVN_NO_ERROR;
}
static svn_error_t *
op_depth_of(int *op_depth,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
SVN_ERR_ASSERT(have_row);
*op_depth = svn_sqlite__column_int(stmt, 0);
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
static svn_error_t *
op_depth_for_copy(int *op_depth,
int *np_op_depth,
int *parent_op_depth,
apr_int64_t copyfrom_repos_id,
const char *copyfrom_relpath,
svn_revnum_t copyfrom_revision,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
const char *parent_relpath, *name;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
int incomplete_op_depth = -1;
int min_op_depth = 1;
*op_depth = relpath_depth(local_relpath);
*np_op_depth = -1;
svn_relpath_split(&parent_relpath, &name, local_relpath, scratch_pool);
*parent_op_depth = relpath_depth(parent_relpath);
if (!copyfrom_relpath)
return SVN_NO_ERROR;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_WORKING_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
svn_wc__db_status_t status = svn_sqlite__column_token(stmt, 1,
presence_map);
min_op_depth = svn_sqlite__column_int(stmt, 0);
if (status == svn_wc__db_status_incomplete)
incomplete_op_depth = min_op_depth;
}
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_WORKING_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
svn_wc__db_status_t presence = svn_sqlite__column_token(stmt, 1,
presence_map);
*parent_op_depth = svn_sqlite__column_int(stmt, 0);
if (*parent_op_depth < min_op_depth)
{
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
SVN_ERR_ASSERT(presence == svn_wc__db_status_normal);
if ((incomplete_op_depth < 0)
|| (incomplete_op_depth == *parent_op_depth))
{
apr_int64_t parent_copyfrom_repos_id
= svn_sqlite__column_int64(stmt, 10);
const char *parent_copyfrom_relpath
= svn_sqlite__column_text(stmt, 11, NULL);
svn_revnum_t parent_copyfrom_revision
= svn_sqlite__column_revnum(stmt, 12);
if (parent_copyfrom_repos_id == copyfrom_repos_id)
{
if (copyfrom_revision == parent_copyfrom_revision
&& !strcmp(copyfrom_relpath,
svn_relpath_join(parent_copyfrom_relpath, name,
scratch_pool)))
*op_depth = *parent_op_depth;
else if (incomplete_op_depth > 0)
*np_op_depth = incomplete_op_depth;
}
}
}
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
static svn_error_t *
db_op_copy(svn_wc__db_wcroot_t *src_wcroot,
const char *src_relpath,
svn_wc__db_wcroot_t *dst_wcroot,
const char *dst_relpath,
const svn_skel_t *work_items,
int move_op_depth,
apr_pool_t *scratch_pool)
{
const char *copyfrom_relpath;
svn_revnum_t copyfrom_rev;
svn_wc__db_status_t status;
svn_wc__db_status_t dst_presence;
svn_boolean_t op_root;
apr_int64_t copyfrom_id;
int dst_op_depth;
int dst_np_op_depth;
int dst_parent_op_depth;
svn_node_kind_t kind;
const apr_array_header_t *children;
SVN_ERR(get_info_for_copy(©from_id, ©from_relpath, ©from_rev,
&status, &kind, &op_root,
src_wcroot, src_relpath, dst_wcroot,
scratch_pool, scratch_pool));
SVN_ERR(op_depth_for_copy(&dst_op_depth, &dst_np_op_depth,
&dst_parent_op_depth,
copyfrom_id, copyfrom_relpath, copyfrom_rev,
dst_wcroot, dst_relpath, scratch_pool));
SVN_ERR_ASSERT(kind == svn_node_file || kind == svn_node_dir);
switch (status)
{
case svn_wc__db_status_normal:
case svn_wc__db_status_added:
case svn_wc__db_status_moved_here:
case svn_wc__db_status_copied:
dst_presence = svn_wc__db_status_normal;
break;
case svn_wc__db_status_deleted:
if (op_root)
{
svn_error_t *err;
svn_wc__db_status_t dst_status;
err = read_info(&dst_status, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
dst_wcroot, dst_relpath, scratch_pool, scratch_pool);
if (err)
{
if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
svn_error_clear(err);
else
return svn_error_trace(err);
}
else if (dst_status == svn_wc__db_status_deleted)
{
SVN_ERR(add_work_items(dst_wcroot->sdb, work_items,
scratch_pool));
return SVN_NO_ERROR;
}
}
else
{
if (! copyfrom_relpath)
{
SVN_ERR(add_work_items(dst_wcroot->sdb, work_items,
scratch_pool));
return SVN_NO_ERROR;
}
}
case svn_wc__db_status_not_present:
case svn_wc__db_status_excluded:
if (dst_np_op_depth > 0)
{
dst_op_depth = dst_np_op_depth;
dst_np_op_depth = -1;
}
if (status == svn_wc__db_status_excluded)
dst_presence = svn_wc__db_status_excluded;
else
dst_presence = svn_wc__db_status_not_present;
break;
case svn_wc__db_status_server_excluded:
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
_("Cannot copy '%s' excluded by server"),
path_for_error_message(src_wcroot,
src_relpath,
scratch_pool));
default:
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
_("Cannot handle status of '%s'"),
path_for_error_message(src_wcroot,
src_relpath,
scratch_pool));
}
if (kind == svn_node_dir)
{
int src_op_depth;
SVN_ERR(op_depth_of(&src_op_depth, src_wcroot, src_relpath));
SVN_ERR(gather_children(&children, src_wcroot, src_relpath,
STMT_SELECT_OP_DEPTH_CHILDREN, src_op_depth,
scratch_pool, scratch_pool));
}
else
children = NULL;
if (src_wcroot == dst_wcroot)
{
svn_sqlite__stmt_t *stmt;
const char *dst_parent_relpath = svn_relpath_dirname(dst_relpath,
scratch_pool);
SVN_ERR(svn_sqlite__get_statement(&stmt, src_wcroot->sdb,
STMT_INSERT_WORKING_NODE_COPY_FROM));
SVN_ERR(svn_sqlite__bindf(stmt, "issdst",
src_wcroot->wc_id, src_relpath,
dst_relpath,
dst_op_depth,
dst_parent_relpath,
presence_map, dst_presence));
if (move_op_depth > 0)
{
if (relpath_depth(dst_relpath) == move_op_depth)
{
if (!(status == svn_wc__db_status_added ||
(status == svn_wc__db_status_copied && op_root)))
SVN_ERR(svn_sqlite__bind_int(stmt, 7, 1));
}
else
{
svn_sqlite__stmt_t *info_stmt;
svn_boolean_t have_row;
SVN_ERR(svn_sqlite__get_statement(&info_stmt, dst_wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(info_stmt, "is", dst_wcroot->wc_id,
dst_parent_relpath));
SVN_ERR(svn_sqlite__step(&have_row, info_stmt));
SVN_ERR_ASSERT(have_row);
if (svn_sqlite__column_boolean(info_stmt, 15) &&
dst_op_depth == dst_parent_op_depth)
{
SVN_ERR(svn_sqlite__bind_int(stmt, 7, 1));
SVN_ERR(svn_sqlite__reset(info_stmt));
}
else
{
SVN_ERR(svn_sqlite__reset(info_stmt));
SVN_ERR(svn_sqlite__get_statement(&info_stmt,
dst_wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(info_stmt, "is",
dst_wcroot->wc_id, src_relpath));
SVN_ERR(svn_sqlite__step(&have_row, info_stmt));
SVN_ERR_ASSERT(have_row);
if (svn_sqlite__column_boolean(info_stmt, 15))
SVN_ERR(svn_sqlite__bind_int(stmt, 7, 1));
SVN_ERR(svn_sqlite__reset(info_stmt));
}
}
}
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(copy_actual(src_wcroot, src_relpath,
dst_wcroot, dst_relpath, scratch_pool));
if (dst_np_op_depth > 0)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, dst_wcroot->sdb,
STMT_INSERT_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "isdsisrtnt",
src_wcroot->wc_id, dst_relpath,
dst_np_op_depth, dst_parent_relpath,
copyfrom_id, copyfrom_relpath,
copyfrom_rev,
presence_map,
svn_wc__db_status_not_present,
kind_map, kind));
SVN_ERR(svn_sqlite__step_done(stmt));
}
if (kind == svn_node_dir
&& dst_presence == svn_wc__db_status_normal)
SVN_ERR(insert_incomplete_children(
dst_wcroot->sdb,
dst_wcroot->wc_id,
dst_relpath,
copyfrom_id,
copyfrom_relpath,
copyfrom_rev,
children,
dst_op_depth,
scratch_pool));
}
else
{
SVN_ERR(cross_db_copy(src_wcroot, src_relpath, dst_wcroot,
dst_relpath, dst_presence, dst_op_depth,
dst_np_op_depth, kind,
children, copyfrom_id, copyfrom_relpath,
copyfrom_rev, scratch_pool));
}
SVN_ERR(add_work_items(dst_wcroot->sdb, work_items, scratch_pool));
return SVN_NO_ERROR;
}
struct op_copy_baton
{
svn_wc__db_wcroot_t *src_wcroot;
const char *src_relpath;
svn_wc__db_wcroot_t *dst_wcroot;
const char *dst_relpath;
const svn_skel_t *work_items;
svn_boolean_t is_move;
const char *dst_op_root_relpath;
};
static svn_error_t *
op_copy_txn(svn_wc__db_wcroot_t *wcroot,
struct op_copy_baton *ocb,
apr_pool_t *scratch_pool)
{
int move_op_depth;
if (wcroot != ocb->dst_wcroot)
{
SVN_WC__DB_WITH_TXN(op_copy_txn(ocb->dst_wcroot, ocb, scratch_pool),
ocb->dst_wcroot);
return SVN_NO_ERROR;
}
if (ocb->is_move)
move_op_depth = relpath_depth(ocb->dst_op_root_relpath);
else
move_op_depth = 0;
SVN_ERR(db_op_copy(ocb->src_wcroot, ocb->src_relpath,
ocb->dst_wcroot, ocb->dst_relpath,
ocb->work_items, move_op_depth, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_copy(svn_wc__db_t *db,
const char *src_abspath,
const char *dst_abspath,
const char *dst_op_root_abspath,
svn_boolean_t is_move,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
struct op_copy_baton ocb = {0};
SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath));
SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_op_root_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&ocb.src_wcroot,
&ocb.src_relpath, db,
src_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(ocb.src_wcroot);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&ocb.dst_wcroot,
&ocb.dst_relpath,
db, dst_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(ocb.dst_wcroot);
ocb.work_items = work_items;
ocb.is_move = is_move;
ocb.dst_op_root_relpath = svn_dirent_skip_ancestor(ocb.dst_wcroot->abspath,
dst_op_root_abspath);
SVN_WC__DB_WITH_TXN(op_copy_txn(ocb.src_wcroot, &ocb, scratch_pool),
ocb.src_wcroot);
return SVN_NO_ERROR;
}
static svn_error_t *
clear_or_remove_actual(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
int op_depth,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row, shadowed;
svn_boolean_t keep_conflict = FALSE;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
svn_wc__db_status_t presence;
shadowed = (svn_sqlite__column_int(stmt, 0) > op_depth);
presence = svn_sqlite__column_token(stmt, 3, presence_map);
if (shadowed && presence == svn_wc__db_status_base_deleted)
{
keep_conflict = TRUE;
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
shadowed = (svn_sqlite__column_int(stmt, 0) > op_depth);
else
shadowed = FALSE;
}
}
else
shadowed = FALSE;
SVN_ERR(svn_sqlite__reset(stmt));
if (shadowed)
return SVN_NO_ERROR;
if (keep_conflict)
{
SVN_ERR(svn_sqlite__get_statement(
&stmt, wcroot->sdb,
STMT_CLEAR_ACTUAL_NODE_LEAVING_CONFLICT));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_EMPTY));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
else
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_copy_layer_internal(svn_wc__db_wcroot_t *wcroot,
const char *src_op_relpath,
int src_op_depth,
const char *dst_op_relpath,
svn_skel_t *conflict,
svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt, *stmt2;
svn_boolean_t have_row;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
int dst_op_depth = relpath_depth(dst_op_relpath);
svn_boolean_t locked;
svn_error_t *err = NULL;
SVN_ERR(svn_wc__db_wclock_owns_lock_internal(&locked, wcroot, dst_op_relpath,
FALSE, scratch_pool));
if (!locked)
return svn_error_createf(SVN_ERR_WC_NOT_LOCKED, NULL,
_("No write-lock in '%s'"),
path_for_error_message(wcroot, dst_op_relpath,
scratch_pool));
SVN_ERR(svn_sqlite__get_statement(&stmt2, wcroot->sdb,
STMT_COPY_NODE_MOVE));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_LAYER_FOR_REPLACE));
SVN_ERR(svn_sqlite__bindf(stmt, "isdsd", wcroot->wc_id,
src_op_relpath, src_op_depth,
dst_op_relpath, dst_op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
const char *src_relpath;
const char *dst_relpath;
svn_pool_clear(iterpool);
src_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
dst_relpath = svn_sqlite__column_text(stmt, 2, iterpool);
err = svn_sqlite__bindf(stmt2, "isdsds", wcroot->wc_id,
src_relpath, src_op_depth,
dst_relpath, dst_op_depth,
svn_relpath_dirname(dst_relpath, iterpool));
if (!err)
err = svn_sqlite__step_done(stmt2);
if (err)
break;
if (relpath_depth(dst_relpath) > (dst_op_depth+1))
{
svn_boolean_t exists = !svn_sqlite__column_is_null(stmt, 3);
if (exists)
{
svn_wc__db_status_t presence;
presence = svn_sqlite__column_token(stmt, 3, presence_map);
if (presence != svn_wc__db_status_normal)
exists = FALSE;
}
if (!exists)
{
svn_node_kind_t kind = svn_sqlite__column_token(stmt, 1, kind_map);
err = db_extend_parent_delete(wcroot, dst_relpath,
kind, dst_op_depth, iterpool);
if (err)
break;
}
}
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NO_LONGER_MOVED_RV));
SVN_ERR(svn_sqlite__bindf(stmt, "isdsd", wcroot->wc_id,
dst_op_relpath, dst_op_depth,
src_op_relpath, src_op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
const char *dst_relpath;
svn_wc__db_status_t shadowed_presence;
svn_pool_clear(iterpool);
dst_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
if (!svn_sqlite__column_is_null(stmt, 2))
shadowed_presence = svn_sqlite__column_token(stmt, 2, presence_map);
else
shadowed_presence = svn_wc__db_status_not_present;
if (shadowed_presence != svn_wc__db_status_normal
&& shadowed_presence != svn_wc__db_status_incomplete)
{
err = svn_sqlite__get_statement(&stmt2, wcroot->sdb,
STMT_DELETE_NODE);
}
else
{
err =svn_sqlite__get_statement(&stmt2, wcroot->sdb,
STMT_REPLACE_WITH_BASE_DELETED);
}
if (!err)
err = svn_sqlite__bindf(stmt2, "isd", wcroot->wc_id, dst_relpath,
dst_op_depth);
if (!err)
err = svn_sqlite__step_done(stmt2);
if (err)
break;
err = clear_or_remove_actual(wcroot, dst_relpath, dst_op_depth,
scratch_pool);
if (err)
break;
err = db_retract_parent_delete(wcroot, dst_relpath, dst_op_depth,
scratch_pool);
if (err)
break;
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
svn_pool_destroy(iterpool);
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
if (conflict)
SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, dst_op_relpath ,
conflict, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
handle_move_back(svn_boolean_t *moved_back,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
const char *moved_from_relpath,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_wc__db_status_t status;
svn_boolean_t op_root;
svn_boolean_t have_more_work;
int from_op_depth = 0;
svn_boolean_t have_row;
svn_boolean_t different = FALSE;
SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
SVN_ERR(svn_wc__db_read_info_internal(&status, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&op_root, NULL, NULL, NULL,
&have_more_work, NULL,
wcroot, local_relpath,
scratch_pool, scratch_pool));
if (status != svn_wc__db_status_added || !op_root)
return SVN_NO_ERROR;
if (have_more_work)
SVN_ERR(op_depth_of(&from_op_depth, wcroot,
svn_relpath_dirname(local_relpath, scratch_pool)));
else
from_op_depth = 0;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MOVED_BACK));
SVN_ERR(svn_sqlite__bindf(stmt, "isdd", wcroot->wc_id,
local_relpath,
from_op_depth,
relpath_depth(local_relpath)));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
SVN_ERR_ASSERT(have_row);
{
svn_boolean_t moved_here = svn_sqlite__column_boolean(stmt, 9);
const char *moved_to = svn_sqlite__column_text(stmt, 10, NULL);
if (!moved_here
|| !moved_to
|| strcmp(moved_to, moved_from_relpath))
{
different = TRUE;
have_row = FALSE;
}
}
while (have_row)
{
svn_wc__db_status_t upper_status;
svn_wc__db_status_t lower_status;
upper_status = svn_sqlite__column_token(stmt, 1, presence_map);
if (svn_sqlite__column_is_null(stmt, 5))
{
if (upper_status != svn_wc__db_status_not_present)
{
different = TRUE;
break;
}
continue;
}
lower_status = svn_sqlite__column_token(stmt, 5, presence_map);
if (upper_status != lower_status)
{
different = TRUE;
break;
}
if (upper_status == svn_wc__db_status_not_present
|| upper_status == svn_wc__db_status_excluded)
{
SVN_ERR(svn_sqlite__step(&have_row, stmt));
continue;
}
else if (upper_status != svn_wc__db_status_normal)
{
different = TRUE;
break;
}
{
const char *upper_repos_relpath;
const char *lower_repos_relpath;
upper_repos_relpath = svn_sqlite__column_text(stmt, 3, NULL);
lower_repos_relpath = svn_sqlite__column_text(stmt, 7, NULL);
if (! upper_repos_relpath
|| strcmp(upper_repos_relpath, lower_repos_relpath))
{
different = TRUE;
break;
}
}
{
svn_revnum_t upper_rev;
svn_revnum_t lower_rev;
upper_rev = svn_sqlite__column_revnum(stmt, 4);
lower_rev = svn_sqlite__column_revnum(stmt, 8);
if (upper_rev != lower_rev)
{
different = TRUE;
break;
}
}
{
apr_int64_t upper_repos_id;
apr_int64_t lower_repos_id;
upper_repos_id = svn_sqlite__column_int64(stmt, 2);
lower_repos_id = svn_sqlite__column_int64(stmt, 6);
if (upper_repos_id != lower_repos_id)
{
different = TRUE;
break;
}
}
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
if (! different)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_WORKING_OP_DEPTH));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
local_relpath,
relpath_depth(local_relpath)));
SVN_ERR(svn_sqlite__step_done(stmt));
if (moved_back)
*moved_back = TRUE;
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_handle_move_back(svn_boolean_t *moved_back,
svn_wc__db_t *db,
const char *local_abspath,
const char *moved_from_abspath,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
const char *moved_from_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
if (moved_back)
*moved_back = FALSE;
moved_from_relpath = svn_dirent_skip_ancestor(wcroot->abspath,
moved_from_abspath);
if (! local_relpath[0]
|| !moved_from_relpath)
{
SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
return SVN_NO_ERROR;
}
SVN_WC__DB_WITH_TXN(handle_move_back(moved_back, wcroot, local_relpath,
moved_from_relpath, work_items,
scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_infinity,
scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
db_op_copy_shadowed_layer(svn_wc__db_wcroot_t *src_wcroot,
const char *src_relpath,
int src_op_depth,
svn_wc__db_wcroot_t *dst_wcroot,
const char *dst_relpath,
int dst_op_depth,
int del_op_depth,
apr_int64_t repos_id,
const char *repos_relpath,
svn_revnum_t revision,
int move_op_depth,
apr_pool_t *scratch_pool)
{
const apr_array_header_t *children;
apr_pool_t *iterpool;
svn_wc__db_status_t status;
svn_node_kind_t kind;
svn_revnum_t node_revision;
const char *node_repos_relpath;
apr_int64_t node_repos_id;
svn_sqlite__stmt_t *stmt;
svn_wc__db_status_t dst_presence;
int i;
{
svn_error_t *err;
err = svn_wc__db_depth_get_info(&status, &kind, &node_revision,
&node_repos_relpath, &node_repos_id,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL,
src_wcroot, src_relpath, src_op_depth,
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);
return SVN_NO_ERROR;
}
}
if (src_op_depth == 0)
{
if (status == svn_wc__db_status_not_present
|| status == svn_wc__db_status_excluded
|| status == svn_wc__db_status_server_excluded
|| node_revision != revision
|| node_repos_id != repos_id
|| strcmp(node_repos_relpath, repos_relpath))
{
struct insert_working_baton_t iwb;
const char *repos_root_url;
const char *repos_uuid;
SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, &repos_uuid,
src_wcroot, node_repos_id,
scratch_pool));
SVN_ERR(create_repos_id(&node_repos_id, repos_root_url, repos_uuid,
dst_wcroot->sdb, scratch_pool));
blank_iwb(&iwb);
iwb.op_depth = dst_op_depth;
if (status != svn_wc__db_status_excluded)
iwb.presence = svn_wc__db_status_not_present;
else
iwb.presence = svn_wc__db_status_excluded;
iwb.kind = kind;
iwb.original_repos_id = node_repos_id;
iwb.original_revnum = node_revision;
iwb.original_repos_relpath = node_repos_relpath;
SVN_ERR(insert_working_node(&iwb, dst_wcroot, dst_relpath,
scratch_pool));
return SVN_NO_ERROR;
}
}
iterpool = svn_pool_create(scratch_pool);
switch (status)
{
case svn_wc__db_status_normal:
case svn_wc__db_status_added:
case svn_wc__db_status_moved_here:
case svn_wc__db_status_copied:
dst_presence = svn_wc__db_status_normal;
break;
case svn_wc__db_status_deleted:
case svn_wc__db_status_not_present:
dst_presence = svn_wc__db_status_not_present;
break;
case svn_wc__db_status_excluded:
dst_presence = svn_wc__db_status_excluded;
break;
case svn_wc__db_status_server_excluded:
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
_("Cannot copy '%s' excluded by server"),
path_for_error_message(src_wcroot,
src_relpath,
scratch_pool));
default:
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
_("Cannot handle status of '%s'"),
path_for_error_message(src_wcroot,
src_relpath,
scratch_pool));
}
if (dst_presence == svn_wc__db_status_normal
&& src_wcroot == dst_wcroot)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, src_wcroot->sdb,
STMT_INSERT_WORKING_NODE_COPY_FROM_DEPTH));
SVN_ERR(svn_sqlite__bindf(stmt, "issdstd",
src_wcroot->wc_id, src_relpath,
dst_relpath,
dst_op_depth,
svn_relpath_dirname(dst_relpath, iterpool),
presence_map, dst_presence,
src_op_depth));
if (dst_op_depth == move_op_depth)
SVN_ERR(svn_sqlite__bind_int(stmt, 8, TRUE));
SVN_ERR(svn_sqlite__step_done(stmt));
{
struct insert_working_baton_t iwb;
blank_iwb(&iwb);
iwb.op_depth = del_op_depth;
iwb.presence = svn_wc__db_status_base_deleted;
iwb.kind = kind;
SVN_ERR(insert_working_node(&iwb, dst_wcroot, dst_relpath,
scratch_pool));
}
}
else
{
struct insert_working_baton_t iwb;
if (dst_presence == svn_wc__db_status_normal)
dst_presence = svn_wc__db_status_not_present;
blank_iwb(&iwb);
iwb.op_depth = dst_op_depth;
iwb.presence = dst_presence;
iwb.kind = kind;
SVN_ERR(insert_working_node(&iwb, dst_wcroot, dst_relpath,
scratch_pool));
}
if (dst_presence == svn_wc__db_status_not_present)
{
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
SVN_ERR(gather_children(&children, src_wcroot, src_relpath,
STMT_SELECT_OP_DEPTH_CHILDREN, src_op_depth,
scratch_pool, iterpool));
for (i = 0; i < children->nelts; i++)
{
const char *name = APR_ARRAY_IDX(children, i, const char *);
const char *child_src_relpath;
const char *child_dst_relpath;
const char *child_repos_relpath = NULL;
svn_pool_clear(iterpool);
child_src_relpath = svn_relpath_join(src_relpath, name, iterpool);
child_dst_relpath = svn_relpath_join(dst_relpath, name, iterpool);
if (repos_relpath)
child_repos_relpath = svn_relpath_join(repos_relpath, name, iterpool);
SVN_ERR(db_op_copy_shadowed_layer(
src_wcroot, child_src_relpath, src_op_depth,
dst_wcroot, child_dst_relpath, dst_op_depth,
del_op_depth,
repos_id, child_repos_relpath, revision,
move_op_depth, scratch_pool));
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
static svn_error_t *
op_copy_shadowed_layer_txn(svn_wc__db_wcroot_t *wcroot,
struct op_copy_baton *ocb,
apr_pool_t *scratch_pool)
{
const char *src_parent_relpath;
const char *dst_parent_relpath;
int src_op_depth;
int dst_op_depth;
int del_op_depth;
const char *repos_relpath = NULL;
apr_int64_t repos_id = INVALID_REPOS_ID;
svn_revnum_t revision = SVN_INVALID_REVNUM;
if (wcroot != ocb->dst_wcroot)
{
SVN_WC__DB_WITH_TXN(op_copy_shadowed_layer_txn(ocb->dst_wcroot, ocb,
scratch_pool),
ocb->dst_wcroot);
return SVN_NO_ERROR;
}
SVN_ERR_ASSERT(*ocb->src_relpath && *ocb->dst_relpath);
src_parent_relpath = svn_relpath_dirname(ocb->src_relpath, scratch_pool);
dst_parent_relpath = svn_relpath_dirname(ocb->dst_relpath, scratch_pool);
SVN_ERR(op_depth_of(&src_op_depth, ocb->src_wcroot, src_parent_relpath));
SVN_ERR(op_depth_of(&dst_op_depth, ocb->dst_wcroot, dst_parent_relpath));
del_op_depth = relpath_depth(ocb->dst_relpath);
SVN_ERR(svn_wc__db_depth_get_info(NULL, NULL, &revision, &repos_relpath,
&repos_id, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
ocb->src_wcroot,
src_parent_relpath, src_op_depth,
scratch_pool, scratch_pool));
if (repos_relpath == NULL)
{
return SVN_NO_ERROR;
}
repos_relpath = svn_relpath_join(repos_relpath,
svn_relpath_basename(ocb->src_relpath,
NULL),
scratch_pool);
SVN_ERR(db_op_copy_shadowed_layer(
ocb->src_wcroot, ocb->src_relpath, src_op_depth,
ocb->dst_wcroot, ocb->dst_relpath, dst_op_depth,
del_op_depth,
repos_id, repos_relpath, revision,
(ocb->is_move ? dst_op_depth : 0),
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_copy_shadowed_layer(svn_wc__db_t *db,
const char *src_abspath,
const char *dst_abspath,
svn_boolean_t is_move,
apr_pool_t *scratch_pool)
{
struct op_copy_baton ocb = {0};
SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath));
SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&ocb.src_wcroot,
&ocb.src_relpath, db,
src_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(ocb.src_wcroot);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&ocb.dst_wcroot,
&ocb.dst_relpath,
db, dst_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(ocb.dst_wcroot);
ocb.is_move = is_move;
ocb.dst_op_root_relpath = NULL;
ocb.work_items = NULL;
SVN_WC__DB_WITH_TXN(op_copy_shadowed_layer_txn(ocb.src_wcroot, &ocb,
scratch_pool),
ocb.src_wcroot);
return SVN_NO_ERROR;
}
static svn_error_t *
catch_copy_of_server_excluded(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
const char *server_excluded_relpath;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_HAS_SERVER_EXCLUDED_DESCENDANTS));
SVN_ERR(svn_sqlite__bindf(stmt, "is",
wcroot->wc_id,
local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
server_excluded_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
SVN_ERR(svn_sqlite__reset(stmt));
if (have_row)
return svn_error_createf(SVN_ERR_AUTHZ_UNREADABLE, NULL,
_("Cannot copy '%s' excluded by server"),
path_for_error_message(wcroot,
server_excluded_relpath,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_copy_dir(svn_wc__db_t *db,
const char *local_abspath,
const apr_hash_t *props,
svn_revnum_t changed_rev,
apr_time_t changed_date,
const char *changed_author,
const char *original_repos_relpath,
const char *original_root_url,
const char *original_uuid,
svn_revnum_t original_revision,
const apr_array_header_t *children,
svn_depth_t depth,
svn_boolean_t is_move,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
insert_working_baton_t iwb;
int parent_op_depth;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(props != NULL);
#if 0
SVN_ERR_ASSERT(children != NULL);
#endif
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
blank_iwb(&iwb);
iwb.presence = svn_wc__db_status_normal;
iwb.kind = svn_node_dir;
if (original_root_url != NULL)
{
SVN_ERR(create_repos_id(&iwb.original_repos_id,
original_root_url, original_uuid,
wcroot->sdb, scratch_pool));
iwb.original_repos_relpath = original_repos_relpath;
iwb.original_revnum = original_revision;
iwb.props = props;
iwb.changed_rev = changed_rev;
iwb.changed_date = changed_date;
iwb.changed_author = changed_author;
}
SVN_ERR(op_depth_for_copy(&iwb.op_depth, &iwb.not_present_op_depth,
&parent_op_depth, iwb.original_repos_id,
original_repos_relpath, original_revision,
wcroot, local_relpath, scratch_pool));
iwb.children = children;
iwb.depth = depth;
iwb.moved_here = is_move && (parent_op_depth == 0 ||
iwb.op_depth == parent_op_depth);
iwb.work_items = work_items;
iwb.conflict = conflict;
SVN_WC__DB_WITH_TXN(
insert_working_node(&iwb, wcroot, local_relpath, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, depth, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_copy_file(svn_wc__db_t *db,
const char *local_abspath,
const apr_hash_t *props,
svn_revnum_t changed_rev,
apr_time_t changed_date,
const char *changed_author,
const char *original_repos_relpath,
const char *original_root_url,
const char *original_uuid,
svn_revnum_t original_revision,
const svn_checksum_t *checksum,
svn_boolean_t update_actual_props,
const apr_hash_t *new_actual_props,
svn_boolean_t is_move,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
insert_working_baton_t iwb;
int parent_op_depth;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(props != NULL);
SVN_ERR_ASSERT((! original_repos_relpath && ! original_root_url
&& ! original_uuid && ! checksum
&& original_revision == SVN_INVALID_REVNUM)
|| (original_repos_relpath && original_root_url
&& original_uuid && checksum
&& original_revision != SVN_INVALID_REVNUM));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
blank_iwb(&iwb);
iwb.presence = svn_wc__db_status_normal;
iwb.kind = svn_node_file;
if (original_root_url != NULL)
{
SVN_ERR(create_repos_id(&iwb.original_repos_id,
original_root_url, original_uuid,
wcroot->sdb, scratch_pool));
iwb.original_repos_relpath = original_repos_relpath;
iwb.original_revnum = original_revision;
iwb.props = props;
iwb.changed_rev = changed_rev;
iwb.changed_date = changed_date;
iwb.changed_author = changed_author;
}
SVN_ERR(op_depth_for_copy(&iwb.op_depth, &iwb.not_present_op_depth,
&parent_op_depth, iwb.original_repos_id,
original_repos_relpath, original_revision,
wcroot, local_relpath, scratch_pool));
iwb.checksum = checksum;
iwb.moved_here = is_move && (parent_op_depth == 0 ||
iwb.op_depth == parent_op_depth);
if (update_actual_props)
{
iwb.update_actual_props = update_actual_props;
iwb.new_actual_props = new_actual_props;
}
iwb.work_items = work_items;
iwb.conflict = conflict;
SVN_WC__DB_WITH_TXN(
insert_working_node(&iwb, wcroot, local_relpath, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_copy_symlink(svn_wc__db_t *db,
const char *local_abspath,
const apr_hash_t *props,
svn_revnum_t changed_rev,
apr_time_t changed_date,
const char *changed_author,
const char *original_repos_relpath,
const char *original_root_url,
const char *original_uuid,
svn_revnum_t original_revision,
const char *target,
svn_boolean_t is_move,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
insert_working_baton_t iwb;
int parent_op_depth;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(props != NULL);
SVN_ERR_ASSERT(target != NULL);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
blank_iwb(&iwb);
iwb.presence = svn_wc__db_status_normal;
iwb.kind = svn_node_symlink;
if (original_root_url != NULL)
{
SVN_ERR(create_repos_id(&iwb.original_repos_id,
original_root_url, original_uuid,
wcroot->sdb, scratch_pool));
iwb.original_repos_relpath = original_repos_relpath;
iwb.original_revnum = original_revision;
iwb.props = props;
iwb.changed_rev = changed_rev;
iwb.changed_date = changed_date;
iwb.changed_author = changed_author;
}
SVN_ERR(op_depth_for_copy(&iwb.op_depth, &iwb.not_present_op_depth,
&parent_op_depth, iwb.original_repos_id,
original_repos_relpath, original_revision,
wcroot, local_relpath, scratch_pool));
iwb.target = target;
iwb.moved_here = is_move && (parent_op_depth == 0 ||
iwb.op_depth == parent_op_depth);
iwb.work_items = work_items;
iwb.conflict = conflict;
SVN_WC__DB_WITH_TXN(
insert_working_node(&iwb, wcroot, local_relpath, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_add_directory(svn_wc__db_t *db,
const char *local_abspath,
const apr_hash_t *props,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
const char *dir_abspath;
const char *name;
insert_working_baton_t iwb;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
svn_dirent_split(&dir_abspath, &name, local_abspath, scratch_pool);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
dir_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
blank_iwb(&iwb);
local_relpath = svn_relpath_join(local_relpath, name, scratch_pool);
iwb.presence = svn_wc__db_status_normal;
iwb.kind = svn_node_dir;
iwb.op_depth = relpath_depth(local_relpath);
if (props && apr_hash_count((apr_hash_t *)props))
{
iwb.update_actual_props = TRUE;
iwb.new_actual_props = props;
}
iwb.work_items = work_items;
SVN_WC__DB_WITH_TXN(
insert_working_node(&iwb, wcroot, local_relpath, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_infinity,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_add_file(svn_wc__db_t *db,
const char *local_abspath,
const apr_hash_t *props,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
insert_working_baton_t iwb;
const char *dir_abspath;
const char *name;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
svn_dirent_split(&dir_abspath, &name, local_abspath, scratch_pool);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
dir_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
blank_iwb(&iwb);
local_relpath = svn_relpath_join(local_relpath, name, scratch_pool);
iwb.presence = svn_wc__db_status_normal;
iwb.kind = svn_node_file;
iwb.op_depth = relpath_depth(local_relpath);
if (props && apr_hash_count((apr_hash_t *)props))
{
iwb.update_actual_props = TRUE;
iwb.new_actual_props = props;
}
iwb.work_items = work_items;
SVN_WC__DB_WITH_TXN(
insert_working_node(&iwb, wcroot, local_relpath, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_add_symlink(svn_wc__db_t *db,
const char *local_abspath,
const char *target,
const apr_hash_t *props,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
insert_working_baton_t iwb;
const char *dir_abspath;
const char *name;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(target != NULL);
svn_dirent_split(&dir_abspath, &name, local_abspath, scratch_pool);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
dir_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
blank_iwb(&iwb);
local_relpath = svn_relpath_join(local_relpath, name, scratch_pool);
iwb.presence = svn_wc__db_status_normal;
iwb.kind = svn_node_symlink;
iwb.op_depth = relpath_depth(local_relpath);
if (props && apr_hash_count((apr_hash_t *)props))
{
iwb.update_actual_props = TRUE;
iwb.new_actual_props = props;
}
iwb.target = target;
iwb.work_items = work_items;
SVN_WC__DB_WITH_TXN(
insert_working_node(&iwb, wcroot, local_relpath, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
db_record_fileinfo(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_int64_t recorded_size,
apr_int64_t recorded_time,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
int affected_rows;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_NODE_FILEINFO));
SVN_ERR(svn_sqlite__bindf(stmt, "isii", wcroot->wc_id, local_relpath,
recorded_size, recorded_time));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
SVN_ERR_ASSERT(affected_rows == 1);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_global_record_fileinfo(svn_wc__db_t *db,
const char *local_abspath,
svn_filesize_t recorded_size,
apr_time_t recorded_time,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(db_record_fileinfo(wcroot, local_relpath,
recorded_size, recorded_time, scratch_pool));
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
set_actual_props(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_hash_t *props,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
int affected_rows;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_ACTUAL_PROPS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
if (affected_rows == 1 || !props)
{
if (!props && affected_rows)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_EMPTY));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
return SVN_NO_ERROR;
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_INSERT_ACTUAL_PROPS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
if (*local_relpath != '\0')
SVN_ERR(svn_sqlite__bind_text(stmt, 3,
svn_relpath_dirname(local_relpath,
scratch_pool)));
SVN_ERR(svn_sqlite__bind_properties(stmt, 4, props, scratch_pool));
return svn_error_trace(svn_sqlite__step_done(stmt));
}
svn_error_t *
svn_wc__db_op_set_props_internal(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_hash_t *props,
svn_boolean_t clear_recorded_info,
apr_pool_t *scratch_pool)
{
SVN_ERR(set_actual_props(wcroot, local_relpath, props, scratch_pool));
if (clear_recorded_info)
{
SVN_ERR(db_record_fileinfo(wcroot, local_relpath,
SVN_INVALID_FILESIZE, 0,
scratch_pool));
}
return SVN_NO_ERROR;
}
static svn_error_t *
set_props_txn(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_hash_t *props,
svn_boolean_t clear_recorded_info,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
apr_hash_t *pristine_props;
SVN_ERR(db_read_pristine_props(&pristine_props, wcroot, local_relpath, FALSE,
scratch_pool, scratch_pool));
if (props && pristine_props)
{
apr_array_header_t *prop_diffs;
SVN_ERR(svn_prop_diffs(&prop_diffs, props, pristine_props,
scratch_pool));
if (prop_diffs->nelts == 0)
props = NULL;
}
SVN_ERR(svn_wc__db_op_set_props_internal(wcroot, local_relpath, props,
clear_recorded_info, scratch_pool));
SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
if (conflict)
SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
conflict, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_set_props(svn_wc__db_t *db,
const char *local_abspath,
apr_hash_t *props,
svn_boolean_t clear_recorded_info,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(set_props_txn(wcroot, local_relpath, props,
clear_recorded_info, conflict, work_items,
scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_modified(svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
NOT_IMPLEMENTED();
}
static svn_error_t *
populate_targets_tree(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_depth_t depth,
const apr_array_header_t *changelist_filter,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
int affected_rows = 0;
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
STMT_CREATE_TARGETS_LIST));
if (changelist_filter && changelist_filter->nelts > 0)
{
int i;
int stmt_idx;
switch (depth)
{
case svn_depth_empty:
stmt_idx = STMT_INSERT_TARGET_WITH_CHANGELIST;
break;
case svn_depth_files:
stmt_idx = STMT_INSERT_TARGET_WITH_CHANGELIST_DEPTH_FILES;
break;
case svn_depth_immediates:
stmt_idx = STMT_INSERT_TARGET_WITH_CHANGELIST_DEPTH_IMMEDIATES;
break;
case svn_depth_infinity:
stmt_idx = STMT_INSERT_TARGET_WITH_CHANGELIST_DEPTH_INFINITY;
break;
default:
SVN_ERR_MALFUNCTION();
break;
}
for (i = 0; i < changelist_filter->nelts; i++)
{
int sub_affected;
const char *changelist = APR_ARRAY_IDX(changelist_filter, i,
const char *);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_INSERT_TARGET_WITH_CHANGELIST));
SVN_ERR(svn_sqlite__bindf(stmt, "iss", wcroot->wc_id,
local_relpath, changelist));
SVN_ERR(svn_sqlite__update(&sub_affected, stmt));
if (!sub_affected && depth > svn_depth_empty)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, stmt_idx));
SVN_ERR(svn_sqlite__bindf(stmt, "iss", wcroot->wc_id,
local_relpath, changelist));
SVN_ERR(svn_sqlite__update(&sub_affected, stmt));
}
affected_rows += sub_affected;
}
}
else
{
int stmt_idx;
int sub_affected;
switch (depth)
{
case svn_depth_empty:
stmt_idx = STMT_INSERT_TARGET;
break;
case svn_depth_files:
stmt_idx = STMT_INSERT_TARGET_DEPTH_FILES;
break;
case svn_depth_immediates:
stmt_idx = STMT_INSERT_TARGET_DEPTH_IMMEDIATES;
break;
case svn_depth_infinity:
stmt_idx = STMT_INSERT_TARGET_DEPTH_INFINITY;
break;
default:
SVN_ERR_MALFUNCTION();
break;
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_INSERT_TARGET));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__update(&sub_affected, stmt));
affected_rows += sub_affected;
if (depth > svn_depth_empty)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, stmt_idx));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__update(&sub_affected, stmt));
affected_rows += sub_affected;
}
}
if (affected_rows == 0)
{
svn_boolean_t exists;
SVN_ERR(does_node_exist(&exists, wcroot, local_relpath));
if (!exists)
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
return SVN_NO_ERROR;
}
#if 0
static svn_error_t *
dump_targets(svn_wc__db_wcroot_t *wcroot,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_TARGETS));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
const char *target = svn_sqlite__column_text(stmt, 0, NULL);
SVN_DBG(("Target: '%s'\n", target));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
#endif
struct set_changelist_baton_t
{
const char *new_changelist;
const apr_array_header_t *changelist_filter;
svn_depth_t depth;
};
static svn_error_t *
set_changelist_txn(void *baton,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
struct set_changelist_baton_t *scb = baton;
svn_sqlite__stmt_t *stmt;
SVN_ERR(populate_targets_tree(wcroot, local_relpath, scb->depth,
scb->changelist_filter, scratch_pool));
if (scb->new_changelist)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_INSERT_ACTUAL_EMPTIES_FILES));
SVN_ERR(svn_sqlite__step_done(stmt));
}
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
STMT_CREATE_CHANGELIST_LIST));
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
STMT_CREATE_CHANGELIST_TRIGGER));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_ACTUAL_CHANGELISTS));
SVN_ERR(svn_sqlite__bindf(stmt, "iss", wcroot->wc_id, local_relpath,
scb->new_changelist));
SVN_ERR(svn_sqlite__step_done(stmt));
if (scb->new_changelist)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_MARK_SKIPPED_CHANGELIST_DIRS));
SVN_ERR(svn_sqlite__bindf(stmt, "iss", wcroot->wc_id, local_relpath,
scb->new_changelist));
SVN_ERR(svn_sqlite__step_done(stmt));
}
if (!scb->new_changelist)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_EMPTIES));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
return SVN_NO_ERROR;
}
static svn_error_t *
do_changelist_notify(void *baton,
svn_wc__db_wcroot_t *wcroot,
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_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_pool_t *iterpool;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_CHANGELIST_LIST));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
iterpool = svn_pool_create(scratch_pool);
while (have_row)
{
const char *notify_relpath = svn_sqlite__column_text(stmt, 1, NULL);
svn_wc_notify_action_t action = svn_sqlite__column_int(stmt, 2);
svn_wc_notify_t *notify;
const char *notify_abspath;
svn_pool_clear(iterpool);
if (cancel_func)
{
svn_error_t *err = cancel_func(cancel_baton);
if (err)
return svn_error_trace(svn_error_compose_create(
err,
svn_sqlite__reset(stmt)));
}
notify_abspath = svn_dirent_join(wcroot->abspath, notify_relpath,
iterpool);
notify = svn_wc_create_notify(notify_abspath, action, iterpool);
notify->changelist_name = svn_sqlite__column_text(stmt, 3, NULL);
notify_func(notify_baton, notify, iterpool);
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
svn_pool_destroy(iterpool);
return svn_error_trace(svn_sqlite__reset(stmt));
}
svn_error_t *
svn_wc__db_op_set_changelist(svn_wc__db_t *db,
const char *local_abspath,
const char *new_changelist,
const apr_array_header_t *changelist_filter,
svn_depth_t depth,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
struct set_changelist_baton_t scb;
scb.new_changelist = new_changelist;
scb.changelist_filter = changelist_filter;
scb.depth = depth;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, depth, scratch_pool));
return svn_error_trace(with_finalization(wcroot, local_relpath,
set_changelist_txn, &scb,
do_changelist_notify, NULL,
cancel_func, cancel_baton,
notify_func, notify_baton,
STMT_FINALIZE_CHANGELIST,
scratch_pool));
}
svn_error_t *
svn_wc__db_mark_conflict_internal(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
const svn_skel_t *conflict_skel,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t got_row;
svn_boolean_t is_complete;
SVN_ERR(svn_wc__conflict_skel_is_complete(&is_complete, conflict_skel));
SVN_ERR_ASSERT(is_complete);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&got_row, stmt));
SVN_ERR(svn_sqlite__reset(stmt));
if (got_row)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_ACTUAL_CONFLICT));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
}
else
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_INSERT_ACTUAL_CONFLICT));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
if (*local_relpath != '\0')
SVN_ERR(svn_sqlite__bind_text(stmt, 4,
svn_relpath_dirname(local_relpath,
scratch_pool)));
}
{
svn_stringbuf_t *sb = svn_skel__unparse(conflict_skel, scratch_pool);
SVN_ERR(svn_sqlite__bind_blob(stmt, 3, sb->data, sb->len));
}
SVN_ERR(svn_sqlite__update(NULL, stmt));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_mark_conflict(svn_wc__db_t *db,
const char *local_abspath,
const svn_skel_t *conflict_skel,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
conflict_skel, scratch_pool));
if (work_items)
SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_mark_resolved_internal(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_wc__db_t *db,
svn_boolean_t resolved_text,
svn_boolean_t resolved_props,
svn_boolean_t resolved_tree,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
int total_affected_rows = 0;
svn_boolean_t resolved_all;
apr_size_t conflict_len;
const void *conflict_data;
svn_skel_t *conflicts;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (! have_row)
{
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
SVN_ERR(svn_sqlite__reset(stmt));
if (have_row)
return SVN_NO_ERROR;
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
conflict_data = svn_sqlite__column_blob(stmt, 2, &conflict_len,
scratch_pool);
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
if (!conflict_data)
return SVN_NO_ERROR;
conflicts = svn_skel__parse(conflict_data, conflict_len, scratch_pool);
SVN_ERR(svn_wc__conflict_skel_resolve(&resolved_all, conflicts,
db, wcroot->abspath,
resolved_text,
resolved_props ? "" : NULL,
resolved_tree,
scratch_pool, scratch_pool));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_ACTUAL_CONFLICT));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
if (! resolved_all)
{
svn_stringbuf_t *sb = svn_skel__unparse(conflicts, scratch_pool);
SVN_ERR(svn_sqlite__bind_blob(stmt, 3, sb->data, sb->len));
}
SVN_ERR(svn_sqlite__update(&total_affected_rows, stmt));
if (total_affected_rows > 0)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_EMPTY));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_mark_resolved(svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t resolved_text,
svn_boolean_t resolved_props,
svn_boolean_t resolved_tree,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
svn_wc__db_op_mark_resolved_internal(
wcroot, local_relpath, db,
resolved_text, resolved_props, resolved_tree,
work_items, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
clear_moved_to(svn_wc__db_wcroot_t *wcroot,
const char *moved_to_relpath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
const char *moved_from_relpath;
int moved_from_op_depth;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MOVED_FROM_RELPATH));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, moved_to_relpath));
SVN_ERR(svn_sqlite__step_row(stmt));
moved_from_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
moved_from_op_depth = svn_sqlite__column_int(stmt, 1);
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_CLEAR_MOVED_TO_RELPATH));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
moved_from_relpath, moved_from_op_depth));
SVN_ERR(svn_sqlite__update(NULL, stmt));
return SVN_NO_ERROR;
}
static svn_error_t *
revert_maybe_raise_moved_away(svn_wc__db_wcroot_t * wcroot,
svn_wc__db_t *db,
const char *local_relpath,
int op_depth_below,
apr_pool_t *scratch_pool)
{
svn_skel_t *conflict;
svn_wc_operation_t operation;
svn_boolean_t tree_conflicted;
const apr_array_header_t *locations;
svn_wc_conflict_reason_t reason;
svn_wc_conflict_action_t action;
SVN_ERR(svn_wc__db_read_conflict_internal(&conflict, NULL, NULL, wcroot,
local_relpath,
scratch_pool, scratch_pool));
if (!conflict)
return SVN_NO_ERROR;
SVN_ERR(svn_wc__conflict_read_info(&operation, &locations, NULL, NULL,
&tree_conflicted,
db, wcroot->abspath,
conflict,
scratch_pool, scratch_pool));
if (!tree_conflicted
|| (operation != svn_wc_operation_update
&& operation != svn_wc_operation_switch))
{
return SVN_NO_ERROR;
}
SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action,
NULL,
db, wcroot->abspath,
conflict,
scratch_pool,
scratch_pool));
if (reason == svn_wc_conflict_reason_deleted
|| reason == svn_wc_conflict_reason_replaced)
{
SVN_ERR(svn_wc__db_op_raise_moved_away_internal(
wcroot, local_relpath, op_depth_below, db,
operation, action,
(locations && locations->nelts > 0)
? APR_ARRAY_IDX(locations, 0,
const svn_wc_conflict_version_t *)
: NULL,
(locations && locations->nelts > 1)
? APR_ARRAY_IDX(locations, 1,
const svn_wc_conflict_version_t *)
: NULL,
scratch_pool));
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
STMT_MOVE_NOTIFY_TO_REVERT));
}
return SVN_NO_ERROR;
}
struct revert_baton_t
{
svn_wc__db_t *db;
svn_boolean_t clear_changelists;
};
static svn_error_t *
op_revert_txn(void *baton,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
struct revert_baton_t *rvb = baton;
svn_wc__db_t *db = rvb->db;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
int op_depth;
svn_boolean_t moved_here;
int affected_rows;
const char *moved_to;
int op_depth_below;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
{
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
if (affected_rows)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_ACTUAL_HAS_CHILDREN));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
SVN_ERR(svn_sqlite__reset(stmt));
if (have_row)
return svn_error_createf(SVN_ERR_WC_INVALID_OPERATION_DEPTH, NULL,
_("Can't revert '%s' without"
" reverting children"),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
return SVN_NO_ERROR;
}
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
op_depth = svn_sqlite__column_int(stmt, 0);
moved_here = svn_sqlite__column_boolean(stmt, 15);
moved_to = svn_sqlite__column_text(stmt, 17, scratch_pool);
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
op_depth_below = svn_sqlite__column_int(stmt, 0);
else
op_depth_below = -1;
SVN_ERR(svn_sqlite__reset(stmt));
if (moved_to)
{
SVN_ERR(svn_wc__db_op_break_move_internal(wcroot,
local_relpath, op_depth,
moved_to, NULL, scratch_pool));
}
if (op_depth > 0 && op_depth == relpath_depth(local_relpath))
{
int op_depth_increased;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_GE_OP_DEPTH_CHILDREN));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
local_relpath, op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
SVN_ERR(svn_sqlite__reset(stmt));
if (have_row)
return svn_error_createf(SVN_ERR_WC_INVALID_OPERATION_DEPTH, NULL,
_("Can't revert '%s' without"
" reverting children"),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_OP_DEPTH_INCREASE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
local_relpath,
op_depth));
SVN_ERR(svn_sqlite__update(&op_depth_increased, stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_WORKING_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_WC_LOCK_ORPHAN));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
if (moved_here)
SVN_ERR(clear_moved_to(wcroot, local_relpath, scratch_pool));
if (op_depth_increased && !moved_to)
SVN_ERR(revert_maybe_raise_moved_away(wcroot, db, local_relpath,
op_depth_below, scratch_pool));
}
if (rvb->clear_changelists)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
}
else
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_NODE_LEAVING_CHANGELIST));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
if (!affected_rows)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_CLEAR_ACTUAL_NODE_LEAVING_CHANGELIST));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
}
}
return SVN_NO_ERROR;
}
static svn_error_t *
op_revert_recursive_txn(void *baton,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
struct revert_baton_t *rvb = baton;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
int op_depth;
int select_op_depth;
svn_boolean_t moved_here;
int affected_rows;
apr_pool_t *iterpool;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
{
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
local_relpath));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
if (affected_rows)
return SVN_NO_ERROR;
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
op_depth = svn_sqlite__column_int(stmt, 0);
moved_here = svn_sqlite__column_boolean(stmt, 15);
SVN_ERR(svn_sqlite__reset(stmt));
if (op_depth > 0 && op_depth != relpath_depth(local_relpath))
return svn_error_createf(SVN_ERR_WC_INVALID_OPERATION_DEPTH, NULL,
_("Can't revert '%s' without"
" reverting parent"),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
SVN_ERR(svn_sqlite__get_statement(
&stmt, wcroot->sdb, STMT_SELECT_MOVED_OUTSIDE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
const char *src_relpath = svn_sqlite__column_text(stmt, 0, NULL);
const char *dst_relpath = svn_sqlite__column_text(stmt, 1, NULL);
int move_op_depth = svn_sqlite__column_int(stmt, 2);
svn_error_t *err;
err = svn_wc__db_op_break_move_internal(wcroot,
src_relpath, move_op_depth,
dst_relpath, NULL, scratch_pool);
if (err)
return svn_error_compose_create(err, svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
select_op_depth = op_depth ? op_depth : 1;
SVN_ERR(svn_sqlite__get_statement(
&stmt, wcroot->sdb,
STMT_DELETE_NODES_ABOVE_DEPTH_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
local_relpath, select_op_depth));
SVN_ERR(svn_sqlite__step_done(stmt));
if (rvb->clear_changelists)
{
SVN_ERR(svn_sqlite__get_statement(
&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_NODE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
else
{
SVN_ERR(svn_sqlite__get_statement(
&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_NODE_LEAVING_CHANGELIST_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(svn_sqlite__get_statement(
&stmt, wcroot->sdb,
STMT_CLEAR_ACTUAL_NODE_LEAVING_CHANGELIST_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_WC_LOCK_ORPHAN_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MOVED_HERE_CHILDREN));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
iterpool = svn_pool_create(scratch_pool);
while (have_row)
{
const char *moved_here_child_relpath;
svn_error_t *err;
svn_pool_clear(iterpool);
moved_here_child_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
err = clear_moved_to(wcroot, moved_here_child_relpath, iterpool);
if (err)
return svn_error_trace(svn_error_compose_create(
err,
svn_sqlite__reset(stmt)));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
svn_pool_destroy(iterpool);
if (op_depth > 0 && op_depth == relpath_depth(local_relpath)
&& moved_here)
SVN_ERR(clear_moved_to(wcroot, local_relpath, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_revert(svn_wc__db_t *db,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t clear_changelists,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
struct revert_baton_t rvb;
struct with_triggers_baton_t wtb = { STMT_CREATE_REVERT_LIST,
STMT_DROP_REVERT_LIST_TRIGGERS,
NULL, NULL};
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
rvb.db = db;
rvb.clear_changelists = clear_changelists;
wtb.cb_baton = &rvb;
switch (depth)
{
case svn_depth_empty:
wtb.cb_func = op_revert_txn;
break;
case svn_depth_infinity:
wtb.cb_func = op_revert_recursive_txn;
break;
default:
return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Unsupported depth for revert of '%s'"),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(with_triggers(&wtb, wcroot, local_relpath, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, depth, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
revert_list_read(svn_boolean_t *reverted,
const apr_array_header_t **marker_paths,
svn_boolean_t *copied_here,
svn_node_kind_t *kind,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_wc__db_t *db,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
*reverted = FALSE;
*marker_paths = NULL;
*copied_here = FALSE;
*kind = svn_node_unknown;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_REVERT_LIST));
SVN_ERR(svn_sqlite__bindf(stmt, "s", local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
svn_boolean_t is_actual = svn_sqlite__column_boolean(stmt, 0);
svn_boolean_t another_row = FALSE;
if (is_actual)
{
apr_size_t conflict_len;
const void *conflict_data;
conflict_data = svn_sqlite__column_blob(stmt, 5, &conflict_len,
scratch_pool);
if (conflict_data)
{
svn_skel_t *conflicts = svn_skel__parse(conflict_data,
conflict_len,
scratch_pool);
SVN_ERR(svn_wc__conflict_read_markers(marker_paths,
db, wcroot->abspath,
conflicts,
result_pool,
scratch_pool));
}
if (!svn_sqlite__column_is_null(stmt, 1))
*reverted = TRUE;
SVN_ERR(svn_sqlite__step(&another_row, stmt));
}
if (!is_actual || another_row)
{
*reverted = TRUE;
if (!svn_sqlite__column_is_null(stmt, 4))
{
int op_depth = svn_sqlite__column_int(stmt, 3);
*copied_here = (op_depth == relpath_depth(local_relpath));
}
*kind = svn_sqlite__column_token(stmt, 2, kind_map);
}
}
SVN_ERR(svn_sqlite__reset(stmt));
if (have_row)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_REVERT_LIST));
SVN_ERR(svn_sqlite__bindf(stmt, "s", local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_revert_list_read(svn_boolean_t *reverted,
const apr_array_header_t **marker_files,
svn_boolean_t *copied_here,
svn_node_kind_t *kind,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
revert_list_read(reverted, marker_files, copied_here, kind,
wcroot, local_relpath, db,
result_pool, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
static svn_error_t *
revert_list_read_copied_children(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_array_header_t **children_p,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_array_header_t *children;
children =
apr_array_make(result_pool, 0,
sizeof(svn_wc__db_revert_list_copied_child_info_t *));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_REVERT_LIST_COPIED_CHILDREN));
SVN_ERR(svn_sqlite__bindf(stmt, "sd",
local_relpath, relpath_depth(local_relpath)));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
svn_wc__db_revert_list_copied_child_info_t *child_info;
const char *child_relpath;
child_info = apr_palloc(result_pool, sizeof(*child_info));
child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
child_info->abspath = svn_dirent_join(wcroot->abspath, child_relpath,
result_pool);
child_info->kind = svn_sqlite__column_token(stmt, 1, kind_map);
APR_ARRAY_PUSH(
children,
svn_wc__db_revert_list_copied_child_info_t *) = child_info;
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
*children_p = children;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_revert_list_read_copied_children(apr_array_header_t **children,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
revert_list_read_copied_children(wcroot, local_relpath, children,
result_pool, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_revert_list_notify(svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath, scratch_pool, iterpool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_REVERT_LIST_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "s", local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
return svn_error_trace(svn_sqlite__reset(stmt));
while (have_row)
{
const char *notify_relpath = svn_sqlite__column_text(stmt, 0, NULL);
svn_wc_notify_t *notify;
svn_pool_clear(iterpool);
notify = svn_wc_create_notify(svn_dirent_join(wcroot->abspath,
notify_relpath,
iterpool),
svn_wc_notify_revert,
iterpool);
if (!svn_sqlite__column_is_null(stmt, 1))
notify->kind = svn_sqlite__column_token(stmt, 1, kind_map);
else
{
if (!svn_sqlite__column_is_null(stmt, 3))
notify->kind = svn_sqlite__column_token(stmt, 3, kind_map_none);
switch (svn_sqlite__column_int(stmt, 2))
{
case 0:
continue;
case 1:
break;
case 2:
notify->action = svn_wc_notify_tree_conflict;
break;
default:
SVN_ERR_MALFUNCTION();
}
}
notify_func(notify_baton, notify, iterpool);
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_REVERT_LIST_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "s", local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_revert_list_done(svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, STMT_DROP_REVERT_LIST));
return SVN_NO_ERROR;
}
static svn_error_t *
remove_node_txn(svn_boolean_t *left_changes,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_wc__db_t *db,
svn_boolean_t destroy_wc,
svn_boolean_t destroy_changes,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
SVN_ERR_ASSERT(!destroy_wc || db != NULL);
if (left_changes)
*left_changes = FALSE;
if (destroy_wc
&& (!destroy_changes || *local_relpath == '\0'))
{
svn_boolean_t have_row;
apr_pool_t *iterpool;
svn_error_t *err = NULL;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_WORKING_PRESENT));
SVN_ERR(svn_sqlite__bindf(stmt, "is",
wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
iterpool = svn_pool_create(scratch_pool);
while (have_row)
{
const char *child_relpath;
const char *child_abspath;
svn_node_kind_t child_kind;
svn_boolean_t have_checksum;
svn_filesize_t recorded_size;
apr_int64_t recorded_time;
const svn_io_dirent2_t *dirent;
svn_boolean_t modified_p = TRUE;
svn_skel_t *work_item = NULL;
svn_pool_clear(iterpool);
child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
child_kind = svn_sqlite__column_token(stmt, 1, kind_map);
child_abspath = svn_dirent_join(wcroot->abspath, child_relpath,
iterpool);
if (child_kind == svn_node_file)
{
have_checksum = !svn_sqlite__column_is_null(stmt, 2);
recorded_size = get_recorded_size(stmt, 3);
recorded_time = svn_sqlite__column_int64(stmt, 4);
}
if (cancel_func)
err = cancel_func(cancel_baton);
if (err)
break;
err = svn_io_stat_dirent2(&dirent, child_abspath, FALSE, TRUE,
iterpool, iterpool);
if (err)
break;
if (destroy_changes
|| dirent->kind != svn_node_file
|| child_kind != svn_node_file)
{
modified_p = FALSE;
}
else if (child_kind == svn_node_file
&& dirent->kind == svn_node_file
&& dirent->filesize == recorded_size
&& dirent->mtime == recorded_time)
{
modified_p = FALSE;
}
else if (have_checksum)
err = svn_wc__internal_file_modified_p(&modified_p,
db, child_abspath,
FALSE, iterpool);
if (err)
break;
if (modified_p)
{
if (left_changes)
*left_changes = TRUE;
}
else if (child_kind == svn_node_dir)
{
err = svn_wc__wq_build_dir_remove(&work_item,
db, wcroot->abspath,
child_abspath, FALSE,
iterpool, iterpool);
}
else
{
err = svn_wc__wq_build_file_remove(&work_item,
db, wcroot->abspath,
child_abspath,
iterpool, iterpool);
}
if (err)
break;
if (work_item)
{
err = add_work_items(wcroot->sdb, work_item, iterpool);
if (err)
break;
}
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
svn_pool_destroy(iterpool);
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
}
if (destroy_wc && *local_relpath != '\0')
{
svn_wc__db_status_t status;
svn_node_kind_t kind;
SVN_ERR(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,
wcroot, local_relpath,
scratch_pool, scratch_pool));
if (status == svn_wc__db_status_normal
|| status == svn_wc__db_status_added
|| status == svn_wc__db_status_incomplete)
{
svn_skel_t *work_item = NULL;
const char *local_abspath = svn_dirent_join(wcroot->abspath,
local_relpath,
scratch_pool);
if (kind == svn_node_dir)
{
SVN_ERR(svn_wc__wq_build_dir_remove(&work_item,
db, wcroot->abspath,
local_abspath,
destroy_changes
,
scratch_pool, scratch_pool));
}
else
{
svn_boolean_t modified_p = FALSE;
if (!destroy_changes)
{
SVN_ERR(svn_wc__internal_file_modified_p(&modified_p,
db, local_abspath,
FALSE,
scratch_pool));
}
if (!modified_p)
SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
db, wcroot->abspath,
local_abspath,
scratch_pool,
scratch_pool));
else
{
if (left_changes)
*left_changes = TRUE;
}
}
SVN_ERR(add_work_items(wcroot->sdb, work_item, scratch_pool));
}
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_NODE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
if (local_relpath[0] != '\0')
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_NODE_ALL_LAYERS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_NODE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
if (conflict)
SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
conflict, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_remove_node(svn_boolean_t *left_changes,
svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t destroy_wc,
svn_boolean_t destroy_changes,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(remove_node_txn(left_changes,
wcroot, local_relpath, db,
destroy_wc, destroy_changes,
conflict, work_items,
cancel_func, cancel_baton, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_infinity,
scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
db_op_set_base_depth(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_depth_t depth,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
int affected_rows;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_NODE_BASE_DEPTH));
SVN_ERR(svn_sqlite__bindf(stmt, "iss", wcroot->wc_id, local_relpath,
svn_token__to_word(depth_map, depth)));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
if (affected_rows == 0)
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' is not a committed directory"),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_set_base_depth(svn_wc__db_t *db,
const char *local_abspath,
svn_depth_t depth,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(depth >= svn_depth_empty && depth <= svn_depth_infinity);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(db_op_set_base_depth(wcroot, local_relpath, depth,
scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
info_below_working(svn_boolean_t *have_base,
svn_boolean_t *have_work,
svn_wc__db_status_t *status,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
int below_op_depth,
apr_pool_t *scratch_pool);
static svn_error_t *
convert_to_working_status(svn_wc__db_status_t *working_status,
svn_wc__db_status_t status)
{
svn_wc__db_status_t work_status = status;
SVN_ERR_ASSERT(work_status == svn_wc__db_status_normal
|| work_status == svn_wc__db_status_not_present
|| work_status == svn_wc__db_status_base_deleted
|| work_status == svn_wc__db_status_incomplete
|| work_status == svn_wc__db_status_excluded);
if (work_status == svn_wc__db_status_excluded)
{
*working_status = svn_wc__db_status_excluded;
}
else if (work_status == svn_wc__db_status_not_present
|| work_status == svn_wc__db_status_base_deleted)
{
*working_status = svn_wc__db_status_deleted;
}
else
{
*working_status = svn_wc__db_status_added;
}
return SVN_NO_ERROR;
}
static svn_error_t *
info_below_working(svn_boolean_t *have_base,
svn_boolean_t *have_work,
svn_wc__db_status_t *status,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
int below_op_depth,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
*have_base = *have_work = FALSE;
*status = svn_wc__db_status_normal;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (below_op_depth >= 0)
{
while (have_row &&
(svn_sqlite__column_int(stmt, 0) > below_op_depth))
{
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
}
if (have_row)
{
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
*status = svn_sqlite__column_token(stmt, 3, presence_map);
while (have_row)
{
int op_depth = svn_sqlite__column_int(stmt, 0);
if (op_depth > 0)
*have_work = TRUE;
else
*have_base = TRUE;
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
}
SVN_ERR(svn_sqlite__reset(stmt));
if (*have_work)
SVN_ERR(convert_to_working_status(status, *status));
return SVN_NO_ERROR;
}
static svn_error_t *
delete_update_movedto(svn_wc__db_wcroot_t *wcroot,
const char *child_moved_from_relpath,
int op_depth,
const char *new_moved_to_relpath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
int affected;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_MOVED_TO_RELPATH));
SVN_ERR(svn_sqlite__bindf(stmt, "isds",
wcroot->wc_id,
child_moved_from_relpath,
op_depth,
new_moved_to_relpath));
SVN_ERR(svn_sqlite__update(&affected, stmt));
#ifdef SVN_DEBUG
SVN_ERR_ASSERT(affected == 1);
#endif
return SVN_NO_ERROR;
}
struct op_delete_baton_t {
const char *moved_to_relpath;
svn_skel_t *conflict;
svn_skel_t *work_items;
svn_boolean_t delete_dir_externals;
svn_boolean_t notify;
};
struct moved_node_t {
const char *local_relpath;
const char *moved_to_relpath;
int op_depth;
int moved_from_depth;
};
static svn_error_t *
resolve_moved_from(const char **moved_from_relpath,
int *moved_from_op_depth,
svn_wc__db_wcroot_t *wcroot,
const char *root_relpath,
const char *local_relpath,
int op_depth,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *suffix = "";
svn_sqlite__stmt_t *stmt;
const char *m_from_relpath;
int m_from_op_depth;
int m_move_from_depth;
svn_boolean_t have_row;
while (relpath_depth(local_relpath) > op_depth)
{
const char *name;
svn_relpath_split(&local_relpath, &name, local_relpath, scratch_pool);
suffix = svn_relpath_join(suffix, name, scratch_pool);
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MOVED_FROM_FOR_DELETE));
SVN_ERR(svn_sqlite__bindf(stmt, "is",
wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
{
*moved_from_relpath = NULL;
*moved_from_op_depth = -1;
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
m_from_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
m_from_op_depth = svn_sqlite__column_int(stmt, 1);
m_move_from_depth = svn_sqlite__column_int(stmt, 2);
SVN_ERR(svn_sqlite__reset(stmt));
if (! svn_relpath_skip_ancestor(root_relpath, m_from_relpath))
{
*moved_from_relpath = svn_relpath_join(m_from_relpath, suffix,
result_pool);
*moved_from_op_depth = m_from_op_depth;
return SVN_NO_ERROR;
}
else if (!m_move_from_depth)
{
*moved_from_relpath = NULL;
*moved_from_op_depth = -1;
return SVN_NO_ERROR;
}
return svn_error_trace(
resolve_moved_from(moved_from_relpath,
moved_from_op_depth,
wcroot,
root_relpath,
svn_relpath_join(m_from_relpath, suffix,
scratch_pool),
m_move_from_depth,
result_pool, scratch_pool));
}
static svn_error_t *
delete_node(void *baton,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
struct op_delete_baton_t *b = baton;
svn_wc__db_status_t status;
svn_boolean_t have_row, op_root;
svn_boolean_t add_work = FALSE;
svn_sqlite__stmt_t *stmt;
int working_op_depth;
int keep_op_depth = 0;
svn_node_kind_t kind;
apr_array_header_t *moved_nodes = NULL;
int delete_op_depth = relpath_depth(local_relpath);
assert(*local_relpath);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
{
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
svn_sqlite__reset(stmt),
_("The node '%s' was not found."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
working_op_depth = svn_sqlite__column_int(stmt, 0);
status = svn_sqlite__column_token(stmt, 3, presence_map);
kind = svn_sqlite__column_token(stmt, 4, kind_map);
if (working_op_depth < delete_op_depth)
{
op_root = FALSE;
add_work = TRUE;
keep_op_depth = working_op_depth;
}
else
{
op_root = TRUE;
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
svn_wc__db_status_t below_status;
int below_op_depth;
below_op_depth = svn_sqlite__column_int(stmt, 0);
below_status = svn_sqlite__column_token(stmt, 3, presence_map);
if (below_status != svn_wc__db_status_not_present
&& below_status != svn_wc__db_status_base_deleted)
{
add_work = TRUE;
keep_op_depth = below_op_depth;
}
else
keep_op_depth = 0;
}
else
keep_op_depth = -1;
}
SVN_ERR(svn_sqlite__reset(stmt));
if (working_op_depth != 0)
SVN_ERR(convert_to_working_status(&status, status));
if (status == svn_wc__db_status_deleted
|| status == svn_wc__db_status_not_present)
return SVN_NO_ERROR;
if (status == svn_wc__db_status_normal && kind == svn_node_dir)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_HAS_SERVER_EXCLUDED_DESCENDANTS));
SVN_ERR(svn_sqlite__bindf(stmt, "is",
wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
const char *absent_path = svn_sqlite__column_text(stmt, 0,
scratch_pool);
return svn_error_createf(
SVN_ERR_WC_PATH_UNEXPECTED_STATUS,
svn_sqlite__reset(stmt),
_("Cannot delete '%s' as '%s' is excluded by server"),
path_for_error_message(wcroot, local_relpath,
scratch_pool),
path_for_error_message(wcroot, absent_path,
scratch_pool));
}
SVN_ERR(svn_sqlite__reset(stmt));
}
else if (status == svn_wc__db_status_server_excluded)
{
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
_("Cannot delete '%s' as it is excluded by server"),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
}
else if (status == svn_wc__db_status_excluded)
{
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
_("Cannot delete '%s' as it is excluded"),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
}
if (b->moved_to_relpath)
{
const char *moved_from_relpath = NULL;
struct moved_node_t *moved_node;
int move_op_depth;
moved_nodes = apr_array_make(scratch_pool, 1,
sizeof(struct moved_node_t *));
if (status == svn_wc__db_status_added)
SVN_ERR(scan_addition(&status, NULL, NULL, NULL, NULL, NULL, NULL,
&moved_from_relpath,
NULL,
&move_op_depth,
wcroot, local_relpath,
scratch_pool, scratch_pool));
if (op_root && moved_from_relpath)
{
const char *part = svn_relpath_skip_ancestor(local_relpath,
moved_from_relpath);
moved_node = apr_palloc(scratch_pool, sizeof(struct moved_node_t));
if (!part)
moved_node->local_relpath = moved_from_relpath;
else
moved_node->local_relpath = svn_relpath_join(b->moved_to_relpath,
part, scratch_pool);
moved_node->op_depth = move_op_depth;
moved_node->moved_to_relpath = b->moved_to_relpath;
moved_node->moved_from_depth = -1;
APR_ARRAY_PUSH(moved_nodes, const struct moved_node_t *) = moved_node;
}
else if (!op_root && (status == svn_wc__db_status_normal
|| status == svn_wc__db_status_copied
|| status == svn_wc__db_status_moved_here))
{
moved_node = apr_palloc(scratch_pool, sizeof(struct moved_node_t));
moved_node->local_relpath = local_relpath;
moved_node->op_depth = delete_op_depth;
moved_node->moved_to_relpath = b->moved_to_relpath;
moved_node->moved_from_depth = -1;
APR_ARRAY_PUSH(moved_nodes, const struct moved_node_t *) = moved_node;
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_MOVED_TO_DESCENDANTS));
SVN_ERR(svn_sqlite__bindf(stmt, "iss", wcroot->wc_id,
local_relpath,
b->moved_to_relpath));
SVN_ERR(svn_sqlite__update(NULL, stmt));
}
{
apr_pool_t *iterpool;
int i;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MOVED_FOR_DELETE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
delete_op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
iterpool = svn_pool_create(scratch_pool);
while (have_row)
{
struct moved_node_t *mn;
const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
const char *mv_to_relpath = svn_sqlite__column_text(stmt, 1, NULL);
int child_op_depth = svn_sqlite__column_int(stmt, 2);
int moved_from_depth = -1;
svn_boolean_t fixup = FALSE;
if (! b->moved_to_relpath
&& ! svn_relpath_skip_ancestor(local_relpath, mv_to_relpath))
{
int moved_here_depth = svn_sqlite__column_int(stmt, 3);
if (moved_here_depth >= delete_op_depth)
{
fixup = TRUE;
moved_from_depth = moved_here_depth;
}
else
{
fixup = TRUE;
child_op_depth = delete_op_depth;
}
}
else if (b->moved_to_relpath)
{
if (delete_op_depth == child_op_depth)
{
fixup = TRUE;
}
else if (child_op_depth >= delete_op_depth
&& !svn_relpath_skip_ancestor(local_relpath,
mv_to_relpath))
{
child_relpath = svn_relpath_skip_ancestor(local_relpath,
child_relpath);
if (child_relpath)
{
child_relpath = svn_relpath_join(b->moved_to_relpath,
child_relpath,
scratch_pool);
if (child_op_depth > delete_op_depth
&& svn_relpath_skip_ancestor(local_relpath,
child_relpath))
child_op_depth = delete_op_depth;
else
{
child_op_depth = child_op_depth
- relpath_depth(local_relpath)
+ relpath_depth(b->moved_to_relpath);
}
fixup = TRUE;
}
}
}
if (fixup)
{
mn = apr_palloc(scratch_pool, sizeof(struct moved_node_t));
mn->local_relpath = apr_pstrdup(scratch_pool, child_relpath);
mn->moved_to_relpath = apr_pstrdup(scratch_pool, mv_to_relpath);
mn->op_depth = child_op_depth;
mn->moved_from_depth = moved_from_depth;
if (!moved_nodes)
moved_nodes = apr_array_make(scratch_pool, 1,
sizeof(struct moved_node_t *));
APR_ARRAY_PUSH(moved_nodes, struct moved_node_t *) = mn;
}
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
for (i = 0; moved_nodes && (i < moved_nodes->nelts); i++)
{
struct moved_node_t *mn = APR_ARRAY_IDX(moved_nodes, i,
struct moved_node_t *);
if (mn->moved_from_depth > 0)
{
svn_pool_clear(iterpool);
SVN_ERR(resolve_moved_from(&mn->local_relpath, &mn->op_depth,
wcroot, local_relpath,
mn->local_relpath,
mn->moved_from_depth,
scratch_pool, iterpool));
if (!mn->local_relpath)
svn_sort__array_delete(moved_nodes, i--, 1);
}
}
svn_pool_destroy(iterpool);
}
if (!b->moved_to_relpath)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_CLEAR_MOVED_TO_DESCENDANTS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
local_relpath));
SVN_ERR(svn_sqlite__update(NULL, stmt));
if (op_root)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_CLEAR_MOVED_TO_FROM_DEST));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
local_relpath));
SVN_ERR(svn_sqlite__update(NULL, stmt));
}
}
if (b->notify)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_INSERT_DELETE_LIST));
SVN_ERR(svn_sqlite__bindf(stmt, "isd",
wcroot->wc_id, local_relpath, working_op_depth));
SVN_ERR(svn_sqlite__step_done(stmt));
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_NODES_ABOVE_DEPTH_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd",
wcroot->wc_id, local_relpath, delete_op_depth));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_NODE_LEAVING_CHANGELIST_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is",
wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_CLEAR_ACTUAL_NODE_LEAVING_CHANGELIST_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is",
wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_WC_LOCK_ORPHAN_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
if (add_work)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_INSERT_DELETE_FROM_NODE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "isdd",
wcroot->wc_id, local_relpath,
keep_op_depth, delete_op_depth));
SVN_ERR(svn_sqlite__step_done(stmt));
}
if (moved_nodes)
{
int i;
for (i = 0; i < moved_nodes->nelts; ++i)
{
const struct moved_node_t *moved_node
= APR_ARRAY_IDX(moved_nodes, i, void *);
SVN_ERR(delete_update_movedto(wcroot,
moved_node->local_relpath,
moved_node->op_depth,
moved_node->moved_to_relpath,
scratch_pool));
}
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_FILE_EXTERNALS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
b->delete_dir_externals
? STMT_DELETE_EXTERNAL_REGISTATIONS
: STMT_DELETE_FILE_EXTERNAL_REGISTATIONS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(add_work_items(wcroot->sdb, b->work_items, scratch_pool));
if (b->conflict)
SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
b->conflict, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
op_delete_txn(void *baton,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, STMT_CREATE_DELETE_LIST));
SVN_ERR(delete_node(baton, wcroot, local_relpath, scratch_pool));
return SVN_NO_ERROR;
}
struct op_delete_many_baton_t {
apr_array_header_t *rel_targets;
svn_boolean_t delete_dir_externals;
const svn_skel_t *work_items;
};
static svn_error_t *
op_delete_many_txn(void *baton,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
struct op_delete_many_baton_t *odmb = baton;
struct op_delete_baton_t odb;
int i;
apr_pool_t *iterpool;
odb.moved_to_relpath = NULL;
odb.conflict = NULL;
odb.work_items = NULL;
odb.delete_dir_externals = odmb->delete_dir_externals;
odb.notify = TRUE;
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, STMT_CREATE_DELETE_LIST));
iterpool = svn_pool_create(scratch_pool);
for (i = 0; i < odmb->rel_targets->nelts; i++)
{
const char *target_relpath = APR_ARRAY_IDX(odmb->rel_targets, i,
const char *);
svn_pool_clear(iterpool);
SVN_ERR(delete_node(&odb, wcroot, target_relpath, iterpool));
}
svn_pool_destroy(iterpool);
SVN_ERR(add_work_items(wcroot->sdb, odmb->work_items, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
do_delete_notify(void *baton,
svn_wc__db_wcroot_t *wcroot,
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_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_pool_t *iterpool;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_DELETE_LIST));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
iterpool = svn_pool_create(scratch_pool);
while (have_row)
{
const char *notify_relpath;
const char *notify_abspath;
svn_pool_clear(iterpool);
notify_relpath = svn_sqlite__column_text(stmt, 0, NULL);
notify_abspath = svn_dirent_join(wcroot->abspath,
notify_relpath,
iterpool);
notify_func(notify_baton,
svn_wc_create_notify(notify_abspath,
svn_wc_notify_delete,
iterpool),
iterpool);
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
svn_pool_destroy(iterpool);
SVN_ERR(svn_sqlite__reset(stmt));
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_delete(svn_wc__db_t *db,
const char *local_abspath,
const char *moved_to_abspath,
svn_boolean_t delete_dir_externals,
svn_skel_t *conflict,
svn_skel_t *work_items,
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_wcroot_t *wcroot;
svn_wc__db_wcroot_t *moved_to_wcroot;
const char *local_relpath;
const char *moved_to_relpath;
struct op_delete_baton_t odb;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
if (moved_to_abspath)
{
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&moved_to_wcroot,
&moved_to_relpath,
db, moved_to_abspath,
scratch_pool,
scratch_pool));
VERIFY_USABLE_WCROOT(moved_to_wcroot);
if (strcmp(wcroot->abspath, moved_to_wcroot->abspath) != 0)
return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Cannot move '%s' to '%s' because they "
"are not in the same working copy"),
svn_dirent_local_style(local_abspath,
scratch_pool),
svn_dirent_local_style(moved_to_abspath,
scratch_pool));
}
else
moved_to_relpath = NULL;
odb.moved_to_relpath = moved_to_relpath;
odb.conflict = conflict;
odb.work_items = work_items;
odb.delete_dir_externals = delete_dir_externals;
if (notify_func)
{
odb.notify = TRUE;
SVN_ERR(with_finalization(wcroot, local_relpath,
op_delete_txn, &odb,
do_delete_notify, NULL,
cancel_func, cancel_baton,
notify_func, notify_baton,
STMT_FINALIZE_DELETE,
scratch_pool));
}
else
{
odb.notify = FALSE;
SVN_WC__DB_WITH_TXN(
delete_node(&odb, wcroot, local_relpath, scratch_pool),
wcroot);
}
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_infinity,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_delete_many(svn_wc__db_t *db,
apr_array_header_t *targets,
svn_boolean_t delete_dir_externals,
const svn_skel_t *work_items,
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_wcroot_t *wcroot;
const char *local_relpath;
struct op_delete_many_baton_t odmb;
int i;
apr_pool_t *iterpool;
odmb.rel_targets = apr_array_make(scratch_pool, targets->nelts,
sizeof(const char *));
odmb.work_items = work_items;
odmb.delete_dir_externals = delete_dir_externals;
iterpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db,
APR_ARRAY_IDX(targets, 0,
const char *),
scratch_pool, iterpool));
VERIFY_USABLE_WCROOT(wcroot);
for (i = 0; i < targets->nelts; i++)
{
const char *local_abspath = APR_ARRAY_IDX(targets, i, const char*);
svn_wc__db_wcroot_t *target_wcroot;
svn_pool_clear(iterpool);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&target_wcroot,
&local_relpath, db,
APR_ARRAY_IDX(targets, i,
const char *),
scratch_pool, iterpool));
VERIFY_USABLE_WCROOT(target_wcroot);
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(wcroot->wc_id == target_wcroot->wc_id);
APR_ARRAY_PUSH(odmb.rel_targets, const char *) = local_relpath;
SVN_ERR(flush_entries(target_wcroot, local_abspath, svn_depth_infinity,
iterpool));
}
svn_pool_destroy(iterpool);
return svn_error_trace(with_finalization(wcroot, wcroot->abspath,
op_delete_many_txn, &odmb,
do_delete_notify, NULL,
cancel_func, cancel_baton,
notify_func, notify_baton,
STMT_FINALIZE_DELETE,
scratch_pool));
}
static int
column_token_err(svn_error_t **err,
svn_sqlite__stmt_t *stmt,
int column,
const svn_token_map_t *map)
{
svn_error_t *err2;
const char *word = svn_sqlite__column_text(stmt, column, NULL);
int value;
err2 = svn_token__from_word_err(&value, map, word);
if (err2)
{
*err = svn_error_compose_create(
*err,
svn_error_createf(
SVN_ERR_WC_CORRUPT, err2,
_("Encountered invalid node state in column %d of "
"info query to working copy database"),
column));
value = map[0].val;
}
return value;
}
static svn_error_t *
read_info(svn_wc__db_status_t *status,
svn_node_kind_t *kind,
svn_revnum_t *revision,
const char **repos_relpath,
apr_int64_t *repos_id,
svn_revnum_t *changed_rev,
apr_time_t *changed_date,
const char **changed_author,
svn_depth_t *depth,
const svn_checksum_t **checksum,
const char **target,
const char **original_repos_relpath,
apr_int64_t *original_repos_id,
svn_revnum_t *original_revision,
svn_wc__db_lock_t **lock,
svn_filesize_t *recorded_size,
apr_time_t *recorded_time,
const char **changelist,
svn_boolean_t *conflicted,
svn_boolean_t *op_root,
svn_boolean_t *had_props,
svn_boolean_t *props_mod,
svn_boolean_t *have_base,
svn_boolean_t *have_more_work,
svn_boolean_t *have_work,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt_info;
svn_sqlite__stmt_t *stmt_act;
svn_boolean_t have_info;
svn_boolean_t have_act;
svn_error_t *err = NULL;
SVN_ERR(svn_sqlite__get_statement(&stmt_info, wcroot->sdb,
lock ? STMT_SELECT_NODE_INFO_WITH_LOCK
: STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt_info, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_info, stmt_info));
if (changelist || conflicted || props_mod)
{
SVN_ERR(svn_sqlite__get_statement(&stmt_act, wcroot->sdb,
STMT_SELECT_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt_act, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_act, stmt_act));
}
else
{
have_act = FALSE;
stmt_act = NULL;
}
if (have_info)
{
int op_depth;
svn_node_kind_t node_kind;
op_depth = svn_sqlite__column_int(stmt_info, 0);
node_kind = column_token_err(&err, stmt_info, 4, kind_map);
if (status)
{
*status = column_token_err(&err, stmt_info, 3, presence_map);
if (op_depth != 0)
err = svn_error_compose_create(err,
convert_to_working_status(status,
*status));
}
if (kind)
{
*kind = node_kind;
}
if (op_depth != 0)
{
if (repos_id)
*repos_id = INVALID_REPOS_ID;
if (revision)
*revision = SVN_INVALID_REVNUM;
if (repos_relpath)
*repos_relpath = NULL;
}
else
{
repos_location_from_columns(repos_id, revision, repos_relpath,
stmt_info, 1, 5, 2, result_pool);
}
if (changed_rev)
{
*changed_rev = svn_sqlite__column_revnum(stmt_info, 8);
}
if (changed_date)
{
*changed_date = svn_sqlite__column_int64(stmt_info, 9);
}
if (changed_author)
{
*changed_author = svn_sqlite__column_text(stmt_info, 10,
result_pool);
}
if (recorded_time)
{
*recorded_time = svn_sqlite__column_int64(stmt_info, 13);
}
if (depth)
{
if (node_kind != svn_node_dir)
*depth = svn_depth_unknown;
else if (svn_sqlite__column_is_null(stmt_info, 11))
*depth = svn_depth_unknown;
else
*depth = column_token_err(&err, stmt_info, 11, depth_map);
}
if (checksum)
{
if (node_kind != svn_node_file)
{
*checksum = NULL;
}
else
{
err = svn_error_compose_create(
err, svn_sqlite__column_checksum(checksum, stmt_info, 6,
result_pool));
}
}
if (recorded_size)
{
*recorded_size = get_recorded_size(stmt_info, 7);
}
if (target)
{
if (node_kind != svn_node_symlink)
*target = NULL;
else
*target = svn_sqlite__column_text(stmt_info, 12, result_pool);
}
if (changelist)
{
if (have_act)
*changelist = svn_sqlite__column_text(stmt_act, 0, result_pool);
else
*changelist = NULL;
}
if (op_depth == 0)
{
if (original_repos_id)
*original_repos_id = INVALID_REPOS_ID;
if (original_revision)
*original_revision = SVN_INVALID_REVNUM;
if (original_repos_relpath)
*original_repos_relpath = NULL;
}
else
{
repos_location_from_columns(original_repos_id,
original_revision,
original_repos_relpath,
stmt_info, 1, 5, 2, result_pool);
}
if (props_mod)
{
*props_mod = have_act && !svn_sqlite__column_is_null(stmt_act, 1);
}
if (had_props)
{
*had_props = SQLITE_PROPERTIES_AVAILABLE(stmt_info, 14);
}
if (conflicted)
{
if (have_act)
{
*conflicted =
!svn_sqlite__column_is_null(stmt_act, 2);
}
else
*conflicted = FALSE;
}
if (lock)
{
if (op_depth != 0)
*lock = NULL;
else
*lock = lock_from_columns(stmt_info, 17, 18, 19, 20, result_pool);
}
if (have_work)
*have_work = (op_depth != 0);
if (op_root)
{
*op_root = ((op_depth > 0)
&& (op_depth == relpath_depth(local_relpath)));
}
if (have_base || have_more_work)
{
if (have_more_work)
*have_more_work = FALSE;
while (!err && op_depth != 0)
{
err = svn_sqlite__step(&have_info, stmt_info);
if (err || !have_info)
break;
op_depth = svn_sqlite__column_int(stmt_info, 0);
if (have_more_work)
{
if (op_depth > 0)
*have_more_work = TRUE;
if (!have_base)
break;
}
}
if (have_base)
*have_base = (op_depth == 0);
}
}
else if (have_act)
{
if (svn_sqlite__column_is_null(stmt_act, 2))
err = svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
_("Corrupt data for '%s'"),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
SVN_ERR_ASSERT(conflicted);
if (status)
*status = svn_wc__db_status_normal;
if (kind)
*kind = svn_node_unknown;
if (revision)
*revision = SVN_INVALID_REVNUM;
if (repos_relpath)
*repos_relpath = NULL;
if (repos_id)
*repos_id = INVALID_REPOS_ID;
if (changed_rev)
*changed_rev = SVN_INVALID_REVNUM;
if (changed_date)
*changed_date = 0;
if (depth)
*depth = svn_depth_unknown;
if (checksum)
*checksum = NULL;
if (target)
*target = NULL;
if (original_repos_relpath)
*original_repos_relpath = NULL;
if (original_repos_id)
*original_repos_id = INVALID_REPOS_ID;
if (original_revision)
*original_revision = SVN_INVALID_REVNUM;
if (lock)
*lock = NULL;
if (recorded_size)
*recorded_size = 0;
if (recorded_time)
*recorded_time = 0;
if (changelist)
*changelist = svn_sqlite__column_text(stmt_act, 0, result_pool);
if (op_root)
*op_root = FALSE;
if (had_props)
*had_props = FALSE;
if (props_mod)
*props_mod = FALSE;
if (conflicted)
*conflicted = TRUE;
if (have_base)
*have_base = FALSE;
if (have_more_work)
*have_more_work = FALSE;
if (have_work)
*have_work = FALSE;
}
else
{
err = svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
}
if (stmt_act != NULL)
err = svn_error_compose_create(err, svn_sqlite__reset(stmt_act));
if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
err = svn_error_quick_wrapf(err, _("Error reading node '%s'"),
local_relpath);
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt_info)));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_info_internal(svn_wc__db_status_t *status,
svn_node_kind_t *kind,
svn_revnum_t *revision,
const char **repos_relpath,
apr_int64_t *repos_id,
svn_revnum_t *changed_rev,
apr_time_t *changed_date,
const char **changed_author,
svn_depth_t *depth,
const svn_checksum_t **checksum,
const char **target,
const char **original_repos_relpath,
apr_int64_t *original_repos_id,
svn_revnum_t *original_revision,
svn_wc__db_lock_t **lock,
svn_filesize_t *recorded_size,
apr_time_t *recorded_time,
const char **changelist,
svn_boolean_t *conflicted,
svn_boolean_t *op_root,
svn_boolean_t *had_props,
svn_boolean_t *props_mod,
svn_boolean_t *have_base,
svn_boolean_t *have_more_work,
svn_boolean_t *have_work,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
return svn_error_trace(
read_info(status, kind, revision, repos_relpath, repos_id,
changed_rev, changed_date, changed_author,
depth, checksum, target, original_repos_relpath,
original_repos_id, original_revision, lock,
recorded_size, recorded_time, changelist, conflicted,
op_root, had_props, props_mod,
have_base, have_more_work, have_work,
wcroot, local_relpath, result_pool, scratch_pool));
}
svn_error_t *
svn_wc__db_read_info(svn_wc__db_status_t *status,
svn_node_kind_t *kind,
svn_revnum_t *revision,
const char **repos_relpath,
const char **repos_root_url,
const char **repos_uuid,
svn_revnum_t *changed_rev,
apr_time_t *changed_date,
const char **changed_author,
svn_depth_t *depth,
const svn_checksum_t **checksum,
const char **target,
const char **original_repos_relpath,
const char **original_root_url,
const char **original_uuid,
svn_revnum_t *original_revision,
svn_wc__db_lock_t **lock,
svn_filesize_t *recorded_size,
apr_time_t *recorded_time,
const char **changelist,
svn_boolean_t *conflicted,
svn_boolean_t *op_root,
svn_boolean_t *have_props,
svn_boolean_t *props_mod,
svn_boolean_t *have_base,
svn_boolean_t *have_more_work,
svn_boolean_t *have_work,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
apr_int64_t repos_id, original_repos_id;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN4(
read_info(status, kind, revision, repos_relpath, &repos_id,
changed_rev, changed_date, changed_author,
depth, checksum, target, original_repos_relpath,
&original_repos_id, original_revision, lock,
recorded_size, recorded_time, changelist, conflicted,
op_root, have_props, props_mod,
have_base, have_more_work, have_work,
wcroot, local_relpath, result_pool, scratch_pool),
svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
wcroot, repos_id, result_pool),
svn_wc__db_fetch_repos_info(original_root_url, original_uuid,
wcroot, original_repos_id,
result_pool),
SVN_NO_ERROR,
wcroot);
return SVN_NO_ERROR;
}
static svn_error_t *
is_wclocked(svn_boolean_t *locked,
svn_wc__db_wcroot_t *wcroot,
const char *dir_relpath,
apr_pool_t *scratch_pool);
static svn_error_t *
find_conflict_descendants(svn_boolean_t *conflict_exists,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
assert(local_relpath[0] != '\0');
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_FIND_CONFLICT_DESCENDANT));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(conflict_exists, stmt));
return svn_error_trace(svn_sqlite__reset(stmt));
}
struct read_children_info_item_t
{
struct svn_wc__db_info_t info;
int op_depth;
int nr_layers;
svn_boolean_t was_dir;
};
static svn_error_t *
read_children_info(svn_wc__db_wcroot_t *wcroot,
const char *dir_relpath,
apr_hash_t *conflicts,
apr_hash_t *nodes,
svn_boolean_t base_tree_only,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
const char *repos_root_url = NULL;
const char *repos_uuid = NULL;
apr_int64_t last_repos_id = INVALID_REPOS_ID;
const char *last_repos_root_url = NULL;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
(base_tree_only
? STMT_SELECT_BASE_NODE_CHILDREN_INFO
: STMT_SELECT_NODE_CHILDREN_INFO)));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, dir_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
struct read_children_info_item_t *child_item;
const char *child_relpath = svn_sqlite__column_text(stmt, 19, NULL);
const char *name = svn_relpath_basename(child_relpath, NULL);
svn_error_t *err;
int op_depth;
svn_boolean_t new_child;
child_item = (base_tree_only ? NULL : svn_hash_gets(nodes, name));
if (child_item)
new_child = FALSE;
else
{
child_item = apr_pcalloc(result_pool, sizeof(*child_item));
new_child = TRUE;
}
op_depth = svn_sqlite__column_int(stmt, 0);
if (new_child)
{
struct svn_wc__db_info_t *child = &child_item->info;
child_item->op_depth = op_depth;
child->kind = svn_sqlite__column_token(stmt, 4, kind_map);
child->status = svn_sqlite__column_token(stmt, 3, presence_map);
if (op_depth != 0)
{
if (child->status == svn_wc__db_status_incomplete)
child->incomplete = TRUE;
err = convert_to_working_status(&child->status, child->status);
if (err)
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
}
if (op_depth != 0)
child->revnum = SVN_INVALID_REVNUM;
else
child->revnum = svn_sqlite__column_revnum(stmt, 5);
if (op_depth != 0)
child->repos_relpath = NULL;
else
child->repos_relpath = svn_sqlite__column_text(stmt, 2,
result_pool);
if (op_depth != 0 || svn_sqlite__column_is_null(stmt, 1))
{
child->repos_root_url = NULL;
child->repos_uuid = NULL;
}
else
{
apr_int64_t repos_id = svn_sqlite__column_int64(stmt, 1);
if (!repos_root_url ||
(last_repos_id != INVALID_REPOS_ID &&
repos_id != last_repos_id))
{
last_repos_root_url = repos_root_url;
err = svn_wc__db_fetch_repos_info(&repos_root_url,
&repos_uuid,
wcroot, repos_id,
result_pool);
if (err)
SVN_ERR(svn_error_compose_create(err,
svn_sqlite__reset(stmt)));
}
if (last_repos_id == INVALID_REPOS_ID)
last_repos_id = repos_id;
if (repos_id != last_repos_id)
{
err= svn_error_createf(
SVN_ERR_WC_DB_ERROR, NULL,
_("The node '%s' comes from unexpected repository "
"'%s', expected '%s'; if this node is a file "
"external using the correct URL in the external "
"definition can fix the problem, see issue #4087"),
child_relpath, repos_root_url, last_repos_root_url);
return svn_error_compose_create(err, svn_sqlite__reset(stmt));
}
child->repos_root_url = repos_root_url;
child->repos_uuid = repos_uuid;
}
child->changed_rev = svn_sqlite__column_revnum(stmt, 8);
child->changed_date = svn_sqlite__column_int64(stmt, 9);
child->changed_author = svn_sqlite__column_text(stmt, 10,
result_pool);
if (child->kind != svn_node_dir)
child->depth = svn_depth_unknown;
else
{
child->has_descendants = TRUE;
child_item->was_dir = TRUE;
child->depth = svn_sqlite__column_token_null(stmt, 11, depth_map,
svn_depth_unknown);
if (new_child)
{
err = is_wclocked(&child->locked, wcroot, child_relpath,
scratch_pool);
if (err)
SVN_ERR(svn_error_compose_create(err,
svn_sqlite__reset(stmt)));
}
}
child->recorded_time = svn_sqlite__column_int64(stmt, 13);
child->recorded_size = get_recorded_size(stmt, 7);
child->has_checksum = !svn_sqlite__column_is_null(stmt, 6);
child->copied = op_depth > 0 && !svn_sqlite__column_is_null(stmt, 2);
child->had_props = SQLITE_PROPERTIES_AVAILABLE(stmt, 14);
#ifdef HAVE_SYMLINK
if (child->had_props)
{
apr_hash_t *properties;
err = svn_sqlite__column_properties(&properties, stmt, 14,
scratch_pool, scratch_pool);
if (err)
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
child->special = (child->had_props
&& svn_hash_gets(properties, SVN_PROP_SPECIAL));
}
#endif
if (op_depth == 0)
child->op_root = FALSE;
else
child->op_root = (op_depth == relpath_depth(child_relpath));
if (op_depth && child->op_root)
child_item->info.moved_here = svn_sqlite__column_boolean(stmt, 20);
if (new_child)
svn_hash_sets(nodes, apr_pstrdup(result_pool, name), child);
}
else if (!child_item->was_dir
&& svn_sqlite__column_token(stmt, 4, kind_map) == svn_node_dir)
{
child_item->was_dir = TRUE;
err = find_conflict_descendants(&child_item->info.has_descendants,
wcroot, child_relpath,
scratch_pool);
if (err)
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
}
if (op_depth == 0)
{
child_item->info.have_base = TRUE;
child_item->info.lock = lock_from_columns(stmt, 15, 16, 17, 18,
result_pool);
child_item->info.file_external = svn_sqlite__column_boolean(stmt,
22);
}
else
{
const char *moved_to_relpath;
child_item->nr_layers++;
child_item->info.have_more_work = (child_item->nr_layers > 1);
moved_to_relpath = svn_sqlite__column_text(stmt, 21, NULL);
if (moved_to_relpath)
{
struct svn_wc__db_moved_to_info_t *moved_to;
struct svn_wc__db_moved_to_info_t **next;
const char *shadow_op_relpath;
moved_to = apr_pcalloc(result_pool, sizeof(*moved_to));
moved_to->moved_to_abspath = svn_dirent_join(wcroot->abspath,
moved_to_relpath,
result_pool);
shadow_op_relpath = svn_relpath_prefix(child_relpath, op_depth,
scratch_pool);
moved_to->shadow_op_root_abspath =
svn_dirent_join(wcroot->abspath, shadow_op_relpath,
result_pool);
next = &child_item->info.moved_to;
while (*next &&
0 < strcmp((*next)->shadow_op_root_abspath,
moved_to->shadow_op_root_abspath))
next = &((*next)->next);
moved_to->next = *next;
*next = moved_to;
}
}
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
if (!base_tree_only)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_ACTUAL_CHILDREN_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, dir_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
struct read_children_info_item_t *child_item;
struct svn_wc__db_info_t *child;
const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
const char *name = svn_relpath_basename(child_relpath, NULL);
child_item = svn_hash_gets(nodes, name);
if (!child_item)
{
child_item = apr_pcalloc(result_pool, sizeof(*child_item));
child_item->info.status = svn_wc__db_status_not_present;
}
child = &child_item->info;
child->changelist = svn_sqlite__column_text(stmt, 1, result_pool);
child->props_mod = !svn_sqlite__column_is_null(stmt, 2);
#ifdef HAVE_SYMLINK
if (child->props_mod)
{
svn_error_t *err;
apr_hash_t *properties;
err = svn_sqlite__column_properties(&properties, stmt, 2,
scratch_pool, scratch_pool);
if (err)
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
child->special = (NULL != svn_hash_gets(properties,
SVN_PROP_SPECIAL));
}
#endif
child->conflicted = !svn_sqlite__column_is_null(stmt, 3);
if (child->conflicted)
svn_hash_sets(conflicts, apr_pstrdup(result_pool, name), "");
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_children_info(apr_hash_t **nodes,
apr_hash_t **conflicts,
svn_wc__db_t *db,
const char *dir_abspath,
svn_boolean_t base_tree_only,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *dir_relpath;
*conflicts = apr_hash_make(result_pool);
*nodes = apr_hash_make(result_pool);
SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &dir_relpath, db,
dir_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
read_children_info(wcroot, dir_relpath, *conflicts, *nodes,
base_tree_only, result_pool, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
static svn_error_t *
read_single_info(const struct svn_wc__db_info_t **info,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_boolean_t base_tree_only,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
struct svn_wc__db_info_t *mtb;
apr_int64_t repos_id;
const svn_checksum_t *checksum;
const char *original_repos_relpath;
svn_boolean_t have_work;
apr_hash_t *properties;
mtb = apr_pcalloc(result_pool, sizeof(*mtb));
if (!base_tree_only)
SVN_ERR(read_info(&mtb->status, &mtb->kind, &mtb->revnum,
&mtb->repos_relpath, &repos_id, &mtb->changed_rev,
&mtb->changed_date, &mtb->changed_author, &mtb->depth,
&checksum, NULL, &original_repos_relpath, NULL, NULL,
&mtb->lock, &mtb->recorded_size, &mtb->recorded_time,
&mtb->changelist, &mtb->conflicted, &mtb->op_root,
&mtb->had_props, &mtb->props_mod, &mtb->have_base,
&mtb->have_more_work, &have_work,
wcroot, local_relpath, result_pool, scratch_pool));
else
{
svn_boolean_t update_root;
have_work = FALSE;
original_repos_relpath = NULL;
SVN_ERR(svn_wc__db_base_get_info_internal(
&mtb->status, &mtb->kind, &mtb->revnum, &mtb->repos_relpath,
&repos_id, &mtb->changed_rev, &mtb->changed_date,
&mtb->changed_author, &mtb->depth, &checksum, NULL,
&mtb->lock, &mtb->had_props, &properties, &update_root,
wcroot, local_relpath, scratch_pool, scratch_pool));
mtb->have_base = TRUE;
mtb->file_external = (update_root && mtb->kind == svn_node_file);
}
if (have_work && (mtb->have_base || mtb->have_more_work))
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MOVED_TO_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
struct svn_wc__db_moved_to_info_t *move;
int op_depth = svn_sqlite__column_int(stmt, 0);
const char *moved_to_relpath = svn_sqlite__column_text(stmt, 1, NULL);
const char *cur_relpath;
move = apr_pcalloc(result_pool, sizeof(*move));
move->moved_to_abspath = svn_dirent_join(wcroot->abspath,
moved_to_relpath,
result_pool);
cur_relpath = svn_relpath_prefix(local_relpath, op_depth,
scratch_pool);
move->shadow_op_root_abspath = svn_dirent_join(wcroot->abspath,
cur_relpath,
result_pool);
move->next = mtb->moved_to;
mtb->moved_to = move;
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
}
if (!base_tree_only && mtb->have_base
&& (have_work || mtb->kind == svn_node_file))
{
svn_boolean_t update_root;
svn_wc__db_lock_t **lock_arg = NULL;
if (have_work)
lock_arg = &mtb->lock;
SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, lock_arg, NULL, NULL,
&update_root,
wcroot, local_relpath,
result_pool, scratch_pool));
mtb->file_external = (update_root && mtb->kind == svn_node_file);
}
if (mtb->status == svn_wc__db_status_added)
{
svn_wc__db_status_t status;
SVN_ERR(scan_addition(&status, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL,
wcroot, local_relpath,
result_pool, scratch_pool));
mtb->moved_here = (status == svn_wc__db_status_moved_here);
mtb->incomplete = (status == svn_wc__db_status_incomplete);
}
#ifdef HAVE_SYMLINK
if (mtb->kind == svn_node_file
&& (mtb->had_props || mtb->props_mod
|| (base_tree_only && properties)))
{
if (!base_tree_only)
{
if (mtb->props_mod)
SVN_ERR(svn_wc__db_read_props_internal(&properties,
wcroot, local_relpath,
scratch_pool, scratch_pool));
else
SVN_ERR(db_read_pristine_props(&properties, wcroot, local_relpath,
TRUE ,
scratch_pool, scratch_pool));
}
mtb->special = (NULL != svn_hash_gets(properties, SVN_PROP_SPECIAL));
}
#endif
mtb->has_checksum = (checksum != NULL);
mtb->copied = (original_repos_relpath != NULL);
SVN_ERR(svn_wc__db_fetch_repos_info(&mtb->repos_root_url, &mtb->repos_uuid,
wcroot, repos_id, result_pool));
if (!base_tree_only && mtb->kind == svn_node_dir)
SVN_ERR(is_wclocked(&mtb->locked, wcroot, local_relpath, scratch_pool));
if (mtb->kind == svn_node_dir)
mtb->has_descendants = TRUE;
else
SVN_ERR(find_conflict_descendants(&mtb->has_descendants,
wcroot, local_relpath, scratch_pool));
*info = mtb;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_single_info(const struct svn_wc__db_info_t **info,
svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t base_tree_only,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(read_single_info(info, wcroot, local_relpath,
base_tree_only,
result_pool, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_pristine_info(svn_wc__db_status_t *status,
svn_node_kind_t *kind,
svn_revnum_t *changed_rev,
apr_time_t *changed_date,
const char **changed_author,
svn_depth_t *depth,
const svn_checksum_t **checksum,
const char **target,
svn_boolean_t *had_props,
apr_hash_t **props,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
svn_error_t *err = NULL;
int op_depth;
svn_wc__db_status_t raw_status;
svn_node_kind_t node_kind;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
{
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
svn_sqlite__reset(stmt),
_("The node '%s' was not found."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
op_depth = svn_sqlite__column_int(stmt, 0);
raw_status = svn_sqlite__column_token(stmt, 3, presence_map);
if (op_depth > 0 && raw_status == svn_wc__db_status_base_deleted)
{
SVN_ERR(svn_sqlite__step_row(stmt));
op_depth = svn_sqlite__column_int(stmt, 0);
raw_status = svn_sqlite__column_token(stmt, 3, presence_map);
}
node_kind = svn_sqlite__column_token(stmt, 4, kind_map);
if (status)
{
if (op_depth > 0)
{
err = svn_error_compose_create(err,
convert_to_working_status(
status,
raw_status));
}
else
*status = raw_status;
}
if (kind)
{
*kind = node_kind;
}
if (changed_rev)
{
*changed_rev = svn_sqlite__column_revnum(stmt, 8);
}
if (changed_date)
{
*changed_date = svn_sqlite__column_int64(stmt, 9);
}
if (changed_author)
{
*changed_author = svn_sqlite__column_text(stmt, 10,
result_pool);
}
if (depth)
{
if (node_kind != svn_node_dir)
{
*depth = svn_depth_unknown;
}
else
{
*depth = svn_sqlite__column_token_null(stmt, 11, depth_map,
svn_depth_unknown);
}
}
if (checksum)
{
if (node_kind != svn_node_file)
{
*checksum = NULL;
}
else
{
svn_error_t *err2;
err2 = svn_sqlite__column_checksum(checksum, stmt, 6, result_pool);
if (err2 != NULL)
{
if (err)
err = svn_error_compose_create(
err,
svn_error_createf(
err->apr_err, err2,
_("The node '%s' has a corrupt checksum value."),
path_for_error_message(wcroot, local_relpath,
scratch_pool)));
else
err = err2;
}
}
}
if (target)
{
if (node_kind != svn_node_symlink)
*target = NULL;
else
*target = svn_sqlite__column_text(stmt, 12, result_pool);
}
if (had_props)
{
*had_props = SQLITE_PROPERTIES_AVAILABLE(stmt, 14);
}
if (props)
{
if (raw_status == svn_wc__db_status_normal
|| raw_status == svn_wc__db_status_incomplete)
{
SVN_ERR(svn_sqlite__column_properties(props, stmt, 14,
result_pool, scratch_pool));
if (*props == NULL)
*props = apr_hash_make(result_pool);
}
else
{
assert(svn_sqlite__column_is_null(stmt, 14));
*props = NULL;
}
}
return svn_error_trace(
svn_error_compose_create(err,
svn_sqlite__reset(stmt)));
}
svn_error_t *
svn_wc__db_read_children_walker_info(const apr_array_header_t **items,
svn_wc__db_t *db,
const char *dir_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *dir_relpath;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_array_header_t *nodes;
SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &dir_relpath, db,
dir_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_CHILDREN_WALKER_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, dir_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
nodes = apr_array_make(result_pool, 16,
sizeof(struct svn_wc__db_walker_info_t *));
while (have_row)
{
struct svn_wc__db_walker_info_t *child;
const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
const char *name = svn_relpath_basename(child_relpath, result_pool);
int op_depth = svn_sqlite__column_int(stmt, 1);
svn_error_t *err;
child = apr_palloc(result_pool, sizeof(*child));
child->name = name;
child->status = svn_sqlite__column_token(stmt, 2, presence_map);
if (op_depth > 0)
{
err = convert_to_working_status(&child->status, child->status);
if (err)
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
}
child->kind = svn_sqlite__column_token(stmt, 3, kind_map);
APR_ARRAY_PUSH(nodes, struct svn_wc__db_walker_info_t *) = child;
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
*items = nodes;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_node_install_info(const char **wcroot_abspath,
const svn_checksum_t **sha1_checksum,
apr_hash_t **pristine_props,
apr_time_t *changed_date,
svn_wc__db_t *db,
const char *local_abspath,
const char *wri_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt;
svn_error_t *err = NULL;
svn_boolean_t have_row;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
if (!wri_abspath)
wri_abspath = local_abspath;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
if (local_abspath != wri_abspath
&& strcmp(local_abspath, wri_abspath))
{
if (!svn_dirent_is_ancestor(wcroot->abspath, local_abspath))
return svn_error_createf(
SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' is not in working copy '%s'"),
svn_dirent_local_style(local_abspath, scratch_pool),
svn_dirent_local_style(wcroot->abspath, scratch_pool));
local_relpath = svn_dirent_skip_ancestor(wcroot->abspath, local_abspath);
}
if (wcroot_abspath != NULL)
*wcroot_abspath = apr_pstrdup(result_pool, wcroot->abspath);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
if (sha1_checksum)
err = svn_sqlite__column_checksum(sha1_checksum, stmt, 6, result_pool);
if (!err && pristine_props)
{
err = svn_sqlite__column_properties(pristine_props, stmt, 14,
result_pool, scratch_pool);
if (*pristine_props == NULL)
*pristine_props = apr_hash_make(result_pool);
}
if (changed_date)
*changed_date = svn_sqlite__column_int64(stmt, 9);
}
else
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
svn_sqlite__reset(stmt),
_("The node '%s' is not installable"),
svn_dirent_local_style(local_abspath,
scratch_pool));
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
return SVN_NO_ERROR;
}
static svn_error_t *
db_read_repos_info(svn_revnum_t *revision,
const char **repos_relpath,
apr_int64_t *repos_id,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_status_t status;
SVN_ERR(read_info(&status, NULL, revision, repos_relpath, repos_id, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
wcroot, local_relpath, result_pool, scratch_pool));
if ((repos_relpath && !*repos_relpath)
|| (repos_id && *repos_id == INVALID_REPOS_ID))
{
if (status == svn_wc__db_status_added)
{
SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id, NULL,
NULL, NULL, NULL, NULL, NULL,
wcroot, local_relpath,
result_pool, scratch_pool));
}
else if (status == svn_wc__db_status_deleted)
{
const char *base_del_relpath;
const char *work_del_relpath;
SVN_ERR(scan_deletion(&base_del_relpath, NULL,
&work_del_relpath,
NULL, wcroot,
local_relpath,
scratch_pool,
scratch_pool));
if (work_del_relpath)
{
const char *work_relpath = NULL;
SVN_ERR_ASSERT(work_del_relpath != NULL);
work_relpath = svn_relpath_dirname(work_del_relpath,
scratch_pool);
SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id,
NULL, NULL, NULL, NULL, NULL, NULL,
wcroot, work_relpath,
scratch_pool, scratch_pool));
if (repos_relpath)
*repos_relpath = svn_relpath_join(
*repos_relpath,
svn_dirent_skip_ancestor(work_relpath,
local_relpath),
result_pool);
}
else if (base_del_relpath)
{
SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, revision,
repos_relpath,
repos_id,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
wcroot,
base_del_relpath,
scratch_pool,
scratch_pool));
if (repos_relpath)
*repos_relpath = svn_relpath_join(
*repos_relpath,
svn_dirent_skip_ancestor(base_del_relpath,
local_relpath),
result_pool);
}
else
SVN_ERR_MALFUNCTION();
}
else if (status == svn_wc__db_status_excluded)
{
const char *parent_relpath;
const char *name;
svn_relpath_split(&parent_relpath, &name, local_relpath,
scratch_pool);
SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id, NULL,
NULL, NULL, NULL, NULL, NULL,
wcroot, parent_relpath,
scratch_pool, scratch_pool));
if (repos_relpath)
*repos_relpath = svn_relpath_join(*repos_relpath, name,
result_pool);
return SVN_NO_ERROR;
}
else
{
SVN_ERR_MALFUNCTION();
}
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_repos_info(svn_revnum_t *revision,
const char **repos_relpath,
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)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
apr_int64_t repos_id = INVALID_REPOS_ID;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN4(db_read_repos_info(revision, repos_relpath,
(repos_root_url || repos_uuid)
? &repos_id : NULL,
wcroot, local_relpath,
result_pool, scratch_pool),
svn_wc__db_fetch_repos_info(repos_root_url,
repos_uuid,
wcroot, repos_id,
result_pool),
SVN_NO_ERROR, SVN_NO_ERROR,
wcroot);
return SVN_NO_ERROR;
}
typedef struct cache_props_baton_t
{
svn_depth_t depth;
svn_boolean_t pristine;
const apr_array_header_t *changelists;
svn_cancel_func_t cancel_func;
void *cancel_baton;
} cache_props_baton_t;
static svn_error_t *
cache_props_recursive(void *cb_baton,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
cache_props_baton_t *baton = cb_baton;
svn_sqlite__stmt_t *stmt;
int stmt_idx;
SVN_ERR(populate_targets_tree(wcroot, local_relpath, baton->depth,
baton->changelists, scratch_pool));
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
STMT_CREATE_TARGET_PROP_CACHE));
if (baton->pristine)
stmt_idx = STMT_CACHE_TARGET_PRISTINE_PROPS;
else
stmt_idx = STMT_CACHE_TARGET_PROPS;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, stmt_idx));
SVN_ERR(svn_sqlite__bind_int64(stmt, 1, wcroot->wc_id));
SVN_ERR(svn_sqlite__step_done(stmt));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_props_streamily(svn_wc__db_t *db,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t pristine,
const apr_array_header_t *changelists,
svn_wc__proplist_receiver_t receiver_func,
void *receiver_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt;
cache_props_baton_t baton;
svn_boolean_t have_row;
apr_pool_t *iterpool;
svn_error_t *err = NULL;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(receiver_func);
SVN_ERR_ASSERT((depth == svn_depth_files) ||
(depth == svn_depth_immediates) ||
(depth == svn_depth_infinity));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
baton.depth = depth;
baton.pristine = pristine;
baton.changelists = changelists;
baton.cancel_func = cancel_func;
baton.cancel_baton = cancel_baton;
SVN_ERR(with_finalization(wcroot, local_relpath,
cache_props_recursive, &baton,
NULL, NULL,
cancel_func, cancel_baton,
NULL, NULL,
STMT_DROP_TARGETS_LIST,
scratch_pool));
iterpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_ALL_TARGET_PROP_CACHE));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (!err && have_row)
{
apr_hash_t *props;
svn_pool_clear(iterpool);
SVN_ERR(svn_sqlite__column_properties(&props, stmt, 1, iterpool,
iterpool));
if (cancel_func)
err = cancel_func(cancel_baton);
if (!err && props && apr_hash_count(props) != 0)
{
const char *child_relpath;
const char *child_abspath;
child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
child_abspath = svn_dirent_join(wcroot->abspath,
child_relpath, iterpool);
err = receiver_func(receiver_baton, child_abspath, props, iterpool);
}
err = svn_error_compose_create(err, svn_sqlite__step(&have_row, stmt));
}
err = svn_error_compose_create(err, svn_sqlite__reset(stmt));
svn_pool_destroy(iterpool);
SVN_ERR(svn_error_compose_create(
err,
svn_sqlite__exec_statements(wcroot->sdb,
STMT_DROP_TARGET_PROP_CACHE)));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_props_internal(apr_hash_t **props,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
svn_error_t *err = NULL;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_ACTUAL_PROPS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row && !svn_sqlite__column_is_null(stmt, 0))
{
err = svn_sqlite__column_properties(props, stmt, 0,
result_pool, scratch_pool);
}
else
have_row = FALSE;
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
if (have_row)
return SVN_NO_ERROR;
SVN_ERR(db_read_pristine_props(props, wcroot, local_relpath, FALSE,
result_pool, scratch_pool));
if (*props == NULL)
{
*props = apr_hash_make(result_pool);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_props(apr_hash_t **props,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(svn_wc__db_read_props_internal(props, wcroot,
local_relpath,
result_pool,
scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
static svn_error_t *
db_read_pristine_props(apr_hash_t **props,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_boolean_t deleted_ok,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
svn_wc__db_status_t presence;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_NODE_PROPS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
{
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
svn_sqlite__reset(stmt),
_("The node '%s' was not found."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
presence = svn_sqlite__column_token(stmt, 1, presence_map);
if (presence == svn_wc__db_status_base_deleted && deleted_ok)
{
SVN_ERR(svn_sqlite__step(&have_row, stmt));
SVN_ERR_ASSERT(have_row);
presence = svn_sqlite__column_token(stmt, 1, presence_map);
}
if (presence == svn_wc__db_status_normal
|| presence == svn_wc__db_status_incomplete)
{
svn_error_t *err;
err = svn_sqlite__column_properties(props, stmt, 0, result_pool,
scratch_pool);
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
if (!*props)
*props = apr_hash_make(result_pool);
return SVN_NO_ERROR;
}
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS,
svn_sqlite__reset(stmt),
_("The node '%s' has a status that"
" has no properties."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
svn_error_t *
svn_wc__db_read_pristine_props(apr_hash_t **props,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(db_read_pristine_props(props, wcroot, local_relpath, TRUE,
result_pool, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_prop_retrieve_recursive(apr_hash_t **values,
svn_wc__db_t *db,
const char *local_abspath,
const char *propname,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_pool_t *iterpool;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_CURRENT_PROPS_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
*values = apr_hash_make(result_pool);
SVN_ERR(svn_sqlite__step(&have_row, stmt));
iterpool = svn_pool_create(scratch_pool);
while (have_row)
{
apr_hash_t *node_props;
svn_string_t *value;
svn_pool_clear(iterpool);
SVN_ERR(svn_sqlite__column_properties(&node_props, stmt, 0,
iterpool, iterpool));
value = (node_props
? svn_hash_gets(node_props, propname)
: NULL);
if (value)
{
svn_hash_sets(*values,
svn_dirent_join(wcroot->abspath,
svn_sqlite__column_text(stmt, 1, NULL),
result_pool),
svn_string_dup(value, result_pool));
}
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
svn_pool_destroy(iterpool);
return svn_error_trace(svn_sqlite__reset(stmt));
}
static void
filter_unwanted_props(apr_hash_t *prop_hash,
const char * propname,
apr_pool_t *scratch_pool)
{
apr_hash_index_t *hi;
for (hi = apr_hash_first(scratch_pool, prop_hash);
hi;
hi = apr_hash_next(hi))
{
const char *ipropname = apr_hash_this_key(hi);
if (strcmp(ipropname, propname) != 0)
svn_hash_sets(prop_hash, ipropname, NULL);
}
return;
}
static svn_error_t *
db_get_changed_props(apr_hash_t **actual_props,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_ACTUAL_PROPS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row && !svn_sqlite__column_is_null(stmt, 0))
SVN_ERR(svn_sqlite__column_properties(actual_props, stmt, 0,
result_pool, scratch_pool));
else
*actual_props = NULL;
return svn_error_trace(svn_sqlite__reset(stmt));
}
static svn_error_t *
db_read_inherited_props(apr_array_header_t **inherited_props,
apr_hash_t **actual_props,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
const char *propname,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
int i;
apr_array_header_t *cached_iprops = NULL;
apr_array_header_t *iprops;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
svn_sqlite__stmt_t *stmt;
const char *relpath;
const char *expected_parent_repos_relpath = NULL;
const char *parent_relpath;
iprops = apr_array_make(result_pool, 1,
sizeof(svn_prop_inherited_item_t *));
*inherited_props = iprops;
if (actual_props)
*actual_props = NULL;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
relpath = local_relpath;
for (relpath = local_relpath; relpath; relpath = parent_relpath)
{
svn_boolean_t have_row;
int op_depth;
svn_wc__db_status_t status;
apr_hash_t *node_props;
parent_relpath = relpath[0] ? svn_relpath_dirname(relpath, scratch_pool)
: NULL;
svn_pool_clear(iterpool);
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
return svn_error_createf(
SVN_ERR_WC_PATH_NOT_FOUND, svn_sqlite__reset(stmt),
_("The node '%s' was not found."),
path_for_error_message(wcroot, relpath,
scratch_pool));
op_depth = svn_sqlite__column_int(stmt, 0);
status = svn_sqlite__column_token(stmt, 3, presence_map);
if (status != svn_wc__db_status_normal
&& status != svn_wc__db_status_incomplete)
return svn_error_createf(
SVN_ERR_WC_PATH_UNEXPECTED_STATUS, svn_sqlite__reset(stmt),
_("The node '%s' has a status that has no properties."),
path_for_error_message(wcroot, relpath,
scratch_pool));
if (op_depth > 0)
{
}
else if (expected_parent_repos_relpath)
{
const char *repos_relpath = svn_sqlite__column_text(stmt, 2, NULL);
if (strcmp(expected_parent_repos_relpath, repos_relpath) != 0)
{
SVN_ERR(svn_sqlite__reset(stmt));
break;
}
expected_parent_repos_relpath =
svn_relpath_dirname(expected_parent_repos_relpath, scratch_pool);
}
else
{
const char *repos_relpath = svn_sqlite__column_text(stmt, 2, NULL);
expected_parent_repos_relpath =
svn_relpath_dirname(repos_relpath, scratch_pool);
}
if (op_depth == 0
&& !svn_sqlite__column_is_null(stmt, 16))
{
SVN_ERR(svn_sqlite__column_iprops(&cached_iprops, stmt, 16,
result_pool, iterpool));
parent_relpath = NULL;
}
SVN_ERR(svn_sqlite__column_properties(&node_props, stmt, 14,
iterpool, iterpool));
SVN_ERR(svn_sqlite__reset(stmt));
if (relpath != local_relpath)
{
apr_hash_t *changed_props;
SVN_ERR(db_get_changed_props(&changed_props, wcroot, relpath,
result_pool, iterpool));
if (changed_props)
node_props = changed_props;
else if (node_props)
node_props = svn_prop_hash_dup(node_props, result_pool);
if (node_props && apr_hash_count(node_props))
{
if (propname)
filter_unwanted_props(node_props, propname, iterpool);
if (apr_hash_count(node_props))
{
svn_prop_inherited_item_t *iprop_elt =
apr_pcalloc(result_pool,
sizeof(svn_prop_inherited_item_t));
iprop_elt->path_or_url = svn_dirent_join(wcroot->abspath,
relpath,
result_pool);
iprop_elt->prop_hash = node_props;
svn_sort__array_insert(iprops, &iprop_elt, 0);
}
}
}
else if (actual_props)
{
apr_hash_t *changed_props;
SVN_ERR(db_get_changed_props(&changed_props, wcroot, relpath,
result_pool, iterpool));
if (changed_props)
*actual_props = changed_props;
else if (node_props)
*actual_props = svn_prop_hash_dup(node_props, result_pool);
}
}
if (cached_iprops)
{
for (i = cached_iprops->nelts - 1; i >= 0; i--)
{
svn_prop_inherited_item_t *cached_iprop =
APR_ARRAY_IDX(cached_iprops, i, svn_prop_inherited_item_t *);
if (apr_hash_count(cached_iprop->prop_hash) == 0)
continue;
if (propname)
filter_unwanted_props(cached_iprop->prop_hash, propname,
scratch_pool);
if (apr_hash_count(cached_iprop->prop_hash))
svn_sort__array_insert(iprops, &cached_iprop, 0);
}
}
if (actual_props && !*actual_props)
*actual_props = apr_hash_make(result_pool);
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_inherited_props(apr_array_header_t **iprops,
apr_hash_t **actual_props,
svn_wc__db_t *db,
const char *local_abspath,
const char *propname,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(db_read_inherited_props(iprops, actual_props,
wcroot, local_relpath, propname,
result_pool, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
static svn_error_t *
get_children_with_cached_iprops(apr_hash_t **iprop_paths,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_depth_t depth,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
*iprop_paths = apr_hash_make(result_pool);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_IPROPS_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
const char *relpath_with_cache = svn_sqlite__column_text(stmt, 0,
NULL);
const char *abspath_with_cache = svn_dirent_join(wcroot->abspath,
relpath_with_cache,
result_pool);
svn_hash_sets(*iprop_paths, abspath_with_cache,
svn_sqlite__column_text(stmt, 1, result_pool));
}
SVN_ERR(svn_sqlite__reset(stmt));
if (depth == svn_depth_empty)
return SVN_NO_ERROR;
if (depth == svn_depth_files
|| depth == svn_depth_immediates)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_IPROPS_CHILDREN));
}
else
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_IPROPS_RECURSIVE));
}
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
const char *relpath_with_cache = svn_sqlite__column_text(stmt, 0,
NULL);
const char *abspath_with_cache = svn_dirent_join(wcroot->abspath,
relpath_with_cache,
result_pool);
svn_hash_sets(*iprop_paths, abspath_with_cache,
svn_sqlite__column_text(stmt, 1, result_pool));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
if (depth == svn_depth_files)
{
apr_hash_index_t *hi;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
for (hi = apr_hash_first(scratch_pool, *iprop_paths);
hi;
hi = apr_hash_next(hi))
{
const char *child_abspath = apr_hash_this_key(hi);
const char *child_relpath;
svn_node_kind_t child_kind;
svn_pool_clear(iterpool);
child_relpath = svn_dirent_is_child(local_relpath, child_abspath,
NULL);
if (! child_relpath)
{
continue;
}
SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &child_kind, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
wcroot, child_relpath,
scratch_pool,
scratch_pool));
if (child_kind != svn_node_file)
{
svn_hash_sets(*iprop_paths, child_abspath, NULL);
}
}
svn_pool_destroy(iterpool);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_get_children_with_cached_iprops(apr_hash_t **iprop_paths,
svn_depth_t depth,
const char *local_abspath,
svn_wc__db_t *db,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool,
scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
get_children_with_cached_iprops(iprop_paths, wcroot, local_relpath,
depth, result_pool, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_children_of_working_node(const apr_array_header_t **children,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
return svn_error_trace(
gather_children(children, wcroot, local_relpath,
STMT_SELECT_WORKING_CHILDREN, -1,
result_pool, scratch_pool));
}
svn_error_t *
svn_wc__db_base_read_not_present_children(
const apr_array_header_t **children,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
return svn_error_trace(
gather_children(children, wcroot, local_relpath,
STMT_SELECT_BASE_NOT_PRESENT_CHILDREN, -1,
result_pool, scratch_pool));
}
static svn_error_t *
check_replace_txn(svn_boolean_t *is_replace_root_p,
svn_boolean_t *base_replace_p,
svn_boolean_t *is_replace_p,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
svn_boolean_t is_replace = FALSE;
int replaced_op_depth;
svn_wc__db_status_t replaced_status;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
svn_sqlite__reset(stmt),
_("The node '%s' was not found."),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
{
svn_wc__db_status_t status;
status = svn_sqlite__column_token(stmt, 3, presence_map);
if (status != svn_wc__db_status_normal)
return svn_error_trace(svn_sqlite__reset(stmt));
}
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
return svn_error_trace(svn_sqlite__reset(stmt));
replaced_status = svn_sqlite__column_token(stmt, 3, presence_map);
if (replaced_status != svn_wc__db_status_not_present
&& replaced_status != svn_wc__db_status_excluded
&& replaced_status != svn_wc__db_status_server_excluded
&& replaced_status != svn_wc__db_status_base_deleted)
{
is_replace = TRUE;
if (is_replace_p)
*is_replace_p = TRUE;
}
replaced_op_depth = svn_sqlite__column_int(stmt, 0);
if (base_replace_p)
{
int op_depth = svn_sqlite__column_int(stmt, 0);
while (op_depth != 0 && have_row)
{
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
op_depth = svn_sqlite__column_int(stmt, 0);
}
if (have_row && op_depth == 0)
{
svn_wc__db_status_t base_status;
base_status = svn_sqlite__column_token(stmt, 3, presence_map);
*base_replace_p = (base_status != svn_wc__db_status_not_present);
}
}
SVN_ERR(svn_sqlite__reset(stmt));
if (!is_replace_root_p || !is_replace)
return SVN_NO_ERROR;
if (replaced_status != svn_wc__db_status_base_deleted)
{
int parent_op_depth;
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
svn_relpath_dirname(local_relpath,
scratch_pool)));
SVN_ERR(svn_sqlite__step_row(stmt));
parent_op_depth = svn_sqlite__column_int(stmt, 0);
if (parent_op_depth >= replaced_op_depth)
{
*is_replace_root_p = (parent_op_depth == replaced_op_depth);
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
parent_op_depth = svn_sqlite__column_int(stmt, 0);
SVN_ERR(svn_sqlite__reset(stmt));
if (!have_row)
*is_replace_root_p = TRUE;
else if (parent_op_depth < replaced_op_depth)
*is_replace_root_p = TRUE;
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_node_check_replace(svn_boolean_t *is_replace_root,
svn_boolean_t *base_replace,
svn_boolean_t *is_replace,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
if (is_replace_root)
*is_replace_root = FALSE;
if (base_replace)
*base_replace = FALSE;
if (is_replace)
*is_replace = FALSE;
if (local_relpath[0] == '\0')
return SVN_NO_ERROR;
SVN_WC__DB_WITH_TXN(
check_replace_txn(is_replace_root, base_replace, is_replace,
wcroot, local_relpath, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_children(const apr_array_header_t **children,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
return gather_children(children, wcroot, local_relpath,
STMT_SELECT_NODE_CHILDREN, -1,
result_pool, scratch_pool);
}
static svn_error_t *
relocate_txn(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
const char *repos_root_url,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
apr_int64_t new_repos_id;
const char *local_dir_relpath;
svn_wc__db_status_t status;
const char *repos_uuid;
svn_boolean_t have_base_node;
apr_int64_t old_repos_id;
local_dir_relpath = local_relpath;
SVN_ERR(read_info(&status,
NULL, NULL, NULL, &old_repos_id,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL,
&have_base_node, NULL, NULL,
wcroot, local_relpath,
scratch_pool, scratch_pool));
if (status == svn_wc__db_status_excluded)
{
const char *parent_relpath = svn_relpath_dirname(local_dir_relpath,
scratch_pool);
SVN_ERR(read_info(&status,
NULL, NULL, NULL, &old_repos_id,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
wcroot, parent_relpath,
scratch_pool, scratch_pool));
local_dir_relpath = parent_relpath;
}
if (old_repos_id == INVALID_REPOS_ID)
{
if (status == svn_wc__db_status_deleted)
{
const char *work_del_relpath;
SVN_ERR(scan_deletion(NULL, NULL,
&work_del_relpath, NULL,
wcroot, local_dir_relpath,
scratch_pool,
scratch_pool));
if (work_del_relpath)
{
status = svn_wc__db_status_added;
local_dir_relpath = svn_relpath_dirname(work_del_relpath,
scratch_pool);
}
}
if (status == svn_wc__db_status_added)
{
SVN_ERR(scan_addition(NULL, NULL, NULL, &old_repos_id,
NULL, NULL, NULL, NULL, NULL, NULL,
wcroot, local_dir_relpath,
scratch_pool, scratch_pool));
}
else
SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL, NULL,
&old_repos_id,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
wcroot, local_dir_relpath,
scratch_pool, scratch_pool));
}
SVN_ERR(svn_wc__db_fetch_repos_info(NULL, &repos_uuid, wcroot,
old_repos_id, scratch_pool));
SVN_ERR_ASSERT(repos_uuid);
SVN_ERR(create_repos_id(&new_repos_id, repos_root_url, repos_uuid,
wcroot->sdb, scratch_pool));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_RECURSIVE_UPDATE_NODE_REPO));
SVN_ERR(svn_sqlite__bindf(stmt, "isii", wcroot->wc_id, local_relpath,
old_repos_id, new_repos_id));
SVN_ERR(svn_sqlite__step_done(stmt));
if (have_base_node)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_LOCK_REPOS_ID));
SVN_ERR(svn_sqlite__bindf(stmt, "ii", old_repos_id, new_repos_id));
SVN_ERR(svn_sqlite__step_done(stmt));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_global_relocate(svn_wc__db_t *db,
const char *local_dir_abspath,
const char *repos_root_url,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_dir_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_dir_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
relocate_txn(wcroot, local_relpath, repos_root_url, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_dir_abspath, svn_depth_infinity,
scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
determine_commit_repos_info(apr_int64_t *repos_id,
const char **repos_relpath,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
int op_depth;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
svn_sqlite__reset(stmt),
_("The node '%s' was not found."),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
op_depth = svn_sqlite__column_int(stmt, 0);
if (op_depth > 0)
{
svn_wc__db_status_t presence = svn_sqlite__column_token(stmt, 3,
presence_map);
if (presence == svn_wc__db_status_base_deleted)
{
SVN_ERR(svn_sqlite__step_row(stmt));
op_depth = svn_sqlite__column_int(stmt, 0);
}
else
{
const char *parent_repos_relpath;
const char *parent_relpath;
const char *name;
SVN_ERR(svn_sqlite__reset(stmt));
svn_relpath_split(&parent_relpath, &name, local_relpath,
scratch_pool);
SVN_ERR(determine_commit_repos_info(repos_id, &parent_repos_relpath,
wcroot, parent_relpath,
scratch_pool, scratch_pool));
*repos_relpath = svn_relpath_join(parent_repos_relpath, name,
result_pool);
return SVN_NO_ERROR;
}
}
SVN_ERR_ASSERT(op_depth == 0);
SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 1));
SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 2));
*repos_id = svn_sqlite__column_int64(stmt, 1);
*repos_relpath = svn_sqlite__column_text(stmt, 2, result_pool);
return svn_error_trace(svn_sqlite__reset(stmt));
}
static svn_error_t *
moved_descendant_collect(apr_hash_t **map,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
int op_depth,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
*map = NULL;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MOVED_DESCENDANTS_SRC));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
local_relpath,
op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (! have_row)
return svn_error_trace(svn_sqlite__reset(stmt));
while (have_row)
{
const char *src_relpath = svn_sqlite__column_text(stmt, 1, result_pool);
const char *to_relpath = svn_sqlite__column_text(stmt, 4, result_pool);
if (!*map)
*map = apr_hash_make(result_pool);
svn_hash_sets(*map, to_relpath, src_relpath);
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
static svn_error_t *
moved_descendant_commit(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_int64_t repos_id,
const char *repos_relpath,
svn_revnum_t revision,
apr_hash_t *children,
apr_pool_t *scratch_pool)
{
apr_pool_t *iterpool;
svn_sqlite__stmt_t *stmt;
apr_hash_index_t *hi;
SVN_ERR_ASSERT(*local_relpath != '\0'
&& *repos_relpath != '\0');
if (!children)
return SVN_NO_ERROR;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_COMMIT_UPDATE_ORIGIN));
iterpool = svn_pool_create(scratch_pool);
for (hi = apr_hash_first(scratch_pool, children); hi; hi = apr_hash_next(hi))
{
const char *src_relpath = apr_hash_this_val(hi);
const char *to_relpath = apr_hash_this_key(hi);
const char *new_repos_relpath;
int to_op_depth = relpath_depth(to_relpath);
int affected;
apr_hash_t *map;
svn_pool_clear(iterpool);
SVN_ERR_ASSERT(to_op_depth > 0);
new_repos_relpath = svn_relpath_join(
repos_relpath,
svn_relpath_skip_ancestor(local_relpath,
src_relpath),
iterpool);
SVN_ERR(svn_sqlite__bindf(stmt, "isdisr", wcroot->wc_id,
to_relpath,
to_op_depth,
repos_id,
new_repos_relpath,
revision));
SVN_ERR(svn_sqlite__update(&affected, stmt));
#ifdef SVN_DEBUG
SVN_ERR_ASSERT(affected >= 1);
#endif
SVN_ERR(moved_descendant_collect(&map, wcroot, to_relpath, to_op_depth,
iterpool, iterpool));
SVN_ERR(moved_descendant_commit(wcroot, to_relpath,
repos_id, new_repos_relpath, revision,
map, iterpool));
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
static svn_error_t *
descendant_commit(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
int op_depth,
apr_int64_t repos_id,
const char *repos_relpath,
svn_revnum_t revision,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
SVN_ERR_ASSERT(*local_relpath != '\0'
&& *repos_relpath != '\0');
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_COMMIT_DESCENDANTS_TO_BASE));
SVN_ERR(svn_sqlite__bindf(stmt, "isdisr", wcroot->wc_id,
local_relpath,
op_depth,
repos_id,
repos_relpath,
revision));
SVN_ERR(svn_sqlite__update(NULL, stmt));
return SVN_NO_ERROR;
}
static svn_error_t *
commit_node(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_revnum_t new_revision,
svn_revnum_t changed_rev,
apr_time_t changed_date,
const char *changed_author,
const svn_checksum_t *new_checksum,
apr_hash_t *new_dav_cache,
svn_boolean_t keep_changelist,
svn_boolean_t no_unlock,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt_info;
svn_sqlite__stmt_t *stmt_act;
svn_boolean_t have_act;
svn_string_t prop_blob = { 0 };
svn_string_t inherited_prop_blob = { 0 };
const char *changelist = NULL;
const char *parent_relpath;
svn_wc__db_status_t new_presence;
svn_node_kind_t new_kind;
const char *new_depth_str = NULL;
svn_sqlite__stmt_t *stmt;
apr_int64_t repos_id;
const char *repos_relpath;
int op_depth;
svn_wc__db_status_t old_presence;
svn_boolean_t moved_here;
SVN_ERR(determine_commit_repos_info(&repos_id, &repos_relpath,
wcroot, local_relpath,
scratch_pool, scratch_pool));
SVN_ERR(svn_sqlite__get_statement(&stmt_info, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt_info, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_row(stmt_info));
SVN_ERR(svn_sqlite__get_statement(&stmt_act, wcroot->sdb,
STMT_SELECT_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt_act, "is",
wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_act, stmt_act));
op_depth = svn_sqlite__column_int(stmt_info, 0);
old_presence = svn_sqlite__column_token(stmt_info, 3, presence_map);
new_kind = svn_sqlite__column_token(stmt_info, 4, kind_map);
if (new_kind == svn_node_dir)
new_depth_str = svn_sqlite__column_text(stmt_info, 11, scratch_pool);
if (op_depth == 0)
{
SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt_info, 1));
SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt_info, 2));
SVN_ERR_ASSERT(repos_id == svn_sqlite__column_int64(stmt_info, 1));
SVN_ERR_ASSERT(strcmp(repos_relpath,
svn_sqlite__column_text(stmt_info, 2, NULL)) == 0);
}
if (old_presence != svn_wc__db_status_base_deleted)
{
if (have_act)
prop_blob.data = svn_sqlite__column_blob(stmt_act, 1, &prop_blob.len,
scratch_pool);
if (prop_blob.data == NULL)
prop_blob.data = svn_sqlite__column_blob(stmt_info, 14, &prop_blob.len,
scratch_pool);
inherited_prop_blob.data = svn_sqlite__column_blob(
stmt_info, 16,
&inherited_prop_blob.len,
scratch_pool);
if (keep_changelist && have_act)
changelist = svn_sqlite__column_text(stmt_act, 0, scratch_pool);
moved_here = svn_sqlite__column_int(stmt_info, 15);
}
else
{
moved_here = FALSE;
changelist = NULL;
}
SVN_ERR(svn_sqlite__reset(stmt_info));
SVN_ERR(svn_sqlite__reset(stmt_act));
if (op_depth > 0)
{
int affected_rows;
SVN_ERR_ASSERT(op_depth == relpath_depth(local_relpath));
{
apr_hash_t *old_moves;
apr_hash_index_t *hi;
SVN_ERR(moved_descendant_collect(&old_moves, wcroot, local_relpath, 0,
scratch_pool, scratch_pool));
if (old_moves)
for (hi = apr_hash_first(scratch_pool, old_moves);
hi; hi = apr_hash_next(hi))
{
SVN_ERR(clear_moved_here(wcroot, apr_hash_this_key(hi),
scratch_pool));
}
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_NODE_ALL_LAYERS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
if (affected_rows > 1)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_SHADOWED_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt,
"isd",
wcroot->wc_id,
local_relpath,
op_depth));
SVN_ERR(svn_sqlite__step_done(stmt));
}
if (old_presence != svn_wc__db_status_base_deleted)
{
SVN_ERR(descendant_commit(wcroot, local_relpath, op_depth,
repos_id, repos_relpath, new_revision,
scratch_pool));
}
if (old_presence != svn_wc__db_status_base_deleted)
{
apr_hash_t *moves = NULL;
SVN_ERR(moved_descendant_collect(&moves, wcroot, local_relpath, 0,
scratch_pool, scratch_pool));
SVN_ERR(moved_descendant_commit(wcroot, local_relpath,
repos_id, repos_relpath, new_revision,
moves, scratch_pool));
}
if (moved_here)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_CLEAR_MOVED_TO_FROM_DEST));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
}
if (*local_relpath == '\0')
parent_relpath = NULL;
else
parent_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
if (old_presence != svn_wc__db_status_base_deleted)
{
new_presence = (old_presence == svn_wc__db_status_incomplete
? svn_wc__db_status_incomplete
: svn_wc__db_status_normal);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_APPLY_CHANGES_TO_BASE_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "issisrtstrisnbn",
wcroot->wc_id, local_relpath,
parent_relpath,
repos_id,
repos_relpath,
new_revision,
presence_map, new_presence,
new_depth_str,
kind_map, new_kind,
changed_rev,
changed_date,
changed_author,
prop_blob.data, prop_blob.len));
SVN_ERR(svn_sqlite__bind_checksum(stmt, 13, new_checksum,
scratch_pool));
SVN_ERR(svn_sqlite__bind_properties(stmt, 15, new_dav_cache,
scratch_pool));
if (inherited_prop_blob.data != NULL)
{
SVN_ERR(svn_sqlite__bind_blob(stmt, 17, inherited_prop_blob.data,
inherited_prop_blob.len));
}
SVN_ERR(svn_sqlite__step_done(stmt));
}
else
{
struct insert_base_baton_t ibb;
blank_ibb(&ibb);
ibb.repos_id = repos_id;
ibb.status = svn_wc__db_status_not_present;
ibb.kind = new_kind;
ibb.repos_relpath = repos_relpath;
ibb.revision = new_revision;
SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool));
keep_changelist = FALSE;
}
if (have_act)
{
if (keep_changelist && changelist != NULL)
{
SVN_ERR(svn_sqlite__get_statement(
&stmt, wcroot->sdb,
STMT_RESET_ACTUAL_WITH_CHANGELIST));
SVN_ERR(svn_sqlite__bindf(stmt, "isss",
wcroot->wc_id, local_relpath,
svn_relpath_dirname(local_relpath,
scratch_pool),
changelist));
SVN_ERR(svn_sqlite__step_done(stmt));
}
else
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
}
if (!no_unlock)
{
svn_sqlite__stmt_t *lock_stmt;
svn_boolean_t op_root = (op_depth > 0
&& (relpath_depth(local_relpath) == op_depth));
SVN_ERR(svn_sqlite__get_statement(&lock_stmt, wcroot->sdb,
op_root
? STMT_DELETE_LOCK_RECURSIVELY
: STMT_DELETE_LOCK));
SVN_ERR(svn_sqlite__bindf(lock_stmt, "is", repos_id, repos_relpath));
SVN_ERR(svn_sqlite__step_done(lock_stmt));
}
SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_global_commit(svn_wc__db_t *db,
const char *local_abspath,
svn_revnum_t new_revision,
svn_revnum_t changed_revision,
apr_time_t changed_date,
const char *changed_author,
const svn_checksum_t *new_checksum,
apr_hash_t *new_dav_cache,
svn_boolean_t keep_changelist,
svn_boolean_t no_unlock,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
const char *local_relpath;
svn_wc__db_wcroot_t *wcroot;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(new_revision));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
commit_node(wcroot, local_relpath,
new_revision, changed_revision, changed_date, changed_author,
new_checksum, new_dav_cache, keep_changelist,
no_unlock, work_items, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_global_update(svn_wc__db_t *db,
const char *local_abspath,
svn_node_kind_t new_kind,
const char *new_repos_relpath,
svn_revnum_t new_revision,
const apr_hash_t *new_props,
svn_revnum_t new_changed_rev,
apr_time_t new_changed_date,
const char *new_changed_author,
const apr_array_header_t *new_children,
const svn_checksum_t *new_checksum,
const char *new_target,
const apr_hash_t *new_dav_cache,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
NOT_IMPLEMENTED();
#if 0
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(svn_relpath_is_canonical(new_repos_relpath));
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(new_revision));
SVN_ERR_ASSERT(new_props != NULL);
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(new_changed_rev));
SVN_ERR_ASSERT((new_children != NULL
&& new_checksum == NULL
&& new_target == NULL)
|| (new_children == NULL
&& new_checksum != NULL
&& new_target == NULL)
|| (new_children == NULL
&& new_checksum == NULL
&& new_target != NULL));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
update_node(wcroot, local_relpath,
new_repos_relpath, new_revision, new_props,
new_changed_rev, new_changed_date, new_changed_author,
new_children, new_checksum, new_target,
conflict, work_items, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, scratch_pool));
return SVN_NO_ERROR;
#endif
}
static svn_error_t *
db_op_set_rev_repos_relpath_iprops(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_array_header_t *iprops,
svn_revnum_t rev,
svn_boolean_t set_repos_relpath,
const char *repos_relpath,
apr_int64_t repos_id,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
SVN_ERR(flush_entries(wcroot,
svn_dirent_join(wcroot->abspath, local_relpath,
scratch_pool),
svn_depth_empty, scratch_pool));
if (SVN_IS_VALID_REVNUM(rev))
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_BASE_REVISION));
SVN_ERR(svn_sqlite__bindf(stmt, "isr", wcroot->wc_id, local_relpath,
rev));
SVN_ERR(svn_sqlite__step_done(stmt));
}
if (set_repos_relpath)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_BASE_REPOS));
SVN_ERR(svn_sqlite__bindf(stmt, "isis", wcroot->wc_id, local_relpath,
repos_id, repos_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_IPROP));
SVN_ERR(svn_sqlite__bindf(stmt, "is",
wcroot->wc_id,
local_relpath));
SVN_ERR(svn_sqlite__bind_iprops(stmt, 3, iprops, scratch_pool));
SVN_ERR(svn_sqlite__step_done(stmt));
return SVN_NO_ERROR;
}
static svn_error_t *
bump_node_revision(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_wc__db_status_t node_status,
svn_node_kind_t node_kind,
svn_revnum_t node_revision,
const char *node_repos_relpath,
apr_int64_t new_repos_id,
const char *new_repos_relpath,
svn_revnum_t new_rev,
svn_depth_t depth,
apr_hash_t *exclude_relpaths,
apr_hash_t *wcroot_iprops,
svn_boolean_t is_root,
svn_boolean_t skip_when_dir,
svn_wc__db_t *db,
apr_pool_t *scratch_pool)
{
apr_pool_t *iterpool;
apr_hash_t *children;
apr_hash_index_t *hi;
svn_boolean_t set_repos_relpath = FALSE;
svn_depth_t depth_below_here = depth;
apr_array_header_t *iprops = NULL;
if (new_repos_relpath != NULL
&& strcmp(node_repos_relpath, new_repos_relpath))
set_repos_relpath = TRUE;
if (wcroot_iprops)
iprops = svn_hash_gets(wcroot_iprops,
svn_dirent_join(wcroot->abspath, local_relpath,
scratch_pool));
if (iprops
|| set_repos_relpath
|| (SVN_IS_VALID_REVNUM(new_rev) && new_rev != node_revision))
{
SVN_ERR(db_op_set_rev_repos_relpath_iprops(wcroot, local_relpath,
iprops, new_rev,
set_repos_relpath,
new_repos_relpath,
new_repos_id,
scratch_pool));
}
if (depth <= svn_depth_empty
|| node_kind != svn_node_dir
|| node_status == svn_wc__db_status_server_excluded
|| node_status == svn_wc__db_status_excluded
|| node_status == svn_wc__db_status_not_present)
return SVN_NO_ERROR;
depth_below_here = depth;
if (depth == svn_depth_immediates || depth == svn_depth_files)
depth_below_here = svn_depth_empty;
iterpool = svn_pool_create(scratch_pool);
SVN_ERR(base_get_children_info(&children, wcroot, local_relpath, 0,
scratch_pool, iterpool));
for (hi = apr_hash_first(scratch_pool, children); hi; hi = apr_hash_next(hi))
{
const char *child_basename = apr_hash_this_key(hi);
const struct svn_wc__db_base_info_t *child_info;
const char *child_local_relpath;
const char *child_repos_relpath = NULL;
svn_pool_clear(iterpool);
child_info = apr_hash_this_val(hi);
if (child_info->update_root && child_info->kind == svn_node_file)
continue;
if (depth < svn_depth_immediates && child_info->kind == svn_node_dir)
continue;
child_local_relpath = svn_relpath_join(local_relpath, child_basename,
iterpool);
if (svn_hash_gets(exclude_relpaths, child_local_relpath))
continue;
if (child_info->status == svn_wc__db_status_not_present
|| (child_info->status == svn_wc__db_status_server_excluded &&
child_info->revnum != new_rev))
{
svn_sqlite__stmt_t *stmt;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_BASE_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, child_local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
continue;
}
if (new_repos_relpath)
child_repos_relpath = svn_relpath_join(new_repos_relpath,
child_basename, iterpool);
SVN_ERR(bump_node_revision(wcroot, child_local_relpath,
child_info->status,
child_info->kind,
child_info->revnum,
child_info->repos_relpath,
new_repos_id,
child_repos_relpath, new_rev,
depth_below_here,
exclude_relpaths, wcroot_iprops,
FALSE ,
(depth < svn_depth_immediates), db,
iterpool));
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
static svn_error_t *
bump_revisions_post_update(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_wc__db_t *db,
svn_depth_t depth,
const char *new_repos_relpath,
const char *new_repos_root_url,
const char *new_repos_uuid,
svn_revnum_t new_revision,
apr_hash_t *exclude_relpaths,
apr_hash_t *wcroot_iprops,
svn_boolean_t empty_update,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
svn_wc__db_status_t status;
svn_node_kind_t kind;
svn_error_t *err;
apr_int64_t new_repos_id = INVALID_REPOS_ID;
svn_revnum_t revision;
const char *repos_relpath;
err = svn_wc__db_base_get_info_internal(&status, &kind, &revision,
&repos_relpath, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
wcroot, local_relpath,
scratch_pool, scratch_pool);
if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
{
svn_error_clear(err);
return SVN_NO_ERROR;
}
else
SVN_ERR(err);
switch (status)
{
case svn_wc__db_status_excluded:
case svn_wc__db_status_server_excluded:
case svn_wc__db_status_not_present:
return SVN_NO_ERROR;
default:
break;
}
if (new_repos_root_url != NULL)
SVN_ERR(create_repos_id(&new_repos_id, new_repos_root_url,
new_repos_uuid,
wcroot->sdb, scratch_pool));
SVN_ERR(bump_node_revision(wcroot, local_relpath,
status, kind, revision, repos_relpath,
new_repos_id,
new_repos_relpath, new_revision,
depth, exclude_relpaths,
wcroot_iprops,
TRUE , FALSE, db,
scratch_pool));
SVN_ERR(svn_wc__db_bump_moved_away(wcroot, local_relpath, depth, db,
scratch_pool));
SVN_ERR(svn_wc__db_update_move_list_notify(wcroot, SVN_INVALID_REVNUM,
SVN_INVALID_REVNUM, notify_func,
notify_baton, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_bump_revisions_post_update(svn_wc__db_t *db,
const char *local_abspath,
svn_depth_t depth,
const char *new_repos_relpath,
const char *new_repos_root_url,
const char *new_repos_uuid,
svn_revnum_t new_revision,
apr_hash_t *exclude_relpaths,
apr_hash_t *wcroot_iprops,
svn_boolean_t empty_update,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
const char *local_relpath;
svn_wc__db_wcroot_t *wcroot;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
if (svn_hash_gets(exclude_relpaths, local_relpath))
return SVN_NO_ERROR;
if (depth == svn_depth_unknown)
depth = svn_depth_infinity;
SVN_WC__DB_WITH_TXN(
bump_revisions_post_update(wcroot, local_relpath, db,
depth, new_repos_relpath, new_repos_root_url,
new_repos_uuid, new_revision,
exclude_relpaths, wcroot_iprops, empty_update,
notify_func, notify_baton, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
static svn_error_t *
lock_add_txn(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
const svn_wc__db_lock_t *lock,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
const char *repos_relpath;
apr_int64_t repos_id;
SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
&repos_relpath, &repos_id,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
wcroot, local_relpath,
scratch_pool, scratch_pool));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_LOCK));
SVN_ERR(svn_sqlite__bindf(stmt, "iss",
repos_id, repos_relpath, lock->token));
if (lock->owner != NULL)
SVN_ERR(svn_sqlite__bind_text(stmt, 4, lock->owner));
if (lock->comment != NULL)
SVN_ERR(svn_sqlite__bind_text(stmt, 5, lock->comment));
if (lock->date != 0)
SVN_ERR(svn_sqlite__bind_int64(stmt, 6, lock->date));
SVN_ERR(svn_sqlite__insert(NULL, stmt));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_lock_add(svn_wc__db_t *db,
const char *local_abspath,
const svn_wc__db_lock_t *lock,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(lock != NULL);
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
lock_add_txn(wcroot, local_relpath, lock, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
lock_remove_txn(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
const char *repos_relpath;
apr_int64_t repos_id;
svn_sqlite__stmt_t *stmt;
SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
&repos_relpath, &repos_id,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
wcroot, local_relpath,
scratch_pool, scratch_pool));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_LOCK));
SVN_ERR(svn_sqlite__bindf(stmt, "is", repos_id, repos_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_lock_remove(svn_wc__db_t *db,
const char *local_abspath,
svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
lock_remove_txn(wcroot, local_relpath, work_items, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
get_moved_from_info(const char **moved_from_relpath,
const char **moved_from_op_root_relpath,
const char *moved_to_op_root_relpath,
int *op_depth,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MOVED_FROM_RELPATH));
SVN_ERR(svn_sqlite__bindf(stmt, "is",
wcroot->wc_id, moved_to_op_root_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
{
if (moved_from_relpath)
*moved_from_relpath = NULL;
if (moved_from_op_root_relpath)
*moved_from_op_root_relpath = NULL;
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
if (op_depth)
*op_depth = svn_sqlite__column_int(stmt, 1);
if (moved_from_relpath || moved_from_op_root_relpath)
{
const char *db_delete_op_root_relpath;
db_delete_op_root_relpath = svn_sqlite__column_text(stmt, 0,
result_pool);
if (moved_from_op_root_relpath)
*moved_from_op_root_relpath = db_delete_op_root_relpath;
if (moved_from_relpath)
{
if (strcmp(moved_to_op_root_relpath, local_relpath) == 0)
{
*moved_from_relpath = db_delete_op_root_relpath;
}
else
{
const char *child_relpath;
child_relpath = svn_relpath_skip_ancestor(
moved_to_op_root_relpath, local_relpath);
SVN_ERR_ASSERT(child_relpath && strlen(child_relpath) > 0);
*moved_from_relpath = svn_relpath_join(db_delete_op_root_relpath,
child_relpath,
result_pool);
}
}
}
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
static svn_error_t *
scan_addition(svn_wc__db_status_t *status,
const char **op_root_relpath_p,
const char **repos_relpath,
apr_int64_t *repos_id,
const char **original_repos_relpath,
apr_int64_t *original_repos_id,
svn_revnum_t *original_revision,
const char **moved_from_relpath,
const char **moved_from_op_root_relpath,
int *moved_from_op_depth,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *op_root_relpath;
const char *build_relpath = "";
if (op_root_relpath_p)
*op_root_relpath_p = NULL;
if (original_repos_relpath)
*original_repos_relpath = NULL;
if (original_repos_id)
*original_repos_id = INVALID_REPOS_ID;
if (original_revision)
*original_revision = SVN_INVALID_REVNUM;
if (moved_from_relpath)
*moved_from_relpath = NULL;
if (moved_from_op_root_relpath)
*moved_from_op_root_relpath = NULL;
if (moved_from_op_depth)
*moved_from_op_depth = 0;
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
svn_wc__db_status_t presence;
int op_depth;
const char *repos_prefix_path;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_WORKING_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
{
SVN_ERR(svn_sqlite__reset(stmt));
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
presence = svn_sqlite__column_token(stmt, 1, presence_map);
op_depth = svn_sqlite__column_int(stmt, 0);
if (op_depth == 0 || (presence != svn_wc__db_status_normal
&& presence != svn_wc__db_status_incomplete))
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS,
svn_sqlite__reset(stmt),
_("Expected node '%s' to be added."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
if (original_revision)
*original_revision = svn_sqlite__column_revnum(stmt, 12);
if (status)
{
if (presence == svn_wc__db_status_normal)
*status = svn_wc__db_status_added;
else
*status = svn_wc__db_status_incomplete;
}
op_root_relpath = svn_relpath_prefix(local_relpath, op_depth,
scratch_pool);
repos_prefix_path = svn_relpath_skip_ancestor(op_root_relpath,
local_relpath);
if (op_root_relpath_p)
*op_root_relpath_p = apr_pstrdup(result_pool, op_root_relpath);
if (original_repos_relpath
|| original_repos_id
|| (original_revision
&& *original_revision == SVN_INVALID_REVNUM)
|| status
|| moved_from_relpath || moved_from_op_root_relpath)
{
if (local_relpath != op_root_relpath)
{
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__bindf(stmt, "is",
wcroot->wc_id, op_root_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
{
SVN_ERR(svn_sqlite__reset(stmt));
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot,
op_root_relpath,
scratch_pool));
}
if (original_revision
&& *original_revision == SVN_INVALID_REVNUM)
*original_revision = svn_sqlite__column_revnum(stmt, 12);
}
if (original_repos_relpath)
*original_repos_relpath = svn_sqlite__column_text(stmt, 11,
result_pool);
if (!svn_sqlite__column_is_null(stmt, 10)
&& (status
|| original_repos_id
|| moved_from_relpath || moved_from_op_root_relpath))
{
svn_boolean_t moved_here;
if (original_repos_id)
*original_repos_id = svn_sqlite__column_int64(stmt, 10);
moved_here = svn_sqlite__column_boolean(stmt, 13 );
if (status)
*status = moved_here ? svn_wc__db_status_moved_here
: svn_wc__db_status_copied;
if (moved_here
&& (moved_from_relpath || moved_from_op_root_relpath))
{
svn_error_t *err;
err = get_moved_from_info(moved_from_relpath,
moved_from_op_root_relpath,
op_root_relpath,
moved_from_op_depth,
wcroot, local_relpath,
result_pool,
scratch_pool);
if (err)
return svn_error_compose_create(
err, svn_sqlite__reset(stmt));
}
}
}
if (repos_relpath || repos_id)
{
const char *base_relpath;
while (TRUE)
{
const char *tmp;
SVN_ERR(svn_sqlite__reset(stmt));
repos_prefix_path =
svn_relpath_join(svn_relpath_basename(op_root_relpath, NULL),
repos_prefix_path,
scratch_pool);
op_root_relpath = svn_relpath_dirname(op_root_relpath, scratch_pool);
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, op_root_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (! have_row)
break;
op_depth = svn_sqlite__column_int(stmt, 0);
tmp = op_root_relpath;
op_root_relpath = svn_relpath_prefix(op_root_relpath, op_depth,
scratch_pool);
repos_prefix_path = svn_relpath_join(
svn_relpath_skip_ancestor(op_root_relpath, tmp),
repos_prefix_path, scratch_pool);
}
SVN_ERR(svn_sqlite__reset(stmt));
build_relpath = repos_prefix_path;
SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
&base_relpath, repos_id,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
wcroot, op_root_relpath,
scratch_pool, scratch_pool));
if (repos_relpath)
*repos_relpath = svn_relpath_join(base_relpath, build_relpath,
result_pool);
}
else
SVN_ERR(svn_sqlite__reset(stmt));
}
#ifdef SVN_DEBUG
if (status)
{
SVN_ERR_ASSERT(*status == svn_wc__db_status_added
|| *status == svn_wc__db_status_copied
|| *status == svn_wc__db_status_incomplete
|| *status == svn_wc__db_status_moved_here);
if (*status == svn_wc__db_status_added)
{
SVN_ERR_ASSERT(!original_repos_relpath
|| *original_repos_relpath == NULL);
SVN_ERR_ASSERT(!original_revision
|| *original_revision == SVN_INVALID_REVNUM);
SVN_ERR_ASSERT(!original_repos_id
|| *original_repos_id == INVALID_REPOS_ID);
}
else if (*status != svn_wc__db_status_incomplete)
{
SVN_ERR_ASSERT(!original_repos_relpath
|| *original_repos_relpath != NULL);
SVN_ERR_ASSERT(!original_revision
|| *original_revision != SVN_INVALID_REVNUM);
SVN_ERR_ASSERT(!original_repos_id
|| *original_repos_id != INVALID_REPOS_ID);
}
}
SVN_ERR_ASSERT(!op_root_relpath_p || *op_root_relpath_p != NULL);
#endif
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_scan_addition_internal(
svn_wc__db_status_t *status,
const char **op_root_relpath_p,
const char **repos_relpath,
apr_int64_t *repos_id,
const char **original_repos_relpath,
apr_int64_t *original_repos_id,
svn_revnum_t *original_revision,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
return svn_error_trace(
scan_addition(status, op_root_relpath_p, repos_relpath, repos_id,
original_repos_relpath, original_repos_id,
original_revision, NULL, NULL, NULL,
wcroot, local_relpath, result_pool, scratch_pool));
}
svn_error_t *
svn_wc__db_scan_addition(svn_wc__db_status_t *status,
const char **op_root_abspath,
const char **repos_relpath,
const char **repos_root_url,
const char **repos_uuid,
const char **original_repos_relpath,
const char **original_root_url,
const char **original_uuid,
svn_revnum_t *original_revision,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
const char *op_root_relpath = NULL;
apr_int64_t repos_id = INVALID_REPOS_ID;
apr_int64_t original_repos_id = INVALID_REPOS_ID;
apr_int64_t *repos_id_p
= (repos_root_url || repos_uuid) ? &repos_id : NULL;
apr_int64_t *original_repos_id_p
= (original_root_url || original_uuid) ? &original_repos_id : NULL;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN4(
scan_addition(status,
op_root_abspath
? &op_root_relpath
: NULL,
repos_relpath, repos_id_p,
original_repos_relpath, original_repos_id_p,
original_revision,
NULL, NULL, NULL,
wcroot, local_relpath, result_pool, scratch_pool),
svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid, wcroot,
repos_id, result_pool),
svn_wc__db_fetch_repos_info(original_root_url, original_uuid,
wcroot, original_repos_id,
result_pool),
SVN_NO_ERROR,
wcroot);
if (op_root_abspath)
*op_root_abspath = svn_dirent_join(wcroot->abspath, op_root_relpath,
result_pool);
SVN_ERR_ASSERT(repos_id_p == NULL || repos_id != INVALID_REPOS_ID);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_scan_moved(const char **moved_from_abspath,
const char **op_root_abspath,
const char **op_root_moved_from_abspath,
const char **moved_from_delete_abspath,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_wc__db_status_t status;
const char *op_root_relpath = NULL;
const char *moved_from_relpath = NULL;
const char *moved_from_op_root_relpath = NULL;
int moved_from_op_depth = -1;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
scan_addition(&status,
op_root_abspath
? &op_root_relpath
: NULL,
NULL, NULL,
NULL, NULL, NULL,
moved_from_abspath
? &moved_from_relpath
: NULL,
(op_root_moved_from_abspath
|| moved_from_delete_abspath)
? &moved_from_op_root_relpath
: NULL,
moved_from_delete_abspath
? &moved_from_op_depth
: NULL,
wcroot, local_relpath, scratch_pool, scratch_pool),
wcroot);
if (status != svn_wc__db_status_moved_here || !moved_from_relpath)
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
_("Path '%s' was not moved here"),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
if (op_root_abspath)
*op_root_abspath = svn_dirent_join(wcroot->abspath, op_root_relpath,
result_pool);
if (moved_from_abspath)
*moved_from_abspath = svn_dirent_join(wcroot->abspath, moved_from_relpath,
result_pool);
if (op_root_moved_from_abspath)
*op_root_moved_from_abspath = svn_dirent_join(wcroot->abspath,
moved_from_op_root_relpath,
result_pool);
if (moved_from_delete_abspath)
{
const char *tmp = svn_relpath_prefix(moved_from_op_root_relpath,
moved_from_op_depth, scratch_pool);
*moved_from_delete_abspath = svn_dirent_join(wcroot->abspath, tmp,
scratch_pool);
}
return SVN_NO_ERROR;
}
static svn_error_t *
follow_moved_to(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
int op_depth,
apr_array_header_t **moved_tos,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
int shadowing_op_depth;
const char *ancestor_relpath;
const char *node_moved_to = NULL;
int i;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_OP_DEPTH_MOVED_TO));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
shadowing_op_depth = svn_sqlite__column_int(stmt, 0);
node_moved_to = svn_sqlite__column_text(stmt, 1, result_pool);
if (node_moved_to)
{
struct svn_wc__db_moved_to_t *moved_to;
moved_to = apr_palloc(result_pool, sizeof(*moved_to));
moved_to->op_depth = shadowing_op_depth;
moved_to->local_relpath = node_moved_to;
APR_ARRAY_PUSH(*moved_tos, struct svn_wc__db_moved_to_t *) = moved_to;
}
}
SVN_ERR(svn_sqlite__reset(stmt));
if (!have_row)
{
return SVN_NO_ERROR;
}
else if (node_moved_to)
{
return SVN_NO_ERROR;
}
ancestor_relpath = local_relpath;
for (i = relpath_depth(local_relpath); i > shadowing_op_depth; --i)
{
const char *ancestor_moved_to;
ancestor_relpath = svn_relpath_dirname(ancestor_relpath, scratch_pool);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MOVED_TO));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, ancestor_relpath,
shadowing_op_depth));
SVN_ERR(svn_sqlite__step_row(stmt));
ancestor_moved_to = svn_sqlite__column_text(stmt, 0, scratch_pool);
SVN_ERR(svn_sqlite__reset(stmt));
if (ancestor_moved_to)
{
struct svn_wc__db_moved_to_t *moved_to;
node_moved_to
= svn_relpath_join(ancestor_moved_to,
svn_relpath_skip_ancestor(ancestor_relpath,
local_relpath),
result_pool);
moved_to = apr_palloc(result_pool, sizeof(*moved_to));
moved_to->op_depth = shadowing_op_depth;
moved_to->local_relpath = node_moved_to;
APR_ARRAY_PUSH(*moved_tos, struct svn_wc__db_moved_to_t *) = moved_to;
SVN_ERR(follow_moved_to(wcroot, node_moved_to,
relpath_depth(ancestor_moved_to),
moved_tos, result_pool, scratch_pool));
break;
}
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_follow_moved_to(apr_array_header_t **moved_tos,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
*moved_tos = apr_array_make(result_pool, 0,
sizeof(struct svn_wc__db_moved_to_t *));
SVN_WC__DB_WITH_TXN(follow_moved_to(wcroot, local_relpath, 0, moved_tos,
result_pool, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_scan_moved_to_internal(const char **move_src_relpath,
const char **move_dst_relpath,
const char **delete_relpath,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
int op_depth,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
int delete_op_depth;
const char *relpath = local_relpath;
const char *dst_relpath;
SVN_ERR_ASSERT(local_relpath[0]);
if (move_src_relpath)
*move_src_relpath = NULL;
if (move_dst_relpath)
*move_dst_relpath = NULL;
if (delete_relpath)
*delete_relpath = NULL;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_OP_DEPTH_MOVED_TO));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, relpath, op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
{
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
svn_sqlite__reset(stmt),
_("Node '%s' is not shadowed"),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
}
delete_op_depth = svn_sqlite__column_int(stmt, 0);
dst_relpath = svn_sqlite__column_text(stmt, 1, scratch_pool);
SVN_ERR(svn_sqlite__reset(stmt));
while (!dst_relpath && have_row)
{
relpath = svn_relpath_dirname(relpath, scratch_pool);
if (relpath_depth(relpath) < delete_op_depth)
break;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_DEPTH_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, relpath,
delete_op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
dst_relpath = svn_sqlite__column_text(stmt, 13, scratch_pool);
SVN_ERR(svn_sqlite__reset(stmt));
}
if (dst_relpath)
{
if (move_src_relpath)
*move_src_relpath = apr_pstrdup(result_pool, relpath);
if (move_dst_relpath)
*move_dst_relpath = apr_pstrdup(result_pool, dst_relpath);
if (delete_relpath)
*delete_relpath = svn_relpath_prefix(local_relpath, delete_op_depth,
result_pool);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_base_moved_to(const char **move_dst_abspath,
const char **move_dst_op_root_abspath,
const char **move_src_root_abspath,
const char **delete_abspath,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
const char *dst_root_relpath;
const char *src_root_relpath, *delete_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(svn_wc__db_scan_moved_to_internal(&src_root_relpath,
&dst_root_relpath,
&delete_relpath,
wcroot, local_relpath,
0 ,
scratch_pool,
scratch_pool),
wcroot);
if (move_dst_abspath)
*move_dst_abspath =
dst_root_relpath
? svn_dirent_join(wcroot->abspath,
svn_dirent_join(
dst_root_relpath,
svn_relpath_skip_ancestor(src_root_relpath,
local_relpath),
scratch_pool),
result_pool)
: NULL;
if (move_dst_op_root_abspath)
*move_dst_op_root_abspath =
dst_root_relpath
? svn_dirent_join(wcroot->abspath, dst_root_relpath, result_pool)
: NULL;
if (move_src_root_abspath)
*move_src_root_abspath =
src_root_relpath
? svn_dirent_join(wcroot->abspath, src_root_relpath, result_pool)
: NULL;
if (delete_abspath)
*delete_abspath =
delete_relpath
? svn_dirent_join(wcroot->abspath, delete_relpath, result_pool)
: NULL;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_upgrade_begin(svn_sqlite__db_t **sdb,
apr_int64_t *repos_id,
apr_int64_t *wc_id,
svn_wc__db_t *wc_db,
const char *dir_abspath,
const char *repos_root_url,
const char *repos_uuid,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
SVN_ERR(create_db(sdb, repos_id, wc_id, dir_abspath,
repos_root_url, repos_uuid,
SDB_FILE,
NULL, SVN_INVALID_REVNUM, svn_depth_unknown,
TRUE ,
0 ,
wc_db->state_pool, scratch_pool));
SVN_ERR(svn_wc__db_pdh_create_wcroot(&wcroot,
apr_pstrdup(wc_db->state_pool,
dir_abspath),
*sdb, *wc_id, FORMAT_FROM_SDB,
FALSE ,
wc_db->state_pool, scratch_pool));
svn_hash_sets(wc_db->dir_data, wcroot->abspath, wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_upgrade_insert_external(svn_wc__db_t *db,
const char *local_abspath,
svn_node_kind_t kind,
const char *parent_abspath,
const char *def_local_abspath,
const char *repos_relpath,
const char *repos_root_url,
const char *repos_uuid,
svn_revnum_t def_peg_revision,
svn_revnum_t def_revision,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *def_local_relpath;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_int64_t repos_id;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &def_local_relpath,
db, def_local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_REPOSITORY));
SVN_ERR(svn_sqlite__bindf(stmt, "s", repos_root_url));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
repos_id = svn_sqlite__column_int64(stmt, 0);
SVN_ERR(svn_sqlite__reset(stmt));
if (!have_row)
{
SVN_ERR(create_repos_id(&repos_id, repos_root_url, repos_uuid,
wcroot->sdb, scratch_pool));
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_INSERT_EXTERNAL));
SVN_ERR(svn_sqlite__bindf(stmt, "issstsis",
wcroot->wc_id,
svn_dirent_skip_ancestor(wcroot->abspath,
local_abspath),
svn_dirent_skip_ancestor(wcroot->abspath,
parent_abspath),
"normal",
kind_map, kind,
def_local_relpath,
repos_id,
repos_relpath));
if (SVN_IS_VALID_REVNUM(def_peg_revision))
SVN_ERR(svn_sqlite__bind_revnum(stmt, 9, def_peg_revision));
if (SVN_IS_VALID_REVNUM(def_revision))
SVN_ERR(svn_sqlite__bind_revnum(stmt, 10, def_revision));
SVN_ERR(svn_sqlite__insert(NULL, stmt));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_wq_add_internal(svn_wc__db_wcroot_t *wcroot,
const svn_skel_t *work_item,
apr_pool_t *scratch_pool)
{
return svn_error_trace(add_work_items(wcroot->sdb, work_item,
scratch_pool));
}
svn_error_t *
svn_wc__db_wq_add(svn_wc__db_t *db,
const char *wri_abspath,
const svn_skel_t *work_item,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
if (work_item == NULL)
return SVN_NO_ERROR;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
return svn_error_trace(add_work_items(wcroot->sdb, work_item,
scratch_pool));
}
static svn_error_t *
wq_fetch_next(apr_uint64_t *id,
svn_skel_t **work_item,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_uint64_t completed_id,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
if (completed_id != 0)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_WORK_ITEM));
SVN_ERR(svn_sqlite__bind_int64(stmt, 1, completed_id));
SVN_ERR(svn_sqlite__step_done(stmt));
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_WORK_ITEM));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
{
*id = 0;
*work_item = NULL;
}
else
{
apr_size_t len;
const void *val;
*id = svn_sqlite__column_int64(stmt, 0);
val = svn_sqlite__column_blob(stmt, 1, &len, result_pool);
*work_item = svn_skel__parse(val, len, result_pool);
}
return svn_error_trace(svn_sqlite__reset(stmt));
}
svn_error_t *
svn_wc__db_wq_fetch_next(apr_uint64_t *id,
svn_skel_t **work_item,
svn_wc__db_t *db,
const char *wri_abspath,
apr_uint64_t completed_id,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(id != NULL);
SVN_ERR_ASSERT(work_item != NULL);
SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
wq_fetch_next(id, work_item,
wcroot, local_relpath, completed_id,
result_pool, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
static svn_error_t *
wq_record(svn_wc__db_wcroot_t *wcroot,
apr_hash_t *record_map,
apr_pool_t *scratch_pool)
{
apr_hash_index_t *hi;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
for (hi = apr_hash_first(scratch_pool, record_map); hi;
hi = apr_hash_next(hi))
{
const char *local_abspath = apr_hash_this_key(hi);
const svn_io_dirent2_t *dirent = apr_hash_this_val(hi);
const char *local_relpath = svn_dirent_skip_ancestor(wcroot->abspath,
local_abspath);
svn_pool_clear(iterpool);
if (! local_relpath)
continue;
SVN_ERR(db_record_fileinfo(wcroot, local_relpath,
dirent->filesize, dirent->mtime,
iterpool));
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_wq_record_and_fetch_next(apr_uint64_t *id,
svn_skel_t **work_item,
svn_wc__db_t *db,
const char *wri_abspath,
apr_uint64_t completed_id,
apr_hash_t *record_map,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(id != NULL);
SVN_ERR_ASSERT(work_item != NULL);
SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
svn_error_compose_create(
wq_fetch_next(id, work_item,
wcroot, local_relpath, completed_id,
result_pool, scratch_pool),
wq_record(wcroot, record_map, scratch_pool)),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_temp_get_format(int *format,
svn_wc__db_t *db,
const char *local_dir_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_error_t *err;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_dir_abspath));
err = svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_dir_abspath, scratch_pool, scratch_pool);
if (err)
{
if (err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
return svn_error_trace(err);
svn_error_clear(err);
*format = 0;
return svn_error_createf(SVN_ERR_WC_MISSING, NULL,
_("'%s' is not a working copy"),
svn_dirent_local_style(local_dir_abspath,
scratch_pool));
}
SVN_ERR_ASSERT(wcroot != NULL);
SVN_ERR_ASSERT(wcroot->format >= 1);
*format = wcroot->format;
return SVN_NO_ERROR;
}
svn_wc_adm_access_t *
svn_wc__db_temp_get_access(svn_wc__db_t *db,
const char *local_dir_abspath,
apr_pool_t *scratch_pool)
{
const char *local_relpath;
svn_wc__db_wcroot_t *wcroot;
svn_error_t *err;
SVN_ERR_ASSERT_NO_RETURN(svn_dirent_is_absolute(local_dir_abspath));
err = svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_dir_abspath, scratch_pool, scratch_pool);
if (err)
{
svn_error_clear(err);
return NULL;
}
if (!wcroot)
return NULL;
return svn_hash_gets(wcroot->access_cache, local_dir_abspath);
}
void
svn_wc__db_temp_set_access(svn_wc__db_t *db,
const char *local_dir_abspath,
svn_wc_adm_access_t *adm_access,
apr_pool_t *scratch_pool)
{
const char *local_relpath;
svn_wc__db_wcroot_t *wcroot;
svn_error_t *err;
SVN_ERR_ASSERT_NO_RETURN(svn_dirent_is_absolute(local_dir_abspath));
err = svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_dir_abspath, scratch_pool, scratch_pool);
if (err)
{
svn_error_clear(err);
return;
}
SVN_ERR_ASSERT_NO_RETURN(
svn_hash_gets(wcroot->access_cache, local_dir_abspath) == NULL
);
svn_hash_sets(wcroot->access_cache, local_dir_abspath, adm_access);
}
svn_error_t *
svn_wc__db_temp_close_access(svn_wc__db_t *db,
const char *local_dir_abspath,
svn_wc_adm_access_t *adm_access,
apr_pool_t *scratch_pool)
{
const char *local_relpath;
svn_wc__db_wcroot_t *wcroot;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_dir_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_dir_abspath, scratch_pool, scratch_pool));
svn_hash_sets(wcroot->access_cache, local_dir_abspath, NULL);
return SVN_NO_ERROR;
}
void
svn_wc__db_temp_clear_access(svn_wc__db_t *db,
const char *local_dir_abspath,
apr_pool_t *scratch_pool)
{
const char *local_relpath;
svn_wc__db_wcroot_t *wcroot;
svn_error_t *err;
SVN_ERR_ASSERT_NO_RETURN(svn_dirent_is_absolute(local_dir_abspath));
err = svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_dir_abspath, scratch_pool, scratch_pool);
if (err)
{
svn_error_clear(err);
return;
}
svn_hash_sets(wcroot->access_cache, local_dir_abspath, NULL);
}
apr_hash_t *
svn_wc__db_temp_get_all_access(svn_wc__db_t *db,
apr_pool_t *result_pool)
{
apr_hash_t *result = apr_hash_make(result_pool);
apr_hash_index_t *hi;
for (hi = apr_hash_first(result_pool, db->dir_data);
hi;
hi = apr_hash_next(hi))
{
const svn_wc__db_wcroot_t *wcroot = apr_hash_this_val(hi);
result = apr_hash_overlay(result_pool, result, wcroot->access_cache);
}
return result;
}
svn_error_t *
svn_wc__db_temp_borrow_sdb(svn_sqlite__db_t **sdb,
svn_wc__db_t *db,
const char *local_dir_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_dir_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_dir_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
*sdb = wcroot->sdb;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_conflict_victims(const apr_array_header_t **victims,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_array_header_t *new_victims;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_CONFLICT_VICTIMS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
new_victims = apr_array_make(result_pool, 0, sizeof(const char *));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
APR_ARRAY_PUSH(new_victims, const char *) =
svn_relpath_basename(child_relpath, result_pool);
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
*victims = new_victims;
return SVN_NO_ERROR;
}
static svn_error_t *
get_conflict_marker_files(apr_hash_t **marker_files_p,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_wc__db_t *db,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_hash_t *marker_files = apr_hash_make(result_pool);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row && !svn_sqlite__column_is_null(stmt, 2))
{
apr_size_t len;
const void *data = svn_sqlite__column_blob(stmt, 2, &len, NULL);
svn_skel_t *conflicts;
const apr_array_header_t *markers;
int i;
conflicts = svn_skel__parse(data, len, scratch_pool);
SVN_ERR(svn_wc__conflict_read_markers(&markers, db, wcroot->abspath,
conflicts,
result_pool, scratch_pool));
for (i = 0; markers && (i < markers->nelts); i++)
{
const char *marker_abspath = APR_ARRAY_IDX(markers, i, const char*);
svn_hash_sets(marker_files, marker_abspath, "");
}
}
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_CONFLICT_VICTIMS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
apr_size_t len;
const void *data = svn_sqlite__column_blob(stmt, 1, &len, NULL);
const apr_array_header_t *markers;
int i;
if (data)
{
svn_skel_t *conflicts;
conflicts = svn_skel__parse(data, len, scratch_pool);
SVN_ERR(svn_wc__conflict_read_markers(&markers, db, wcroot->abspath,
conflicts,
result_pool, scratch_pool));
for (i = 0; markers && (i < markers->nelts); i++)
{
const char *marker_abspath = APR_ARRAY_IDX(markers, i, const char*);
svn_hash_sets(marker_files, marker_abspath, "");
}
}
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
if (apr_hash_count(marker_files))
*marker_files_p = marker_files;
else
*marker_files_p = NULL;
return svn_error_trace(svn_sqlite__reset(stmt));
}
svn_error_t *
svn_wc__db_get_conflict_marker_files(apr_hash_t **marker_files,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
get_conflict_marker_files(marker_files, wcroot, local_relpath, db,
result_pool, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_conflict(svn_skel_t **conflict,
svn_node_kind_t *kind,
apr_hash_t **props,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
return svn_error_trace(svn_wc__db_read_conflict_internal(conflict, kind, props,
wcroot, local_relpath,
result_pool,
scratch_pool));
}
svn_error_t *
svn_wc__db_read_conflict_internal(svn_skel_t **conflict,
svn_node_kind_t *kind,
apr_hash_t **props,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
if (kind)
*kind = svn_node_none;
if (props)
*props = NULL;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
apr_size_t cfl_len;
const void *cfl_data;
cfl_data = svn_sqlite__column_blob(stmt, 2, &cfl_len, result_pool);
if (cfl_data)
*conflict = svn_skel__parse(cfl_data, cfl_len, result_pool);
else
*conflict = NULL;
if (props)
{
svn_error_t *err;
err = svn_error_trace(svn_sqlite__column_properties(props, stmt, 1,
result_pool,
scratch_pool));
if (err)
return svn_error_compose_create(err, svn_sqlite__reset(stmt));
}
}
else
*conflict = NULL;
SVN_ERR(svn_sqlite__reset(stmt));
if (!have_row || kind || (props && !*props))
{
svn_error_t *err = NULL;
svn_boolean_t have_info = FALSE;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
local_relpath));
SVN_ERR(svn_sqlite__step(&have_info, stmt));
if (have_info)
{
if (kind)
{
svn_wc__db_status_t status;
int op_depth = svn_sqlite__column_int(stmt, 0);
status = svn_sqlite__column_token(stmt, 3, presence_map);
if (op_depth > 0)
err = convert_to_working_status(&status, status);
if (!err && (status == svn_wc__db_status_normal
|| status == svn_wc__db_status_added
|| status == svn_wc__db_status_deleted
|| status == svn_wc__db_status_incomplete))
{
*kind = svn_sqlite__column_token(stmt, 4, kind_map);
}
}
if (!err && (props && !*props))
{
err = svn_sqlite__column_properties(props, stmt, 14,
result_pool, scratch_pool);
}
}
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
if (!have_row && !have_info)
{
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_read_kind(svn_node_kind_t *kind,
svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t allow_missing,
svn_boolean_t show_deleted,
svn_boolean_t show_hidden,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt_info;
svn_boolean_t have_info;
svn_wc__db_status_t status;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt_info, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt_info, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_info, stmt_info));
if (!have_info)
{
if (allow_missing)
{
*kind = svn_node_unknown;
SVN_ERR(svn_sqlite__reset(stmt_info));
return SVN_NO_ERROR;
}
else
{
SVN_ERR(svn_sqlite__reset(stmt_info));
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
}
status = svn_sqlite__column_token(stmt_info, 3, presence_map);
if (show_deleted && status == svn_wc__db_status_base_deleted)
{
SVN_ERR(svn_sqlite__step(&have_info, stmt_info));
if (!have_info)
{
*kind = svn_node_none;
return svn_error_trace(svn_sqlite__reset(stmt_info));
}
}
if (!(show_deleted && show_hidden))
{
int op_depth = svn_sqlite__column_int(stmt_info, 0);
svn_boolean_t report_none = FALSE;
if (op_depth > 0)
SVN_ERR(convert_to_working_status(&status, status));
switch (status)
{
case svn_wc__db_status_not_present:
if (! (show_hidden && show_deleted))
report_none = TRUE;
break;
case svn_wc__db_status_excluded:
case svn_wc__db_status_server_excluded:
if (! show_hidden)
report_none = TRUE;
break;
case svn_wc__db_status_deleted:
if (! show_deleted)
report_none = TRUE;
break;
default:
break;
}
if (report_none)
{
*kind = svn_node_none;
return svn_error_trace(svn_sqlite__reset(stmt_info));
}
}
*kind = svn_sqlite__column_token(stmt_info, 4, kind_map);
return svn_error_trace(svn_sqlite__reset(stmt_info));
}
svn_error_t *
svn_wc__db_is_wcroot(svn_boolean_t *is_wcroot,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
if (*local_relpath != '\0')
{
*is_wcroot = FALSE;
return SVN_NO_ERROR;
}
*is_wcroot = TRUE;
return SVN_NO_ERROR;
}
static svn_error_t *
db_is_switched(svn_boolean_t *is_switched,
svn_node_kind_t *kind,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
svn_wc__db_status_t status;
apr_int64_t repos_id;
const char *repos_relpath;
const char *name;
const char *parent_local_relpath;
apr_int64_t parent_repos_id;
const char *parent_repos_relpath;
SVN_ERR_ASSERT(*local_relpath != '\0');
SVN_ERR(read_info(&status, kind, NULL, &repos_relpath, &repos_id, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
wcroot, local_relpath, scratch_pool, scratch_pool));
if (status == svn_wc__db_status_server_excluded
|| status == svn_wc__db_status_excluded
|| status == svn_wc__db_status_not_present)
{
return svn_error_createf(
SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
}
else if (! repos_relpath)
{
if (is_switched)
*is_switched = FALSE;
return SVN_NO_ERROR;
}
if (! is_switched)
return SVN_NO_ERROR;
svn_relpath_split(&parent_local_relpath, &name, local_relpath, scratch_pool);
SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
&parent_repos_relpath,
&parent_repos_id, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL,
wcroot, parent_local_relpath,
scratch_pool, scratch_pool));
if (repos_id != parent_repos_id)
*is_switched = TRUE;
else
{
const char *expected_relpath;
expected_relpath = svn_relpath_join(parent_repos_relpath, name,
scratch_pool);
*is_switched = (strcmp(expected_relpath, repos_relpath) != 0);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_is_switched(svn_boolean_t *is_wcroot,
svn_boolean_t *is_switched,
svn_node_kind_t *kind,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
if (is_switched)
*is_switched = FALSE;
if (*local_relpath == '\0')
{
if (is_wcroot)
*is_wcroot = TRUE;
if (kind)
*kind = svn_node_dir;
return SVN_NO_ERROR;
}
if (is_wcroot)
*is_wcroot = FALSE;
if (! is_switched && ! kind)
return SVN_NO_ERROR;
SVN_WC__DB_WITH_TXN(
db_is_switched(is_switched, kind, wcroot, local_relpath, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_temp_wcroot_tempdir(const char **temp_dir_abspath,
svn_wc__db_t *db,
const char *wri_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(temp_dir_abspath != NULL);
SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
*temp_dir_abspath = svn_dirent_join_many(result_pool,
wcroot->abspath,
svn_wc_get_adm_dir(scratch_pool),
WCROOT_TEMPDIR_RELPATH,
SVN_VA_NULL);
return SVN_NO_ERROR;
}
static svn_error_t *
wclock_steal(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_DELETE_WC_LOCK));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
return SVN_NO_ERROR;
}
static svn_error_t *
wclock_obtain_cb(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
int levels_to_lock,
svn_boolean_t steal_lock,
svn_boolean_t enforce_empty_wq,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_error_t *err;
const char *lock_relpath;
int max_depth;
int lock_depth;
svn_boolean_t got_row;
svn_wc__db_wclock_t lock;
if (local_relpath[0])
{
svn_boolean_t exists;
SVN_ERR(does_node_exist(&exists, wcroot, local_relpath));
if (!exists)
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
if (enforce_empty_wq)
SVN_ERR(svn_wc__db_verify_no_work(wcroot->sdb));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_FIND_WC_LOCK));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
lock_depth = relpath_depth(local_relpath);
max_depth = lock_depth + levels_to_lock;
SVN_ERR(svn_sqlite__step(&got_row, stmt));
while (got_row)
{
svn_boolean_t own_lock;
lock_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
if (levels_to_lock >= 0
&& relpath_depth(lock_relpath) > max_depth)
{
SVN_ERR(svn_sqlite__step(&got_row, stmt));
continue;
}
err = svn_wc__db_wclock_owns_lock_internal(&own_lock, wcroot,
lock_relpath,
TRUE, scratch_pool);
if (err)
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
if (!own_lock && !steal_lock)
{
SVN_ERR(svn_sqlite__reset(stmt));
err = svn_error_createf(SVN_ERR_WC_LOCKED, NULL,
_("'%s' is already locked."),
path_for_error_message(wcroot,
lock_relpath,
scratch_pool));
return svn_error_createf(SVN_ERR_WC_LOCKED, err,
_("Working copy '%s' locked."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
else if (!own_lock)
{
err = wclock_steal(wcroot, lock_relpath, scratch_pool);
if (err)
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
}
SVN_ERR(svn_sqlite__step(&got_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
if (steal_lock)
SVN_ERR(wclock_steal(wcroot, local_relpath, scratch_pool));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_WC_LOCK));
lock_relpath = local_relpath;
while (TRUE)
{
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, lock_relpath));
SVN_ERR(svn_sqlite__step(&got_row, stmt));
if (got_row)
{
int levels = svn_sqlite__column_int(stmt, 0);
if (levels >= 0)
levels += relpath_depth(lock_relpath);
SVN_ERR(svn_sqlite__reset(stmt));
if (levels == -1 || levels >= lock_depth)
{
err = svn_error_createf(
SVN_ERR_WC_LOCKED, NULL,
_("'%s' is already locked."),
svn_dirent_local_style(
svn_dirent_join(wcroot->abspath,
lock_relpath,
scratch_pool),
scratch_pool));
return svn_error_createf(
SVN_ERR_WC_LOCKED, err,
_("Working copy '%s' locked."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
}
break;
}
else
SVN_ERR(svn_sqlite__reset(stmt));
if (!*lock_relpath)
break;
lock_relpath = svn_relpath_dirname(lock_relpath, scratch_pool);
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_WC_LOCK));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
levels_to_lock));
err = svn_sqlite__insert(NULL, stmt);
if (err)
return svn_error_createf(SVN_ERR_WC_LOCKED, err,
_("Failed to lock working copy '%s'."),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
lock.local_relpath = apr_pstrdup(wcroot->owned_locks->pool, local_relpath);
lock.levels = levels_to_lock;
APR_ARRAY_PUSH(wcroot->owned_locks, svn_wc__db_wclock_t) = lock;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_wclock_obtain(svn_wc__db_t *db,
const char *local_abspath,
int levels_to_lock,
svn_boolean_t steal_lock,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(levels_to_lock >= -1);
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
if (!steal_lock)
{
int i;
int depth = relpath_depth(local_relpath);
for (i = 0; i < wcroot->owned_locks->nelts; i++)
{
svn_wc__db_wclock_t* lock = &APR_ARRAY_IDX(wcroot->owned_locks,
i, svn_wc__db_wclock_t);
if (svn_relpath_skip_ancestor(lock->local_relpath, local_relpath)
&& (lock->levels == -1
|| (lock->levels + relpath_depth(lock->local_relpath))
>= depth))
{
return svn_error_createf(
SVN_ERR_WC_LOCKED, NULL,
_("'%s' is already locked via '%s'."),
svn_dirent_local_style(local_abspath, scratch_pool),
path_for_error_message(wcroot, lock->local_relpath,
scratch_pool));
}
}
}
SVN_WC__DB_WITH_TXN(
wclock_obtain_cb(wcroot, local_relpath, levels_to_lock, steal_lock,
db->enforce_empty_wq, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
static svn_error_t *
find_wclock(const char **lock_relpath,
svn_wc__db_wcroot_t *wcroot,
const char *dir_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
int dir_depth = relpath_depth(dir_relpath);
const char *first_relpath;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_ANCESTOR_WCLOCKS));
first_relpath = strchr(dir_relpath, '/');
if (first_relpath != NULL)
first_relpath = apr_pstrndup(scratch_pool, dir_relpath,
first_relpath - dir_relpath);
else
first_relpath = dir_relpath;
SVN_ERR(svn_sqlite__bindf(stmt, "iss",
wcroot->wc_id,
dir_relpath,
first_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
const char *relpath = svn_sqlite__column_text(stmt, 0, NULL);
if (svn_relpath_skip_ancestor(relpath, dir_relpath))
{
int locked_levels = svn_sqlite__column_int(stmt, 1);
int row_depth = relpath_depth(relpath);
if (locked_levels == -1
|| locked_levels + row_depth >= dir_depth)
{
*lock_relpath = apr_pstrdup(result_pool, relpath);
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
}
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
*lock_relpath = NULL;
return svn_error_trace(svn_sqlite__reset(stmt));
}
static svn_error_t *
is_wclocked(svn_boolean_t *locked,
svn_wc__db_wcroot_t *wcroot,
const char *dir_relpath,
apr_pool_t *scratch_pool)
{
const char *lock_relpath;
SVN_ERR(find_wclock(&lock_relpath, wcroot, dir_relpath,
scratch_pool, scratch_pool));
*locked = (lock_relpath != NULL);
return SVN_NO_ERROR;
}
svn_error_t*
svn_wc__db_wclock_find_root(const char **lock_abspath,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
const char *lock_relpath;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
find_wclock(&lock_relpath, wcroot, local_relpath,
scratch_pool, scratch_pool),
wcroot);
if (!lock_relpath)
*lock_abspath = NULL;
else
SVN_ERR(svn_wc__db_from_relpath(lock_abspath, db, wcroot->abspath,
lock_relpath, result_pool, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_wclocked(svn_boolean_t *locked,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
is_wclocked(locked, wcroot, local_relpath, scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_wclock_release(svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
int i;
apr_array_header_t *owned_locks;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
owned_locks = wcroot->owned_locks;
for (i = 0; i < owned_locks->nelts; i++)
{
svn_wc__db_wclock_t *lock = &APR_ARRAY_IDX(owned_locks, i,
svn_wc__db_wclock_t);
if (strcmp(lock->local_relpath, local_relpath) == 0)
break;
}
if (i >= owned_locks->nelts)
return svn_error_createf(SVN_ERR_WC_NOT_LOCKED, NULL,
_("Working copy not locked at '%s'."),
svn_dirent_local_style(local_abspath,
scratch_pool));
if (i < owned_locks->nelts)
{
owned_locks->nelts--;
if (owned_locks->nelts > 0)
APR_ARRAY_IDX(owned_locks, i, svn_wc__db_wclock_t) =
APR_ARRAY_IDX(owned_locks, owned_locks->nelts, svn_wc__db_wclock_t);
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_WC_LOCK));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_wclock_owns_lock_internal(svn_boolean_t *own_lock,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_boolean_t exact,
apr_pool_t *scratch_pool)
{
apr_array_header_t *owned_locks;
int lock_level;
int i;
*own_lock = FALSE;
owned_locks = wcroot->owned_locks;
lock_level = relpath_depth(local_relpath);
if (exact)
{
for (i = 0; i < owned_locks->nelts; i++)
{
svn_wc__db_wclock_t *lock = &APR_ARRAY_IDX(owned_locks, i,
svn_wc__db_wclock_t);
if (strcmp(lock->local_relpath, local_relpath) == 0)
{
*own_lock = TRUE;
return SVN_NO_ERROR;
}
}
}
else
{
for (i = 0; i < owned_locks->nelts; i++)
{
svn_wc__db_wclock_t *lock = &APR_ARRAY_IDX(owned_locks, i,
svn_wc__db_wclock_t);
if (svn_relpath_skip_ancestor(lock->local_relpath, local_relpath)
&& (lock->levels == -1
|| ((relpath_depth(lock->local_relpath) + lock->levels)
>= lock_level)))
{
*own_lock = TRUE;
return SVN_NO_ERROR;
}
}
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_wclock_owns_lock(svn_boolean_t *own_lock,
svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t exact,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
if (!wcroot)
return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
_("The node '%s' was not found."),
svn_dirent_local_style(local_abspath,
scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_wc__db_wclock_owns_lock_internal(own_lock, wcroot, local_relpath,
exact, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
end_directory_update(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_wc__db_status_t base_status;
SVN_ERR(svn_wc__db_base_get_info_internal(&base_status, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
wcroot, local_relpath,
scratch_pool, scratch_pool));
if (base_status == svn_wc__db_status_normal)
return SVN_NO_ERROR;
SVN_ERR_ASSERT(base_status == svn_wc__db_status_incomplete);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_NODE_BASE_PRESENCE));
SVN_ERR(svn_sqlite__bindf(stmt, "ist", wcroot->wc_id, local_relpath,
presence_map, svn_wc__db_status_normal));
SVN_ERR(svn_sqlite__step_done(stmt));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_temp_op_end_directory_update(svn_wc__db_t *db,
const char *local_dir_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_dir_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_dir_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
end_directory_update(wcroot, local_relpath, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_dir_abspath, svn_depth_empty,
scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
start_directory_update_txn(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
const char *new_repos_relpath,
svn_revnum_t new_rev,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_BASE_NODE_PRESENCE_REVNUM_AND_REPOS_PATH));
SVN_ERR(svn_sqlite__bindf(stmt, "istrs",
wcroot->wc_id,
local_relpath,
presence_map, svn_wc__db_status_incomplete,
new_rev,
new_repos_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_temp_op_start_directory_update(svn_wc__db_t *db,
const char *local_abspath,
const char *new_repos_relpath,
svn_revnum_t new_rev,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(new_rev));
SVN_ERR_ASSERT(svn_relpath_is_canonical(new_repos_relpath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
start_directory_update_txn(wcroot, local_relpath,
new_repos_relpath, new_rev, scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
db_move_moved_to(svn_wc__db_wcroot_t *wcroot,
const char *src1_relpath,
int src1_op_depth,
const char *src2_relpath,
int src2_op_depth,
const char *dst_relpath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
int affected_rows;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_MOVED_TO_RELPATH));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
src1_relpath, src1_op_depth));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
if (affected_rows == 1)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_MOVED_TO_RELPATH));
SVN_ERR(svn_sqlite__bindf(stmt, "isds", wcroot->wc_id,
src2_relpath, src2_op_depth,
dst_relpath));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
}
if (affected_rows != 1)
return svn_error_create(SVN_ERR_WC_PATH_NOT_FOUND, NULL, NULL);
return SVN_NO_ERROR;
}
static svn_error_t *
db_move_moved_to_down_recursive(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
int new_shadow_layer,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MOVED_DESCENDANTS_SRC));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
new_shadow_layer));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
int del_op_depth;
const char *src_relpath;
const char *dst_relpath;
svn_error_t *err;
svn_pool_clear(iterpool);
del_op_depth = svn_sqlite__column_int(stmt, 0);
src_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
dst_relpath = svn_sqlite__column_text(stmt, 4, iterpool);
err = svn_error_trace(
db_move_moved_to(
wcroot,
src_relpath, del_op_depth,
src_relpath, new_shadow_layer,
dst_relpath, iterpool));
if (err)
return svn_error_compose_create(err, svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
static svn_error_t *
make_copy_txn(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_int64_t last_repos_id,
const char *last_repos_relpath,
svn_revnum_t last_revision,
int last_op_depth,
svn_boolean_t shadowed,
int root_shadow_depth,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row = FALSE;
svn_revnum_t revision;
apr_int64_t repos_id;
const char *repos_relpath;
svn_node_kind_t kind;
int op_depth = relpath_depth(local_relpath);
if (last_op_depth != op_depth)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_DEPTH_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
SVN_ERR(svn_sqlite__reset(stmt));
if (have_row)
shadowed = TRUE;
}
SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &kind, &revision,
&repos_relpath, &repos_id, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
wcroot, local_relpath,
scratch_pool, scratch_pool));
if (last_repos_relpath
&& repos_id == last_repos_id
&& revision == last_revision)
{
const char *name = svn_relpath_skip_ancestor(last_repos_relpath,
repos_relpath);
if (name && strcmp(name, svn_relpath_basename(local_relpath, NULL)) == 0)
op_depth = last_op_depth;
}
if (!have_row || op_depth == last_op_depth)
{
int i;
SVN_ERR(svn_sqlite__get_statement(
&stmt, wcroot->sdb,
STMT_INSERT_WORKING_NODE_FROM_BASE_COPY));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
op_depth));
SVN_ERR(svn_sqlite__step_done(stmt));
if (shadowed)
SVN_ERR(db_extend_parent_delete(wcroot, local_relpath, kind,
op_depth, scratch_pool));
if (kind == svn_node_dir)
{
const apr_array_header_t *children;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
SVN_ERR(gather_children(&children, wcroot, local_relpath,
STMT_SELECT_OP_DEPTH_CHILDREN, 0,
scratch_pool, iterpool));
for (i = 0; i < children->nelts; i++)
{
const char *name = APR_ARRAY_IDX(children, i, const char *);
const char *copy_relpath;
svn_pool_clear(iterpool);
copy_relpath = svn_relpath_join(local_relpath, name, iterpool);
SVN_ERR(make_copy_txn(wcroot, copy_relpath,
repos_id, repos_relpath, revision,
op_depth, shadowed, root_shadow_depth,
scratch_pool));
}
svn_pool_destroy(iterpool);
}
}
else
{
SVN_ERR(db_move_moved_to_down_recursive(wcroot, local_relpath,
root_shadow_depth,
scratch_pool));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_WORKING_BASE_DELETE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
last_op_depth));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
last_op_depth));
SVN_ERR(svn_sqlite__step_done(stmt));
}
if (last_op_depth > 0 && last_op_depth != op_depth)
{
insert_working_baton_t iwb;
blank_iwb(&iwb);
iwb.presence = svn_wc__db_status_not_present;
iwb.op_depth = last_op_depth;
iwb.original_repos_id = repos_id;
iwb.original_repos_relpath = repos_relpath;
iwb.original_revnum = revision;
iwb.kind = kind;
SVN_ERR(insert_working_node(&iwb, wcroot, local_relpath, scratch_pool));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_make_copy_internal(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_boolean_t move_move_info,
const svn_skel_t *conflicts,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
int op_depth = -1;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_WORKING_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
op_depth = svn_sqlite__column_int(stmt, 0);
SVN_ERR(svn_sqlite__reset(stmt));
if (have_row)
{
if (op_depth == relpath_depth(local_relpath))
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
_("Modification of '%s' already exists"),
path_for_error_message(wcroot,
local_relpath,
scratch_pool));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_COPY_OP_DEPTH_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "isdd", wcroot->wc_id, local_relpath,
op_depth, relpath_depth(local_relpath)));
SVN_ERR(svn_sqlite__step_done(stmt));
}
else
{
int affected_rows;
op_depth = relpath_depth(local_relpath);
SVN_ERR(catch_copy_of_server_excluded(wcroot, local_relpath,
scratch_pool));
SVN_ERR(svn_sqlite__get_statement(
&stmt, wcroot->sdb,
STMT_INSERT_DELETE_FROM_NODE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "isdd",
wcroot->wc_id, local_relpath,
0, op_depth));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
SVN_ERR_ASSERT(affected_rows > 0);
if (!move_move_info)
SVN_ERR(db_move_moved_to_down_recursive(wcroot, local_relpath,
op_depth, scratch_pool));
SVN_ERR(make_copy_txn(wcroot, local_relpath,
INVALID_REPOS_ID, NULL, SVN_INVALID_REVNUM,
op_depth, FALSE, op_depth,
scratch_pool));
}
if (conflicts)
SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
conflicts, scratch_pool));
SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_op_make_copy(svn_wc__db_t *db,
const char *local_abspath,
const svn_skel_t *conflicts,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
svn_wc__db_op_make_copy_internal(wcroot, local_relpath, FALSE,
conflicts, work_items,
scratch_pool),
wcroot);
SVN_ERR(flush_entries(wcroot, local_abspath,
svn_depth_infinity, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_info_below_working(svn_boolean_t *have_base,
svn_boolean_t *have_work,
svn_wc__db_status_t *status,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(info_below_working(have_base, have_work, status,
wcroot, local_relpath, -1, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_get_not_present_descendants(const apr_array_header_t **descendants,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_NOT_PRESENT_DESCENDANTS));
SVN_ERR(svn_sqlite__bindf(stmt, "isd",
wcroot->wc_id,
local_relpath,
relpath_depth(local_relpath)));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
{
apr_array_header_t *paths;
paths = apr_array_make(result_pool, 4, sizeof(const char*));
while (have_row)
{
const char *found_relpath = svn_sqlite__column_text(stmt, 0, NULL);
APR_ARRAY_PUSH(paths, const char *)
= apr_pstrdup(result_pool, svn_relpath_skip_ancestor(
local_relpath, found_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
*descendants = paths;
}
else
*descendants = apr_array_make(result_pool, 0, sizeof(const char*));
return svn_error_trace(svn_sqlite__reset(stmt));
}
static svn_error_t *
get_min_max_revisions(svn_revnum_t *min_revision,
svn_revnum_t *max_revision,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_boolean_t committed,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_revnum_t min_rev, max_rev;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MIN_MAX_REVISIONS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_row(stmt));
if (committed)
{
min_rev = svn_sqlite__column_revnum(stmt, 2);
max_rev = svn_sqlite__column_revnum(stmt, 3);
}
else
{
min_rev = svn_sqlite__column_revnum(stmt, 0);
max_rev = svn_sqlite__column_revnum(stmt, 1);
}
SVN_ERR(svn_sqlite__reset(stmt));
if (min_revision)
*min_revision = min_rev;
if (max_revision)
*max_revision = max_rev;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_min_max_revisions(svn_revnum_t *min_revision,
svn_revnum_t *max_revision,
svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t committed,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
return svn_error_trace(get_min_max_revisions(min_revision, max_revision,
wcroot, local_relpath,
committed, scratch_pool));
}
static svn_error_t *
is_sparse_checkout_internal(svn_boolean_t *is_sparse_checkout,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_HAS_SPARSE_NODES));
SVN_ERR(svn_sqlite__bindf(stmt, "is",
wcroot->wc_id,
local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
*is_sparse_checkout = have_row;
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
static svn_error_t *
has_switched_subtrees(svn_boolean_t *is_switched,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
const char *trail_url,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_int64_t repos_id;
const char *repos_relpath;
if (!is_switched)
return SVN_NO_ERROR;
*is_switched = FALSE;
SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
&repos_relpath, &repos_id,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
wcroot, local_relpath,
scratch_pool, scratch_pool));
if (trail_url != NULL)
{
const char *repos_root_url;
const char *url;
apr_size_t len1, len2;
SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, NULL, wcroot,
repos_id, scratch_pool));
url = svn_path_url_add_component2(repos_root_url, repos_relpath,
scratch_pool);
len1 = strlen(trail_url);
len2 = strlen(url);
if ((len1 > len2) || strcmp(url + len2 - len1, trail_url))
{
*is_switched = TRUE;
return SVN_NO_ERROR;
}
}
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_HAS_SWITCHED));
SVN_ERR(svn_sqlite__bindf(stmt, "iss", wcroot->wc_id, local_relpath, repos_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
*is_switched = TRUE;
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_has_switched_subtrees(svn_boolean_t *is_switched,
svn_wc__db_t *db,
const char *local_abspath,
const char *trail_url,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
return svn_error_trace(has_switched_subtrees(is_switched, wcroot,
local_relpath, trail_url,
scratch_pool));
}
svn_error_t *
svn_wc__db_get_excluded_subtrees(apr_hash_t **excluded_subtrees,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_ALL_EXCLUDED_DESCENDANTS));
SVN_ERR(svn_sqlite__bindf(stmt, "is",
wcroot->wc_id,
local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
*excluded_subtrees = apr_hash_make(result_pool);
else
*excluded_subtrees = NULL;
while (have_row)
{
const char *abs_path =
svn_dirent_join(wcroot->abspath,
svn_sqlite__column_text(stmt, 0, NULL),
result_pool);
svn_hash_sets(*excluded_subtrees, abs_path, abs_path);
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
return SVN_NO_ERROR;
}
static svn_error_t *
has_db_mods(svn_boolean_t *is_modified,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SUBTREE_HAS_TREE_MODIFICATIONS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(is_modified, stmt));
SVN_ERR(svn_sqlite__reset(stmt));
if (! *is_modified)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SUBTREE_HAS_PROP_MODIFICATIONS));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(is_modified, stmt));
SVN_ERR(svn_sqlite__reset(stmt));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_has_db_mods(svn_boolean_t *is_modified,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
return svn_error_trace(has_db_mods(is_modified, wcroot, local_relpath,
scratch_pool));
}
static svn_error_t *
revision_status_txn(svn_revnum_t *min_revision,
svn_revnum_t *max_revision,
svn_boolean_t *is_sparse_checkout,
svn_boolean_t *is_modified,
svn_boolean_t *is_switched,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_wc__db_t *db,
const char *trail_url,
svn_boolean_t committed,
apr_pool_t *scratch_pool)
{
svn_error_t *err;
svn_boolean_t exists;
SVN_ERR(does_node_exist(&exists, wcroot, local_relpath));
if (!exists)
{
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
}
SVN_ERR(get_min_max_revisions(min_revision, max_revision, wcroot,
local_relpath, committed, scratch_pool));
SVN_ERR(is_sparse_checkout_internal(is_sparse_checkout, wcroot,
local_relpath, scratch_pool));
{
err = has_switched_subtrees(is_switched, wcroot, local_relpath,
trail_url, scratch_pool);
if (err)
{
if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
return svn_error_trace(err);
svn_error_clear(err);
*is_switched = FALSE;
}
}
SVN_ERR(has_db_mods(is_modified, wcroot, local_relpath, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_revision_status(svn_revnum_t *min_revision,
svn_revnum_t *max_revision,
svn_boolean_t *is_sparse_checkout,
svn_boolean_t *is_modified,
svn_boolean_t *is_switched,
svn_wc__db_t *db,
const char *local_abspath,
const char *trail_url,
svn_boolean_t committed,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
revision_status_txn(min_revision, max_revision,
is_sparse_checkout, is_modified, is_switched,
wcroot, local_relpath, db,
trail_url, committed,
scratch_pool),
wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_base_get_lock_tokens_recursive(apr_hash_t **lock_tokens,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_int64_t last_repos_id = INVALID_REPOS_ID;
const char *last_repos_root_url = NULL;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
*lock_tokens = apr_hash_make(result_pool);
SVN_ERR(svn_sqlite__get_statement(
&stmt, wcroot->sdb,
STMT_SELECT_BASE_NODE_LOCK_TOKENS_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
apr_int64_t child_repos_id = svn_sqlite__column_int64(stmt, 0);
const char *child_relpath = svn_sqlite__column_text(stmt, 1, NULL);
const char *lock_token = svn_sqlite__column_text(stmt, 2, result_pool);
if (child_repos_id != last_repos_id)
{
svn_error_t *err = svn_wc__db_fetch_repos_info(&last_repos_root_url,
NULL, wcroot,
child_repos_id,
scratch_pool);
if (err)
{
return svn_error_trace(
svn_error_compose_create(err,
svn_sqlite__reset(stmt)));
}
last_repos_id = child_repos_id;
}
SVN_ERR_ASSERT(last_repos_root_url != NULL);
svn_hash_sets(*lock_tokens,
svn_path_url_add_component2(last_repos_root_url,
child_relpath, result_pool),
lock_token);
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
return svn_sqlite__reset(stmt);
}
#define VERIFY(expression) \
do { \
if (! (expression)) \
return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, \
_("database inconsistency at local_relpath='%s' verifying " \
"expression '%s'"), local_relpath, #expression); \
} while (0)
static svn_error_t *
verify_wcroot(svn_wc__db_wcroot_t *wcroot,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_ALL_NODES));
SVN_ERR(svn_sqlite__bindf(stmt, "i", wcroot->wc_id));
while (TRUE)
{
svn_boolean_t have_row;
const char *local_relpath, *parent_relpath;
int op_depth;
svn_pool_clear(iterpool);
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (!have_row)
break;
op_depth = svn_sqlite__column_int(stmt, 0);
local_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
parent_relpath = svn_sqlite__column_text(stmt, 2, iterpool);
VERIFY((parent_relpath == NULL)
? (local_relpath[0] == '\0')
: (strcmp(svn_relpath_dirname(local_relpath, iterpool),
parent_relpath) == 0));
VERIFY(op_depth <= relpath_depth(local_relpath));
if (parent_relpath && svn_sqlite__column_is_null(stmt, 3))
{
svn_sqlite__stmt_t *stmt2;
svn_boolean_t have_a_parent_row;
SVN_ERR(svn_sqlite__get_statement(&stmt2, wcroot->sdb,
STMT_SELECT_NODE_INFO));
SVN_ERR(svn_sqlite__bindf(stmt2, "is", wcroot->wc_id,
parent_relpath));
SVN_ERR(svn_sqlite__step(&have_a_parent_row, stmt2));
VERIFY(have_a_parent_row);
SVN_ERR(svn_sqlite__reset(stmt2));
}
}
svn_pool_destroy(iterpool);
return svn_error_trace(svn_sqlite__reset(stmt));
}
svn_error_t *
svn_wc__db_verify(svn_wc__db_t *db,
const char *wri_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, wri_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(verify_wcroot(wcroot, scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_verify_db_full_internal(svn_wc__db_wcroot_t *wcroot,
svn_wc__db_verify_cb_t callback,
void *baton,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
svn_error_t *err = NULL;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_STATIC_VERIFY));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
const char *local_relpath;
int op_depth = svn_sqlite__column_int(stmt, 1);
int id = svn_sqlite__column_int(stmt, 2);
const char *msg;
svn_pool_clear(iterpool);
local_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
msg = svn_sqlite__column_text(stmt, 3, scratch_pool);
err = callback(baton, wcroot->abspath, local_relpath, op_depth,
id, msg, iterpool);
if (err)
break;
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
svn_pool_destroy(iterpool);
return svn_error_trace(
svn_error_compose_create(err, svn_sqlite__reset(stmt)));
}
svn_error_t *
svn_wc__db_verify_db_full(svn_wc__db_t *db,
const char *wri_abspath,
svn_wc__db_verify_cb_t callback,
void *baton,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
return svn_error_trace(
svn_wc__db_verify_db_full_internal(wcroot, callback, baton,
scratch_pool));
}
svn_error_t *
svn_wc__db_bump_format(int *result_format,
svn_boolean_t *bumped_format,
svn_wc__db_t *db,
const char *wcroot_abspath,
apr_pool_t *scratch_pool)
{
svn_sqlite__db_t *sdb;
svn_error_t *err;
int format;
if (bumped_format)
*bumped_format = FALSE;
err = svn_wc__db_util_open_db(&sdb, wcroot_abspath, SDB_FILE,
svn_sqlite__mode_readwrite,
TRUE,
0,
NULL,
scratch_pool, scratch_pool);
if (err)
{
svn_error_t *err2;
apr_hash_t *entries;
err2 = svn_wc__read_entries_old(&entries, wcroot_abspath,
scratch_pool, scratch_pool);
if (err2 || apr_hash_count(entries) == 0)
return svn_error_createf(SVN_ERR_WC_INVALID_OP_ON_CWD,
svn_error_compose_create(err, err2),
_("Can't upgrade '%s' as it is not a working copy root"),
svn_dirent_local_style(wcroot_abspath, scratch_pool));
return svn_error_createf(SVN_ERR_WC_UPGRADE_REQUIRED, err,
_("Working copy '%s' is too old and must be upgraded to "
"at least format %d, as created by Subversion %s"),
svn_dirent_local_style(wcroot_abspath, scratch_pool),
SVN_WC__WC_NG_VERSION,
svn_wc__version_string_from_format(SVN_WC__WC_NG_VERSION));
}
SVN_ERR(svn_sqlite__read_schema_version(&format, sdb, scratch_pool));
err = svn_wc__upgrade_sdb(result_format, wcroot_abspath,
sdb, format, scratch_pool);
if (err == SVN_NO_ERROR && bumped_format)
*bumped_format = (*result_format > format);
if (err && err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
err = svn_error_create(SVN_ERR_WC_UNSUPPORTED_FORMAT, err,
_("Working copy upgrade failed"));
err = svn_error_compose_create(err, svn_sqlite__close(sdb));
return svn_error_trace(err);
}
svn_error_t *
svn_wc__db_vacuum(svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, STMT_VACUUM));
return SVN_NO_ERROR;
}
typedef struct commit_queue_item_t
{
const char *local_relpath;
svn_boolean_t recurse;
svn_boolean_t committed;
svn_boolean_t remove_lock;
svn_boolean_t remove_changelist;
const svn_checksum_t *new_sha1_checksum;
apr_hash_t *new_dav_cache;
} commit_queue_item_t;
struct svn_wc__db_commit_queue_t
{
svn_wc__db_wcroot_t *wcroot;
apr_array_header_t *items;
svn_boolean_t have_recurse;
};
svn_error_t *
svn_wc__db_create_commit_queue(svn_wc__db_commit_queue_t **queue,
svn_wc__db_t *db,
const char *wri_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_wc__db_commit_queue_t *q;
SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
wri_abspath, result_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
q = apr_pcalloc(result_pool, sizeof(*q));
SVN_ERR_ASSERT(wcroot->sdb);
q->wcroot = wcroot;
q->items = apr_array_make(result_pool, 64,
sizeof(commit_queue_item_t*));
q->have_recurse = FALSE;
*queue = q;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_commit_queue_add(svn_wc__db_commit_queue_t *queue,
const char *local_abspath,
svn_boolean_t recurse,
svn_boolean_t is_commited,
svn_boolean_t remove_lock,
svn_boolean_t remove_changelist,
const svn_checksum_t *new_sha1_checksum,
apr_hash_t *new_dav_cache,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
commit_queue_item_t *cqi;
const char *local_relpath;
local_relpath = svn_dirent_skip_ancestor(queue->wcroot->abspath,
local_abspath);
if (! local_relpath)
return svn_error_createf(
SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The path '%s' is not in the working copy '%s'"),
svn_dirent_local_style(local_abspath, scratch_pool),
svn_dirent_local_style(queue->wcroot->abspath, scratch_pool));
cqi = apr_pcalloc(result_pool, sizeof(*cqi));
cqi->local_relpath = local_relpath;
cqi->recurse = recurse;
cqi->committed = is_commited;
cqi->remove_lock = remove_lock;
cqi->remove_changelist = remove_changelist;
cqi->new_sha1_checksum = new_sha1_checksum;
cqi->new_dav_cache = new_dav_cache;
queue->have_recurse |= recurse;
APR_ARRAY_PUSH(queue->items, commit_queue_item_t *) = cqi;
return SVN_NO_ERROR;
}
static svn_error_t *
process_committed_leaf(svn_wc__db_t *db,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
svn_boolean_t via_recurse,
svn_wc__db_status_t status,
svn_node_kind_t kind,
svn_boolean_t prop_mods,
const svn_checksum_t *old_checksum,
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 remove_lock,
svn_boolean_t remove_changelist,
const svn_checksum_t *checksum,
apr_pool_t *scratch_pool)
{
svn_revnum_t new_changed_rev = new_revnum;
svn_skel_t *work_item = NULL;
{
const char *lock_relpath;
svn_boolean_t locked;
if (kind == svn_node_dir)
lock_relpath = local_relpath;
else
lock_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
SVN_ERR(svn_wc__db_wclock_owns_lock_internal(&locked, wcroot,
lock_relpath, FALSE,
scratch_pool));
if (!locked)
return svn_error_createf(SVN_ERR_WC_NOT_LOCKED, NULL,
_("No write-lock in '%s'"),
path_for_error_message(wcroot, local_relpath,
scratch_pool));
SVN_ERR(flush_entries(wcroot, lock_relpath, svn_depth_empty,
scratch_pool));
}
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
|| status == svn_wc__db_status_deleted);
if (kind != svn_node_dir
&& status != svn_wc__db_status_deleted)
{
if (checksum == NULL)
{
SVN_ERR_ASSERT(old_checksum != NULL);
checksum = old_checksum;
if (via_recurse && !prop_mods)
{
SVN_ERR(svn_wc__db_read_info_internal(
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,
wcroot, local_relpath,
scratch_pool, scratch_pool));
}
}
SVN_ERR(svn_wc__wq_build_file_commit(&work_item,
db, svn_dirent_join(wcroot->abspath,
local_relpath,
scratch_pool),
prop_mods,
scratch_pool, scratch_pool));
}
SVN_ERR(commit_node(wcroot, local_relpath,
new_revnum, new_changed_rev,
new_changed_date, new_changed_author,
checksum,
new_dav_cache,
!remove_changelist,
!remove_lock,
work_item,
scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
process_committed_internal(svn_wc__db_t *db,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
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 remove_lock,
svn_boolean_t remove_changelist,
const svn_checksum_t *new_sha1_checksum,
apr_hash_t *items_by_relpath,
apr_pool_t *scratch_pool)
{
svn_wc__db_status_t status;
svn_node_kind_t kind;
const svn_checksum_t *old_checksum;
svn_boolean_t prop_mods;
SVN_ERR(svn_wc__db_read_info_internal(&status, &kind, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, &old_checksum, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, &prop_mods, NULL, NULL, NULL,
wcroot, local_relpath,
scratch_pool, scratch_pool));
SVN_ERR(process_committed_leaf(db, wcroot, local_relpath, !top_of_recurse,
status, kind, prop_mods, old_checksum,
new_revnum, new_date, rev_author,
new_dav_cache,
remove_lock, remove_changelist,
new_sha1_checksum,
scratch_pool));
if (kind != svn_node_dir
|| status == svn_wc__db_status_not_present
|| status == svn_wc__db_status_excluded
|| status == svn_wc__db_status_server_excluded
|| status == svn_wc__db_status_deleted)
{
return SVN_NO_ERROR;
}
if (recurse)
{
const apr_array_header_t *children;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
int i;
SVN_ERR(gather_children(&children, wcroot, local_relpath,
STMT_SELECT_NODE_CHILDREN, -1,
scratch_pool, iterpool));
for (i = 0; i < children->nelts; i++)
{
const char *name = APR_ARRAY_IDX(children, i, const char *);
const char *this_relpath;
const commit_queue_item_t *cqi;
svn_pool_clear(iterpool);
this_relpath = svn_dirent_join(local_relpath, name, iterpool);
new_sha1_checksum = NULL;
cqi = svn_hash_gets(items_by_relpath, this_relpath);
if (cqi != NULL)
new_sha1_checksum = cqi->new_sha1_checksum;
SVN_ERR(process_committed_internal(
db, wcroot, this_relpath,
TRUE ,
FALSE ,
new_revnum, new_date,
rev_author,
NULL ,
FALSE ,
remove_changelist,
new_sha1_checksum,
items_by_relpath,
iterpool));
}
svn_pool_destroy(iterpool);
}
return SVN_NO_ERROR;
}
static svn_boolean_t
have_recursive_parent(const apr_array_header_t *all_items,
const commit_queue_item_t *item,
apr_pool_t *scratch_pool)
{
const char *local_relpath = item->local_relpath;
int i;
for (i = 0; i < all_items->nelts; i++)
{
const commit_queue_item_t *qi
= APR_ARRAY_IDX(all_items, i, const commit_queue_item_t *);
if (qi == item)
continue;
if (qi->recurse && svn_relpath_skip_ancestor(qi->local_relpath,
local_relpath))
{
return TRUE;
}
}
return FALSE;
}
static int
compare_queue_items(const void *v1,
const void *v2)
{
const commit_queue_item_t *cqi1
= *(const commit_queue_item_t **)v1;
const commit_queue_item_t *cqi2
= *(const commit_queue_item_t **)v2;
return svn_path_compare_paths(cqi1->local_relpath, cqi2->local_relpath);
}
static svn_error_t *
db_process_commit_queue(svn_wc__db_t *db,
svn_wc__db_commit_queue_t *queue,
svn_revnum_t new_revnum,
apr_time_t new_date,
const char *new_author,
apr_pool_t *scratch_pool)
{
apr_hash_t *items_by_relpath = NULL;
int j;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
svn_sort__array(queue->items, compare_queue_items);
if (queue->have_recurse)
{
items_by_relpath = apr_hash_make(scratch_pool);
for (j = 0; j < queue->items->nelts; j++)
{
commit_queue_item_t *cqi
= APR_ARRAY_IDX(queue->items, j, commit_queue_item_t *);
svn_hash_sets(items_by_relpath, cqi->local_relpath, cqi);
}
}
for (j = 0; j < queue->items->nelts; j++)
{
commit_queue_item_t *cqi
= APR_ARRAY_IDX(queue->items, j, commit_queue_item_t *);
svn_pool_clear(iterpool);
if (queue->have_recurse && have_recursive_parent(queue->items, cqi,
iterpool))
continue;
if (!cqi->committed)
{
if (cqi->remove_lock)
{
svn_skel_t *work_item;
SVN_ERR(svn_wc__wq_build_sync_file_flags(
&work_item,
db,
svn_dirent_join(
queue->wcroot->abspath,
cqi->local_relpath,
iterpool),
iterpool, iterpool));
lock_remove_txn(queue->wcroot, cqi->local_relpath, work_item,
iterpool);
}
if (cqi->remove_changelist)
SVN_ERR(svn_wc__db_op_set_changelist(db,
svn_dirent_join(
queue->wcroot->abspath,
cqi->local_relpath,
iterpool),
NULL, NULL,
svn_depth_empty,
NULL, NULL,
NULL, NULL,
iterpool));
}
else
{
SVN_ERR(process_committed_internal(
db, queue->wcroot, cqi->local_relpath,
cqi->recurse,
TRUE ,
new_revnum, new_date, new_author,
cqi->new_dav_cache,
cqi->remove_lock,
cqi->remove_changelist,
cqi->new_sha1_checksum,
items_by_relpath,
iterpool));
}
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__db_process_commit_queue(svn_wc__db_t *db,
svn_wc__db_commit_queue_t *queue,
svn_revnum_t new_revnum,
apr_time_t new_date,
const char *new_author,
apr_pool_t *scratch_pool)
{
SVN_WC__DB_WITH_TXN(db_process_commit_queue(db, queue,
new_revnum, new_date,
new_author, scratch_pool),
queue->wcroot);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__find_repos_node_in_wc(apr_array_header_t **local_abspath_list,
svn_wc__db_t *db,
const char *wri_abspath,
const char *repos_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *wri_relpath;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &wri_relpath, db,
wri_abspath, scratch_pool,
scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_FIND_REPOS_PATH_IN_WC));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, repos_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
*local_abspath_list = apr_array_make(result_pool, have_row ? 1 : 0,
sizeof(const char*));
while (have_row)
{
const char *local_relpath;
const char *local_abspath;
local_relpath = svn_sqlite__column_text(stmt, 0, NULL);
local_abspath = svn_dirent_join(wcroot->abspath, local_relpath,
result_pool);
APR_ARRAY_PUSH(*local_abspath_list, const char *) = local_abspath;
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
return svn_error_trace(svn_sqlite__reset(stmt));
}