#include <string.h>
#include <assert.h>
#include <apr_strings.h>
#include "svn_error.h"
#include "svn_types.h"
#include "svn_time.h"
#include "svn_pools.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_ctype.h"
#include "svn_string.h"
#include "wc.h"
#include "adm_files.h"
#include "entries.h"
#include "lock.h"
#include "tree_conflicts.h"
#include "wc_db.h"
#include "wc-queries.h"
#include "svn_private_config.h"
#include "private/svn_wc_private.h"
#include "private/svn_sqlite.h"
#define MAYBE_ALLOC(x,p) ((x) ? (x) : apr_pcalloc((p), sizeof(*(x))))
typedef struct db_node_t {
apr_int64_t wc_id;
const char *local_relpath;
apr_int64_t op_depth;
apr_int64_t repos_id;
const char *repos_relpath;
const char *parent_relpath;
svn_wc__db_status_t presence;
svn_revnum_t revision;
svn_node_kind_t kind;
svn_checksum_t *checksum;
svn_filesize_t translated_size;
svn_revnum_t changed_rev;
apr_time_t changed_date;
const char *changed_author;
svn_depth_t depth;
apr_time_t last_mod_time;
apr_hash_t *properties;
svn_boolean_t file_external;
} db_node_t;
typedef struct db_actual_node_t {
apr_int64_t wc_id;
const char *local_relpath;
const char *parent_relpath;
apr_hash_t *properties;
const char *conflict_old;
const char *conflict_new;
const char *conflict_working;
const char *prop_reject;
const char *changelist;
const char *tree_conflict_data;
} db_actual_node_t;
static svn_wc_entry_t *
alloc_entry(apr_pool_t *pool)
{
svn_wc_entry_t *entry = apr_pcalloc(pool, sizeof(*entry));
entry->revision = SVN_INVALID_REVNUM;
entry->copyfrom_rev = SVN_INVALID_REVNUM;
entry->cmt_rev = SVN_INVALID_REVNUM;
entry->kind = svn_node_none;
entry->working_size = SVN_WC_ENTRY_WORKING_SIZE_UNKNOWN;
entry->depth = svn_depth_infinity;
entry->file_external_peg_rev.kind = svn_opt_revision_unspecified;
entry->file_external_rev.kind = svn_opt_revision_unspecified;
return entry;
}
svn_error_t *
svn_wc__entry_is_hidden(svn_boolean_t *hidden, const svn_wc_entry_t *entry)
{
if (entry->deleted
|| entry->absent
|| entry->depth == svn_depth_exclude)
{
SVN_ERR_ASSERT(entry->schedule == svn_wc_schedule_add
|| entry->schedule == svn_wc_schedule_normal);
*hidden = entry->schedule != svn_wc_schedule_add;
}
else
*hidden = FALSE;
return SVN_NO_ERROR;
}
static svn_error_t *
check_file_external(svn_wc_entry_t *entry,
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_status_t status;
svn_wc__db_kind_t kind;
const char *repos_relpath;
svn_revnum_t peg_revision;
svn_revnum_t revision;
svn_error_t *err;
err = svn_wc__db_external_read(&status, &kind, NULL, NULL, NULL,
&repos_relpath, &peg_revision, &revision,
db, local_abspath, wri_abspath,
result_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 (status == svn_wc__db_status_normal
&& kind == svn_wc__db_kind_file)
{
entry->file_external_path = repos_relpath;
if (SVN_IS_VALID_REVNUM(peg_revision))
{
entry->file_external_peg_rev.kind = svn_opt_revision_number;
entry->file_external_peg_rev.value.number = peg_revision;
entry->file_external_rev = entry->file_external_peg_rev;
}
if (SVN_IS_VALID_REVNUM(revision))
{
entry->file_external_rev.kind = svn_opt_revision_number;
entry->file_external_rev.value.number = revision;
}
}
return SVN_NO_ERROR;
}
static svn_error_t *
get_info_for_deleted(svn_wc_entry_t *entry,
svn_wc__db_kind_t *kind,
const char **repos_relpath,
const svn_checksum_t **checksum,
svn_wc__db_t *db,
const char *entry_abspath,
const svn_wc_entry_t *parent_entry,
svn_boolean_t have_base,
svn_boolean_t have_more_work,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
if (have_base && !have_more_work)
{
SVN_ERR(svn_wc__db_base_get_info(NULL, kind,
&entry->revision,
repos_relpath,
&entry->repos,
&entry->uuid,
&entry->cmt_rev,
&entry->cmt_date,
&entry->cmt_author,
&entry->depth,
checksum,
NULL,
NULL ,
&entry->has_props,
NULL,
db,
entry_abspath,
result_pool,
scratch_pool));
if (*repos_relpath == NULL)
SVN_ERR(svn_wc__db_scan_base_repos(repos_relpath,
&entry->repos,
&entry->uuid,
db,
entry_abspath,
result_pool,
scratch_pool));
}
else
{
const char *work_del_abspath;
const char *parent_repos_relpath;
const char *parent_abspath;
SVN_ERR(svn_wc__db_read_pristine_info(NULL, kind,
&entry->cmt_rev,
&entry->cmt_date,
&entry->cmt_author,
&entry->depth,
checksum,
NULL,
&entry->has_props,
db,
entry_abspath,
result_pool,
scratch_pool));
SVN_ERR(svn_wc__db_scan_deletion(NULL,
NULL,
&work_del_abspath,
db, entry_abspath,
scratch_pool, scratch_pool));
SVN_ERR_ASSERT(work_del_abspath != NULL);
parent_abspath = svn_dirent_dirname(work_del_abspath, scratch_pool);
SVN_ERR(svn_wc__db_scan_addition(NULL, NULL,
&parent_repos_relpath,
&entry->repos,
&entry->uuid,
NULL, NULL, NULL, NULL,
db, parent_abspath,
result_pool, scratch_pool));
*repos_relpath = svn_relpath_join(parent_repos_relpath,
svn_dirent_is_child(parent_abspath,
entry_abspath,
NULL),
result_pool);
if (have_base)
{
svn_wc__db_status_t status;
SVN_ERR(svn_wc__db_base_get_info(&status, NULL, &entry->revision,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
db, entry_abspath,
result_pool, scratch_pool));
if (status == svn_wc__db_status_not_present)
entry->deleted = TRUE;
}
}
if (!SVN_IS_VALID_REVNUM(entry->revision) && parent_entry != NULL)
{
entry->revision = parent_entry->revision;
}
return SVN_NO_ERROR;
}
static svn_error_t *
write_tree_conflicts(const char **conflict_data,
apr_hash_t *conflicts,
apr_pool_t *pool)
{
svn_skel_t *skel = svn_skel__make_empty_list(pool);
apr_hash_index_t *hi;
for (hi = apr_hash_first(pool, conflicts); hi; hi = apr_hash_next(hi))
{
svn_skel_t *c_skel;
SVN_ERR(svn_wc__serialize_conflict(&c_skel, svn__apr_hash_index_val(hi),
pool, pool));
svn_skel__prepend(c_skel, skel);
}
*conflict_data = svn_skel__unparse(skel, pool)->data;
return SVN_NO_ERROR;
}
static svn_error_t *
read_one_entry(const svn_wc_entry_t **new_entry,
svn_wc__db_t *db,
apr_int64_t wc_id,
const char *dir_abspath,
const char *name,
const svn_wc_entry_t *parent_entry,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc__db_kind_t kind;
svn_wc__db_status_t status;
svn_wc__db_lock_t *lock;
const char *repos_relpath;
const svn_checksum_t *checksum;
svn_filesize_t translated_size;
svn_wc_entry_t *entry = alloc_entry(result_pool);
const char *entry_abspath;
const char *original_repos_relpath;
const char *original_root_url;
svn_boolean_t conflicted;
svn_boolean_t have_base;
svn_boolean_t have_more_work;
entry->name = name;
entry_abspath = svn_dirent_join(dir_abspath, entry->name, scratch_pool);
SVN_ERR(svn_wc__db_read_info(
&status,
&kind,
&entry->revision,
&repos_relpath,
&entry->repos,
&entry->uuid,
&entry->cmt_rev,
&entry->cmt_date,
&entry->cmt_author,
&entry->depth,
&checksum,
NULL,
&original_repos_relpath,
&original_root_url,
NULL,
&entry->copyfrom_rev,
&lock,
&translated_size,
&entry->text_time,
&entry->changelist,
&conflicted,
NULL ,
&entry->has_props ,
&entry->has_prop_mods ,
&have_base,
&have_more_work,
NULL ,
db,
entry_abspath,
result_pool,
scratch_pool));
if (entry->has_prop_mods)
entry->has_props = TRUE;
if (strcmp(entry->name, SVN_WC_ENTRY_THIS_DIR) == 0)
{
apr_hash_t *tree_conflicts = NULL;
const apr_array_header_t *conflict_victims;
int k;
SVN_ERR(svn_wc__db_read_conflict_victims(&conflict_victims, db,
dir_abspath,
scratch_pool,
scratch_pool));
for (k = 0; k < conflict_victims->nelts; k++)
{
int j;
const apr_array_header_t *child_conflicts;
const char *child_name;
const char *child_abspath;
child_name = APR_ARRAY_IDX(conflict_victims, k, const char *);
child_abspath = svn_dirent_join(dir_abspath, child_name,
scratch_pool);
SVN_ERR(svn_wc__db_read_conflicts(&child_conflicts,
db, child_abspath,
scratch_pool, scratch_pool));
for (j = 0; j < child_conflicts->nelts; j++)
{
const svn_wc_conflict_description2_t *conflict =
APR_ARRAY_IDX(child_conflicts, j,
svn_wc_conflict_description2_t *);
if (conflict->kind == svn_wc_conflict_kind_tree)
{
if (!tree_conflicts)
tree_conflicts = apr_hash_make(scratch_pool);
apr_hash_set(tree_conflicts, child_name,
APR_HASH_KEY_STRING, conflict);
}
}
}
if (tree_conflicts)
{
SVN_ERR(write_tree_conflicts(&entry->tree_conflict_data,
tree_conflicts, result_pool));
}
}
if (status == svn_wc__db_status_normal
|| status == svn_wc__db_status_incomplete)
{
entry->schedule = svn_wc_schedule_normal;
if (repos_relpath == NULL)
{
SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath,
&entry->repos,
&entry->uuid,
db,
entry_abspath,
result_pool,
scratch_pool));
}
entry->incomplete = (status == svn_wc__db_status_incomplete);
}
else if (status == svn_wc__db_status_deleted)
{
svn_node_kind_t path_kind;
entry->schedule = svn_wc_schedule_delete;
if (have_more_work || !have_base)
entry->copied = TRUE;
else if (have_base && !have_more_work)
entry->copied = FALSE;
else
{
const char *work_del_abspath;
SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL,
&work_del_abspath,
db, entry_abspath,
scratch_pool, scratch_pool));
if (work_del_abspath)
entry->copied = TRUE;
}
SVN_ERR(svn_io_check_path(entry_abspath, &path_kind, scratch_pool));
entry->keep_local = (path_kind == svn_node_dir);
}
else if (status == svn_wc__db_status_added)
{
svn_wc__db_status_t work_status;
const char *op_root_abspath;
const char *scanned_original_relpath;
svn_revnum_t original_revision;
if (*entry->name != '\0')
{
assert(parent_entry != NULL);
assert(entry->revision == SVN_INVALID_REVNUM);
entry->revision = parent_entry->revision;
}
if (have_base)
{
svn_wc__db_status_t base_status;
SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL,
&entry->revision,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
db, entry_abspath,
scratch_pool,
scratch_pool));
if (base_status == svn_wc__db_status_not_present)
{
entry->deleted = TRUE;
entry->schedule = svn_wc_schedule_add;
}
else
entry->schedule = svn_wc_schedule_replace;
}
else
{
if (!SVN_IS_VALID_REVNUM(entry->copyfrom_rev)
&& !SVN_IS_VALID_REVNUM(entry->cmt_rev))
entry->revision = 0;
entry->schedule = svn_wc_schedule_add;
}
{
SVN_ERR(svn_wc__db_scan_addition(&work_status,
&op_root_abspath,
&repos_relpath,
&entry->repos,
&entry->uuid,
&scanned_original_relpath,
NULL, NULL,
&original_revision,
db,
entry_abspath,
result_pool, scratch_pool));
if (work_status == svn_wc__db_status_added
&& entry->deleted)
entry->revision = 0;
}
if (!SVN_IS_VALID_REVNUM(entry->cmt_rev)
&& scanned_original_relpath == NULL)
{
}
else if (work_status == svn_wc__db_status_copied)
{
entry->copied = TRUE;
if (original_repos_relpath == NULL)
{
entry->schedule = svn_wc_schedule_normal;
}
if (!SVN_IS_VALID_REVNUM(entry->revision)
|| entry->revision == 0 )
entry->revision = original_revision;
}
if (scanned_original_relpath != NULL)
{
svn_boolean_t is_copied_child;
svn_boolean_t is_mixed_rev = FALSE;
SVN_ERR_ASSERT(work_status == svn_wc__db_status_copied);
is_copied_child = (original_repos_relpath == NULL);
if (!is_copied_child)
{
const char *parent_abspath;
svn_error_t *err;
const char *parent_repos_relpath;
const char *parent_root_url;
parent_abspath = svn_dirent_dirname(entry_abspath,
scratch_pool);
err = svn_wc__db_scan_addition(NULL,
&op_root_abspath,
NULL, NULL, NULL,
&parent_repos_relpath,
&parent_root_url,
NULL, NULL,
db,
parent_abspath,
scratch_pool,
scratch_pool);
if (err)
{
if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
return svn_error_trace(err);
svn_error_clear(err);
}
else if (parent_root_url != NULL
&& strcmp(original_root_url, parent_root_url) == 0)
{
const char *relpath_to_entry = svn_dirent_is_child(
op_root_abspath, entry_abspath, NULL);
const char *entry_repos_relpath = svn_relpath_join(
parent_repos_relpath, relpath_to_entry, scratch_pool);
if (strcmp(entry_repos_relpath,
original_repos_relpath) == 0)
{
is_copied_child = TRUE;
is_mixed_rev = TRUE;
}
}
}
if (is_copied_child)
{
entry->copyfrom_rev = SVN_INVALID_REVNUM;
entry->schedule = svn_wc_schedule_normal;
if (is_mixed_rev)
entry->revision = original_revision;
}
else if (original_repos_relpath != NULL)
{
entry->copyfrom_url =
svn_path_url_add_component2(original_root_url,
original_repos_relpath,
result_pool);
}
else
{
const char *relpath_to_entry = svn_dirent_is_child(
op_root_abspath, entry_abspath, NULL);
const char *entry_repos_relpath = svn_relpath_join(
scanned_original_relpath, relpath_to_entry, scratch_pool);
entry->copyfrom_url =
svn_path_url_add_component2(original_root_url,
entry_repos_relpath,
result_pool);
}
}
}
else if (status == svn_wc__db_status_not_present)
{
entry->schedule = svn_wc_schedule_normal;
entry->deleted = TRUE;
}
else if (status == svn_wc__db_status_server_excluded)
{
entry->absent = TRUE;
}
else if (status == svn_wc__db_status_excluded)
{
entry->schedule = svn_wc_schedule_normal;
entry->depth = svn_depth_exclude;
}
else
{
SVN_ERR_MALFUNCTION();
}
if (entry->schedule == svn_wc_schedule_delete)
{
SVN_ERR(get_info_for_deleted(entry,
&kind,
&repos_relpath,
&checksum,
db, entry_abspath,
parent_entry,
have_base, have_more_work,
result_pool, scratch_pool));
}
if (entry->depth == svn_depth_unknown)
entry->depth = svn_depth_infinity;
if (kind == svn_wc__db_kind_dir)
entry->kind = svn_node_dir;
else if (kind == svn_wc__db_kind_file)
entry->kind = svn_node_file;
else if (kind == svn_wc__db_kind_symlink)
entry->kind = svn_node_file;
else
entry->kind = svn_node_unknown;
SVN_ERR_ASSERT(repos_relpath != NULL
|| entry->schedule == svn_wc_schedule_delete
|| status == svn_wc__db_status_not_present
|| status == svn_wc__db_status_server_excluded
|| status == svn_wc__db_status_excluded);
if (repos_relpath)
entry->url = svn_path_url_add_component2(entry->repos,
repos_relpath,
result_pool);
if (checksum)
{
if (checksum->kind != svn_checksum_md5)
SVN_ERR(svn_wc__db_pristine_get_md5(&checksum, db,
entry_abspath, checksum,
scratch_pool, scratch_pool));
SVN_ERR_ASSERT(checksum->kind == svn_checksum_md5);
entry->checksum = svn_checksum_to_cstring(checksum, result_pool);
}
if (conflicted)
{
const apr_array_header_t *conflicts;
int j;
SVN_ERR(svn_wc__db_read_conflicts(&conflicts, db, entry_abspath,
scratch_pool, scratch_pool));
for (j = 0; j < conflicts->nelts; j++)
{
const svn_wc_conflict_description2_t *cd;
cd = APR_ARRAY_IDX(conflicts, j,
const svn_wc_conflict_description2_t *);
switch (cd->kind)
{
case svn_wc_conflict_kind_text:
if (cd->base_abspath)
entry->conflict_old = svn_dirent_basename(cd->base_abspath,
result_pool);
if (cd->their_abspath)
entry->conflict_new = svn_dirent_basename(cd->their_abspath,
result_pool);
if (cd->my_abspath)
entry->conflict_wrk = svn_dirent_basename(cd->my_abspath,
result_pool);
break;
case svn_wc_conflict_kind_property:
entry->prejfile = svn_dirent_basename(cd->their_abspath,
result_pool);
break;
case svn_wc_conflict_kind_tree:
break;
}
}
}
if (lock)
{
entry->lock_token = lock->token;
entry->lock_owner = lock->owner;
entry->lock_comment = lock->comment;
entry->lock_creation_date = lock->date;
}
if (status == svn_wc__db_status_normal
&& kind == svn_wc__db_kind_file)
SVN_ERR(check_file_external(entry, db, entry_abspath, dir_abspath,
result_pool, scratch_pool));
entry->working_size = translated_size;
*new_entry = entry;
return SVN_NO_ERROR;
}
static svn_error_t *
read_entries_new(apr_hash_t **result_entries,
svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
apr_hash_t *entries;
const apr_array_header_t *children;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
int i;
const svn_wc_entry_t *parent_entry;
apr_int64_t wc_id = 1;
entries = apr_hash_make(result_pool);
SVN_ERR(read_one_entry(&parent_entry, db, wc_id, local_abspath,
"" ,
NULL ,
result_pool, iterpool));
apr_hash_set(entries, "", APR_HASH_KEY_STRING, parent_entry);
SVN_ERR(svn_wc__db_read_children(&children, db,
local_abspath,
result_pool, iterpool));
for (i = children->nelts; i--; )
{
const char *name = APR_ARRAY_IDX(children, i, const char *);
const svn_wc_entry_t *entry;
svn_pool_clear(iterpool);
SVN_ERR(read_one_entry(&entry,
db, wc_id, local_abspath, name, parent_entry,
result_pool, iterpool));
apr_hash_set(entries, entry->name, APR_HASH_KEY_STRING, entry);
}
svn_pool_destroy(iterpool);
*result_entries = entries;
return SVN_NO_ERROR;
}
static svn_error_t *
read_entry_pair(const svn_wc_entry_t **parent_entry,
const svn_wc_entry_t **entry,
svn_wc__db_t *db,
const char *dir_abspath,
const char *name,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
apr_int64_t wc_id = 1;
SVN_ERR(read_one_entry(parent_entry, db, wc_id, dir_abspath,
"" ,
NULL ,
result_pool, scratch_pool));
if (*name == '\0')
{
if ((*parent_entry)->kind == svn_node_file)
{
*parent_entry = NULL;
return svn_error_createf(SVN_ERR_WC_MISSING, NULL,
_("'%s' is not a versioned working copy"),
svn_dirent_local_style(dir_abspath,
scratch_pool));
}
*entry = *parent_entry;
}
else
{
const apr_array_header_t *children;
int i;
*entry = NULL;
SVN_ERR(svn_wc__db_read_children(&children, db, dir_abspath,
scratch_pool, scratch_pool));
for (i = children->nelts; i--; )
{
const char *child = APR_ARRAY_IDX(children, i, const char *);
if (strcmp(child, name) == 0)
{
svn_error_t *err;
err = read_one_entry(entry,
db, wc_id, dir_abspath, name, *parent_entry,
result_pool, scratch_pool);
if (err)
{
if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
return svn_error_trace(err);
svn_error_clear(err);
}
break;
}
}
}
return SVN_NO_ERROR;
}
static svn_error_t *
read_entries(apr_hash_t **entries,
svn_wc__db_t *db,
const char *wcroot_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
int wc_format;
SVN_ERR(svn_wc__db_temp_get_format(&wc_format, db, wcroot_abspath,
scratch_pool));
if (wc_format < SVN_WC__WC_NG_VERSION)
return svn_error_trace(svn_wc__read_entries_old(entries,
wcroot_abspath,
result_pool,
scratch_pool));
return svn_error_trace(read_entries_new(entries, db, wcroot_abspath,
result_pool, scratch_pool));
}
static svn_error_t *
get_entry_access_info(const char **adm_abspath,
const char **entry_name,
svn_wc__db_t *db,
const char *local_abspath,
svn_node_kind_t kind,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_wc_adm_access_t *adm_access;
svn_boolean_t read_from_subdir = FALSE;
if (kind == svn_node_unknown)
{
svn_node_kind_t on_disk;
adm_access = svn_wc__adm_retrieve_internal2(db, local_abspath,
scratch_pool);
if (adm_access)
{
on_disk = svn_node_dir;
}
else
{
svn_boolean_t special;
SVN_ERR(svn_io_check_special_path(local_abspath, &on_disk, &special,
scratch_pool));
}
if (on_disk != svn_node_dir)
{
}
else
{
read_from_subdir = TRUE;
}
}
else if (kind == svn_node_dir)
{
read_from_subdir = TRUE;
}
if (read_from_subdir)
{
*adm_abspath = apr_pstrdup(result_pool, local_abspath);
*entry_name = "";
}
else
{
svn_dirent_split(adm_abspath, entry_name, local_abspath, result_pool);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__get_entry(const svn_wc_entry_t **entry,
svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t allow_unversioned,
svn_node_kind_t kind,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *dir_abspath;
const char *entry_name;
SVN_ERR(get_entry_access_info(&dir_abspath, &entry_name, db, local_abspath,
kind, scratch_pool, scratch_pool));
{
const svn_wc_entry_t *parent_entry;
svn_error_t *err;
err = read_entry_pair(&parent_entry, entry,
db, dir_abspath, entry_name,
result_pool, scratch_pool);
if (err)
{
if (err->apr_err != SVN_ERR_WC_MISSING || kind != svn_node_unknown
|| *entry_name != '\0')
return svn_error_trace(err);
svn_error_clear(err);
err = svn_wc__get_entry(entry, db, local_abspath, allow_unversioned,
svn_node_file, result_pool, scratch_pool);
if (err == SVN_NO_ERROR)
return SVN_NO_ERROR;
if (err->apr_err != SVN_ERR_NODE_UNEXPECTED_KIND)
return svn_error_trace(err);
svn_error_clear(err);
SVN_ERR_ASSERT(*entry != NULL && (*entry)->kind == svn_node_dir);
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("Admin area of '%s' is missing"),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
}
if (*entry == NULL)
{
if (allow_unversioned)
return SVN_NO_ERROR;
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("'%s' is not under version control"),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
if ((kind == svn_node_file && (*entry)->kind != svn_node_file)
|| (kind == svn_node_dir && (*entry)->kind != svn_node_dir))
return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
_("'%s' is not of the right kind"),
svn_dirent_local_style(local_abspath,
scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
prune_deleted(apr_hash_t **entries_pruned,
apr_hash_t *entries_all,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
apr_hash_index_t *hi;
if (!entries_all)
{
*entries_pruned = NULL;
return SVN_NO_ERROR;
}
for (hi = apr_hash_first(scratch_pool, entries_all);
hi;
hi = apr_hash_next(hi))
{
svn_boolean_t hidden;
SVN_ERR(svn_wc__entry_is_hidden(&hidden,
svn__apr_hash_index_val(hi)));
if (hidden)
break;
}
if (! hi)
{
*entries_pruned = entries_all;
return SVN_NO_ERROR;
}
*entries_pruned = apr_hash_make(result_pool);
for (hi = apr_hash_first(scratch_pool, entries_all);
hi;
hi = apr_hash_next(hi))
{
const void *key = svn__apr_hash_index_key(hi);
const svn_wc_entry_t *entry = svn__apr_hash_index_val(hi);
svn_boolean_t hidden;
SVN_ERR(svn_wc__entry_is_hidden(&hidden, entry));
if (!hidden)
apr_hash_set(*entries_pruned, key, APR_HASH_KEY_STRING, entry);
}
return SVN_NO_ERROR;
}
struct entries_read_baton_t
{
apr_hash_t **new_entries;
svn_wc__db_t *db;
const char *local_abspath;
apr_pool_t *result_pool;
};
static svn_error_t *
entries_read_txn(void *baton, svn_sqlite__db_t *db, apr_pool_t *scratch_pool)
{
struct entries_read_baton_t *erb = baton;
SVN_ERR(read_entries(erb->new_entries, erb->db, erb->local_abspath,
erb->result_pool, scratch_pool));
return NULL;
}
svn_error_t *
svn_wc_entries_read(apr_hash_t **entries,
svn_wc_adm_access_t *adm_access,
svn_boolean_t show_hidden,
apr_pool_t *pool)
{
apr_hash_t *new_entries;
new_entries = svn_wc__adm_access_entries(adm_access);
if (! new_entries)
{
svn_wc__db_t *db = svn_wc__adm_get_db(adm_access);
const char *local_abspath = svn_wc__adm_access_abspath(adm_access);
apr_pool_t *result_pool = svn_wc_adm_access_pool(adm_access);
svn_sqlite__db_t *sdb;
struct entries_read_baton_t erb;
SVN_ERR(svn_wc__db_temp_borrow_sdb(&sdb, db, local_abspath, pool));
erb.db = db;
erb.local_abspath = local_abspath;
erb.new_entries = &new_entries;
erb.result_pool = result_pool;
SVN_ERR(svn_sqlite__with_lock(sdb, entries_read_txn, &erb, pool));
svn_wc__adm_access_set_entries(adm_access, new_entries);
}
if (show_hidden)
*entries = new_entries;
else
SVN_ERR(prune_deleted(entries, new_entries,
svn_wc_adm_access_pool(adm_access),
pool));
return SVN_NO_ERROR;
}
static svn_error_t *
insert_node(svn_sqlite__db_t *sdb,
const db_node_t *node,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
SVN_ERR_ASSERT(node->op_depth > 0 || node->repos_relpath);
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "isisnnnnsnrisnnni",
node->wc_id,
node->local_relpath,
node->op_depth,
node->parent_relpath,
svn_depth_to_word(node->depth),
node->changed_rev,
node->changed_date,
node->changed_author,
node->last_mod_time));
if (node->repos_relpath)
{
SVN_ERR(svn_sqlite__bind_int64(stmt, 5,
node->repos_id));
SVN_ERR(svn_sqlite__bind_text(stmt, 6,
node->repos_relpath));
SVN_ERR(svn_sqlite__bind_int64(stmt, 7, node->revision));
}
if (node->presence == svn_wc__db_status_normal)
SVN_ERR(svn_sqlite__bind_text(stmt, 8, "normal"));
else if (node->presence == svn_wc__db_status_not_present)
SVN_ERR(svn_sqlite__bind_text(stmt, 8, "not-present"));
else if (node->presence == svn_wc__db_status_base_deleted)
SVN_ERR(svn_sqlite__bind_text(stmt, 8, "base-deleted"));
else if (node->presence == svn_wc__db_status_incomplete)
SVN_ERR(svn_sqlite__bind_text(stmt, 8, "incomplete"));
else if (node->presence == svn_wc__db_status_excluded)
SVN_ERR(svn_sqlite__bind_text(stmt, 8, "excluded"));
else if (node->presence == svn_wc__db_status_server_excluded)
SVN_ERR(svn_sqlite__bind_text(stmt, 8, "absent"));
if (node->kind == svn_node_none)
SVN_ERR(svn_sqlite__bind_text(stmt, 10, "unknown"));
else
SVN_ERR(svn_sqlite__bind_text(stmt, 10,
svn_node_kind_to_word(node->kind)));
if (node->kind == svn_node_file)
{
if (!node->checksum
&& node->op_depth == 0
&& node->presence != svn_wc__db_status_not_present
&& node->presence != svn_wc__db_status_excluded
&& node->presence != svn_wc__db_status_server_excluded)
return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
_("The file '%s' has no checksum"),
svn_dirent_local_style(node->local_relpath,
scratch_pool));
SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, node->checksum,
scratch_pool));
}
if (node->properties)
SVN_ERR(svn_sqlite__bind_properties(stmt, 15, node->properties,
scratch_pool));
if (node->translated_size != SVN_INVALID_FILESIZE)
SVN_ERR(svn_sqlite__bind_int64(stmt, 16, node->translated_size));
if (node->file_external)
SVN_ERR(svn_sqlite__bind_int(stmt, 20, 1));
SVN_ERR(svn_sqlite__insert(NULL, stmt));
return SVN_NO_ERROR;
}
static svn_error_t *
insert_actual_node(svn_sqlite__db_t *sdb,
const db_actual_node_t *actual_node,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bind_int64(stmt, 1, actual_node->wc_id));
SVN_ERR(svn_sqlite__bind_text(stmt, 2, actual_node->local_relpath));
SVN_ERR(svn_sqlite__bind_text(stmt, 3, actual_node->parent_relpath));
if (actual_node->properties)
SVN_ERR(svn_sqlite__bind_properties(stmt, 4, actual_node->properties,
scratch_pool));
if (actual_node->conflict_old)
{
SVN_ERR(svn_sqlite__bind_text(stmt, 5, actual_node->conflict_old));
SVN_ERR(svn_sqlite__bind_text(stmt, 6, actual_node->conflict_new));
SVN_ERR(svn_sqlite__bind_text(stmt, 7, actual_node->conflict_working));
}
if (actual_node->prop_reject)
SVN_ERR(svn_sqlite__bind_text(stmt, 8, actual_node->prop_reject));
if (actual_node->changelist)
SVN_ERR(svn_sqlite__bind_text(stmt, 9, actual_node->changelist));
if (actual_node->tree_conflict_data)
SVN_ERR(svn_sqlite__bind_text(stmt, 10, actual_node->tree_conflict_data));
return svn_error_trace(svn_sqlite__insert(NULL, stmt));
}
struct write_baton {
db_node_t *base;
db_node_t *work;
db_node_t *below_work;
apr_hash_t *tree_conflicts;
};
static svn_error_t *
write_entry(struct write_baton **entry_node,
const struct write_baton *parent_node,
svn_wc__db_t *db,
svn_sqlite__db_t *sdb,
apr_int64_t wc_id,
apr_int64_t repos_id,
const svn_wc_entry_t *entry,
const svn_wc__text_base_info_t *text_base_info,
const char *local_relpath,
const char *tmp_entry_abspath,
const char *root_abspath,
const svn_wc_entry_t *this_dir,
svn_boolean_t create_locks,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
db_node_t *base_node = NULL;
db_node_t *working_node = NULL, *below_working_node = NULL;
db_actual_node_t *actual_node = NULL;
const char *parent_relpath;
apr_hash_t *tree_conflicts;
if (*local_relpath == '\0')
parent_relpath = NULL;
else
parent_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
SVN_ERR_ASSERT(parent_node || entry->schedule == svn_wc_schedule_normal);
SVN_ERR_ASSERT(!parent_node || parent_node->base
|| parent_node->below_work || parent_node->work);
switch (entry->schedule)
{
case svn_wc_schedule_normal:
if (entry->copied ||
(entry->depth == svn_depth_exclude
&& parent_node && !parent_node->base && parent_node->work))
working_node = MAYBE_ALLOC(working_node, result_pool);
else
base_node = MAYBE_ALLOC(base_node, result_pool);
break;
case svn_wc_schedule_add:
working_node = MAYBE_ALLOC(working_node, result_pool);
if (entry->deleted)
{
if (parent_node->base)
base_node = MAYBE_ALLOC(base_node, result_pool);
else
below_working_node = MAYBE_ALLOC(below_working_node, result_pool);
}
break;
case svn_wc_schedule_delete:
working_node = MAYBE_ALLOC(working_node, result_pool);
if (parent_node->base)
base_node = MAYBE_ALLOC(base_node, result_pool);
if (parent_node->work)
below_working_node = MAYBE_ALLOC(below_working_node, result_pool);
break;
case svn_wc_schedule_replace:
working_node = MAYBE_ALLOC(working_node, result_pool);
if (parent_node->base)
base_node = MAYBE_ALLOC(base_node, result_pool);
else
below_working_node = MAYBE_ALLOC(below_working_node, result_pool);
break;
}
if (entry->deleted)
{
SVN_ERR_ASSERT(base_node || below_working_node);
SVN_ERR_ASSERT(!entry->incomplete);
if (base_node)
base_node->presence = svn_wc__db_status_not_present;
else
below_working_node->presence = svn_wc__db_status_not_present;
}
else if (entry->absent)
{
SVN_ERR_ASSERT(base_node && !working_node && !below_working_node);
SVN_ERR_ASSERT(!entry->incomplete);
base_node->presence = svn_wc__db_status_server_excluded;
}
if (entry->copied)
{
if (entry->copyfrom_url)
{
const char *relpath;
working_node->repos_id = repos_id;
relpath = svn_uri__is_child(this_dir->repos,
entry->copyfrom_url,
result_pool);
if (relpath == NULL)
working_node->repos_relpath = "";
else
working_node->repos_relpath = relpath;
working_node->revision = entry->copyfrom_rev;
working_node->op_depth
= svn_wc__db_op_depth_for_upgrade(local_relpath);
}
else if (parent_node->work && parent_node->work->repos_relpath)
{
working_node->repos_id = repos_id;
working_node->repos_relpath
= svn_relpath_join(parent_node->work->repos_relpath,
svn_relpath_basename(local_relpath, NULL),
result_pool);
working_node->revision = parent_node->work->revision;
working_node->op_depth = parent_node->work->op_depth;
}
else
return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL,
_("No copyfrom URL for '%s'"),
svn_dirent_local_style(local_relpath,
scratch_pool));
}
if (entry->conflict_old)
{
actual_node = MAYBE_ALLOC(actual_node, scratch_pool);
if (parent_relpath && entry->conflict_old)
actual_node->conflict_old = svn_relpath_join(parent_relpath,
entry->conflict_old,
scratch_pool);
else
actual_node->conflict_old = entry->conflict_old;
if (parent_relpath && entry->conflict_new)
actual_node->conflict_new = svn_relpath_join(parent_relpath,
entry->conflict_new,
scratch_pool);
else
actual_node->conflict_new = entry->conflict_new;
if (parent_relpath && entry->conflict_wrk)
actual_node->conflict_working = svn_relpath_join(parent_relpath,
entry->conflict_wrk,
scratch_pool);
else
actual_node->conflict_working = entry->conflict_wrk;
}
if (entry->prejfile)
{
actual_node = MAYBE_ALLOC(actual_node, scratch_pool);
actual_node->prop_reject = svn_relpath_join((entry->kind == svn_node_dir
? local_relpath
: parent_relpath),
entry->prejfile,
scratch_pool);
}
if (entry->changelist)
{
actual_node = MAYBE_ALLOC(actual_node, scratch_pool);
actual_node->changelist = entry->changelist;
}
if (entry_node && entry->tree_conflict_data)
{
svn_skel_t *skel;
skel = svn_skel__parse(entry->tree_conflict_data,
strlen(entry->tree_conflict_data),
scratch_pool);
tree_conflicts = apr_hash_make(result_pool);
skel = skel->children;
while(skel)
{
svn_wc_conflict_description2_t *conflict;
svn_skel_t *new_skel;
const char *key;
SVN_ERR(svn_wc__deserialize_conflict(
(const svn_wc_conflict_description2_t**)&conflict,
skel,
svn_dirent_join(root_abspath,
local_relpath,
scratch_pool),
scratch_pool, scratch_pool));
SVN_ERR_ASSERT(conflict->kind == svn_wc_conflict_kind_tree);
if (conflict->reason == svn_wc_conflict_reason_added)
conflict->src_left_version = NULL;
SVN_ERR(svn_wc__serialize_conflict(&new_skel, conflict,
scratch_pool, scratch_pool));
key = svn_dirent_skip_ancestor(root_abspath, conflict->local_abspath);
apr_hash_set(tree_conflicts, apr_pstrdup(result_pool, key),
APR_HASH_KEY_STRING,
svn_skel__unparse(new_skel, result_pool)->data);
skel = skel->next;
}
}
else
tree_conflicts = NULL;
if (parent_node && parent_node->tree_conflicts)
{
const char *tree_conflict_data = apr_hash_get(parent_node->tree_conflicts,
local_relpath,
APR_HASH_KEY_STRING);
if (tree_conflict_data)
{
actual_node = MAYBE_ALLOC(actual_node, scratch_pool);
actual_node->tree_conflict_data = tree_conflict_data;
}
apr_hash_set(parent_node->tree_conflicts, local_relpath,
APR_HASH_KEY_STRING, NULL);
}
if (entry->file_external_path != NULL)
{
base_node = MAYBE_ALLOC(base_node, result_pool);
}
if (base_node)
{
base_node->wc_id = wc_id;
base_node->local_relpath = local_relpath;
base_node->op_depth = 0;
base_node->parent_relpath = parent_relpath;
base_node->revision = entry->revision;
base_node->last_mod_time = entry->text_time;
base_node->translated_size = entry->working_size;
if (entry->depth != svn_depth_exclude)
base_node->depth = entry->depth;
else
{
base_node->presence = svn_wc__db_status_excluded;
base_node->depth = svn_depth_infinity;
}
if (entry->deleted)
{
SVN_ERR_ASSERT(base_node->presence == svn_wc__db_status_not_present);
base_node->kind = entry->kind;
}
else if (entry->absent)
{
SVN_ERR_ASSERT(base_node->presence
== svn_wc__db_status_server_excluded);
base_node->kind = entry->kind;
if (!SVN_IS_VALID_REVNUM(base_node->revision) && parent_node->base)
base_node->revision = parent_node->base->revision;
}
else
{
base_node->kind = entry->kind;
if (base_node->presence != svn_wc__db_status_excluded)
{
if (entry->kind == svn_node_dir
&& strcmp(entry->name, SVN_WC_ENTRY_THIS_DIR))
{
base_node->presence = svn_wc__db_status_incomplete;
if (parent_node->base)
base_node->revision = parent_node->base->revision;
}
else if (entry->incomplete)
{
SVN_ERR_ASSERT(base_node->presence
== svn_wc__db_status_normal);
base_node->presence = svn_wc__db_status_incomplete;
}
}
}
if (entry->kind == svn_node_dir)
base_node->checksum = NULL;
else
{
if (text_base_info && text_base_info->revert_base.sha1_checksum)
base_node->checksum = text_base_info->revert_base.sha1_checksum;
else if (text_base_info && text_base_info->normal_base.sha1_checksum)
base_node->checksum = text_base_info->normal_base.sha1_checksum;
else
base_node->checksum = NULL;
if (! (working_node && entry->copied))
{
svn_checksum_t *entry_md5_checksum, *found_md5_checksum;
SVN_ERR(svn_checksum_parse_hex(&entry_md5_checksum,
svn_checksum_md5,
entry->checksum, scratch_pool));
if (text_base_info && text_base_info->revert_base.md5_checksum)
found_md5_checksum = text_base_info->revert_base.md5_checksum;
else if (text_base_info
&& text_base_info->normal_base.md5_checksum)
found_md5_checksum = text_base_info->normal_base.md5_checksum;
else
found_md5_checksum = NULL;
if (entry_md5_checksum && found_md5_checksum &&
!svn_checksum_match(entry_md5_checksum, found_md5_checksum))
return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
_("Bad base MD5 checksum for '%s'; "
"expected: '%s'; found '%s'; "),
svn_dirent_local_style(
svn_dirent_join(root_abspath,
local_relpath,
scratch_pool),
scratch_pool),
svn_checksum_to_cstring_display(
entry_md5_checksum, scratch_pool),
svn_checksum_to_cstring_display(
found_md5_checksum, scratch_pool));
else
{
}
}
}
if (this_dir->repos)
{
base_node->repos_id = repos_id;
if (entry->url != NULL)
{
const char *relpath = svn_uri__is_child(this_dir->repos,
entry->url,
result_pool);
base_node->repos_relpath = relpath ? relpath : "";
}
else
{
const char *relpath = svn_uri__is_child(this_dir->repos,
this_dir->url,
scratch_pool);
if (relpath == NULL)
base_node->repos_relpath = entry->name;
else
base_node->repos_relpath =
svn_dirent_join(relpath, entry->name, result_pool);
}
}
base_node->changed_rev = entry->cmt_rev;
base_node->changed_date = entry->cmt_date;
base_node->changed_author = entry->cmt_author;
if (entry->file_external_path)
base_node->file_external = TRUE;
SVN_ERR(insert_node(sdb, base_node, scratch_pool));
if (entry->lock_token && create_locks)
{
svn_wc__db_lock_t lock;
lock.token = entry->lock_token;
lock.owner = entry->lock_owner;
lock.comment = entry->lock_comment;
lock.date = entry->lock_creation_date;
SVN_ERR(svn_wc__db_lock_add(db, tmp_entry_abspath, &lock,
scratch_pool));
}
}
if (below_working_node)
{
db_node_t *work
= parent_node->below_work ? parent_node->below_work : parent_node->work;
below_working_node->wc_id = wc_id;
below_working_node->local_relpath = local_relpath;
below_working_node->op_depth = work->op_depth;
below_working_node->parent_relpath = parent_relpath;
below_working_node->presence = svn_wc__db_status_normal;
below_working_node->kind = entry->kind;
below_working_node->repos_id = work->repos_id;
if (work->repos_relpath)
below_working_node->repos_relpath
= svn_relpath_join(work->repos_relpath, entry->name,
result_pool);
else
below_working_node->repos_relpath = NULL;
below_working_node->revision = parent_node->work->revision;
below_working_node->checksum = NULL;
if (text_base_info)
{
if (entry->schedule == svn_wc_schedule_delete)
below_working_node->checksum =
text_base_info->normal_base.sha1_checksum;
else
below_working_node->checksum =
text_base_info->revert_base.sha1_checksum;
}
below_working_node->translated_size = 0;
below_working_node->changed_rev = SVN_INVALID_REVNUM;
below_working_node->changed_date = 0;
below_working_node->changed_author = NULL;
below_working_node->depth = svn_depth_infinity;
below_working_node->last_mod_time = 0;
below_working_node->properties = NULL;
SVN_ERR(insert_node(sdb, below_working_node, scratch_pool));
}
if (working_node)
{
working_node->wc_id = wc_id;
working_node->local_relpath = local_relpath;
working_node->parent_relpath = parent_relpath;
working_node->changed_rev = SVN_INVALID_REVNUM;
working_node->last_mod_time = entry->text_time;
working_node->translated_size = entry->working_size;
if (entry->depth != svn_depth_exclude)
working_node->depth = entry->depth;
else
{
working_node->presence = svn_wc__db_status_excluded;
working_node->depth = svn_depth_infinity;
}
if (entry->kind == svn_node_dir)
working_node->checksum = NULL;
else
{
working_node->checksum = NULL;
if (text_base_info)
working_node->checksum = text_base_info->normal_base.sha1_checksum;
#ifdef SVN_DEBUG
if (entry->checksum && text_base_info)
{
svn_checksum_t *md5_checksum;
SVN_ERR(svn_checksum_parse_hex(&md5_checksum, svn_checksum_md5,
entry->checksum, result_pool));
SVN_ERR_ASSERT(
md5_checksum && text_base_info->normal_base.md5_checksum);
SVN_ERR_ASSERT(svn_checksum_match(
md5_checksum, text_base_info->normal_base.md5_checksum));
}
#endif
}
working_node->kind = entry->kind;
if (working_node->presence != svn_wc__db_status_excluded)
{
if (entry->kind == svn_node_dir
&& strcmp(entry->name, SVN_WC_ENTRY_THIS_DIR))
{
working_node->presence = svn_wc__db_status_incomplete;
working_node->kind = svn_node_dir;
}
else if (entry->schedule == svn_wc_schedule_delete)
{
working_node->presence = svn_wc__db_status_base_deleted;
working_node->kind = entry->kind;
}
else
{
working_node->kind = entry->kind;
if (entry->incomplete)
{
SVN_ERR_ASSERT(working_node->presence
== svn_wc__db_status_normal);
working_node->presence = svn_wc__db_status_incomplete;
}
}
}
if (working_node->presence != svn_wc__db_status_base_deleted)
{
working_node->changed_rev = entry->cmt_rev;
working_node->changed_date = entry->cmt_date;
working_node->changed_author = entry->cmt_author;
}
if (entry->schedule == svn_wc_schedule_delete
&& parent_node->work
&& parent_node->work->presence == svn_wc__db_status_base_deleted)
{
working_node->op_depth = parent_node->work->op_depth;
}
else if (!entry->copied)
{
working_node->op_depth
= svn_wc__db_op_depth_for_upgrade(local_relpath);
}
SVN_ERR(insert_node(sdb, working_node, scratch_pool));
}
if (actual_node)
{
actual_node = MAYBE_ALLOC(actual_node, scratch_pool);
actual_node->wc_id = wc_id;
actual_node->local_relpath = local_relpath;
actual_node->parent_relpath = parent_relpath;
SVN_ERR(insert_actual_node(sdb, actual_node, scratch_pool));
}
if (entry_node)
{
*entry_node = apr_palloc(result_pool, sizeof(**entry_node));
(*entry_node)->base = base_node;
(*entry_node)->work = working_node;
(*entry_node)->below_work = below_working_node;
(*entry_node)->tree_conflicts = tree_conflicts;
}
if (entry->file_external_path)
{
}
return SVN_NO_ERROR;
}
static svn_error_t *
write_actual_only_entries(apr_hash_t *tree_conflicts,
svn_sqlite__db_t *sdb,
apr_int64_t wc_id,
const char *parent_relpath,
apr_pool_t *scratch_pool)
{
apr_hash_index_t *hi;
for (hi = apr_hash_first(scratch_pool, tree_conflicts);
hi;
hi = apr_hash_next(hi))
{
db_actual_node_t *actual_node = NULL;
actual_node = MAYBE_ALLOC(actual_node, scratch_pool);
actual_node->wc_id = wc_id;
actual_node->local_relpath = svn__apr_hash_index_key(hi);
actual_node->parent_relpath = parent_relpath;
actual_node->tree_conflict_data = svn__apr_hash_index_val(hi);
SVN_ERR(insert_actual_node(sdb, actual_node, scratch_pool));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__write_upgraded_entries(void **dir_baton,
void *parent_baton,
svn_wc__db_t *db,
svn_sqlite__db_t *sdb,
apr_int64_t repos_id,
apr_int64_t wc_id,
const char *dir_abspath,
const char *new_root_abspath,
apr_hash_t *entries,
apr_hash_t *text_bases_info,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const svn_wc_entry_t *this_dir;
apr_hash_index_t *hi;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
const char *old_root_abspath, *dir_relpath;
struct write_baton *parent_node = parent_baton;
struct write_baton *dir_node;
this_dir = apr_hash_get(entries, SVN_WC_ENTRY_THIS_DIR,
APR_HASH_KEY_STRING);
if (! this_dir)
return svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, NULL,
_("No default entry in directory '%s'"),
svn_dirent_local_style(dir_abspath,
iterpool));
old_root_abspath = svn_dirent_get_longest_ancestor(dir_abspath,
new_root_abspath,
scratch_pool);
SVN_ERR_ASSERT(old_root_abspath[0]);
dir_relpath = svn_dirent_skip_ancestor(old_root_abspath, dir_abspath);
SVN_ERR(write_entry(&dir_node, parent_node, db, sdb,
wc_id, repos_id, this_dir, NULL, dir_relpath,
svn_dirent_join(new_root_abspath, dir_relpath,
iterpool),
old_root_abspath,
this_dir, FALSE, result_pool, iterpool));
for (hi = apr_hash_first(scratch_pool, entries); hi;
hi = apr_hash_next(hi))
{
const char *name = svn__apr_hash_index_key(hi);
const svn_wc_entry_t *this_entry = svn__apr_hash_index_val(hi);
const char *child_abspath, *child_relpath;
svn_wc__text_base_info_t *text_base_info
= apr_hash_get(text_bases_info, name, APR_HASH_KEY_STRING);
svn_pool_clear(iterpool);
if (strcmp(name, SVN_WC_ENTRY_THIS_DIR) == 0)
continue;
child_abspath = svn_dirent_join(dir_abspath, name, iterpool);
child_relpath = svn_dirent_skip_ancestor(old_root_abspath, child_abspath);
SVN_ERR(write_entry(NULL, dir_node, db, sdb,
wc_id, repos_id,
this_entry, text_base_info, child_relpath,
svn_dirent_join(new_root_abspath, child_relpath,
iterpool),
old_root_abspath,
this_dir, TRUE, iterpool, iterpool));
}
if (dir_node->tree_conflicts)
SVN_ERR(write_actual_only_entries(dir_node->tree_conflicts, sdb,
wc_id, dir_relpath, iterpool));
*dir_baton = dir_node;
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
svn_wc_entry_t *
svn_wc_entry_dup(const svn_wc_entry_t *entry, apr_pool_t *pool)
{
svn_wc_entry_t *dupentry = apr_palloc(pool, sizeof(*dupentry));
*dupentry = *entry;
if (entry->name)
dupentry->name = apr_pstrdup(pool, entry->name);
if (entry->url)
dupentry->url = apr_pstrdup(pool, entry->url);
if (entry->repos)
dupentry->repos = apr_pstrdup(pool, entry->repos);
if (entry->uuid)
dupentry->uuid = apr_pstrdup(pool, entry->uuid);
if (entry->copyfrom_url)
dupentry->copyfrom_url = apr_pstrdup(pool, entry->copyfrom_url);
if (entry->conflict_old)
dupentry->conflict_old = apr_pstrdup(pool, entry->conflict_old);
if (entry->conflict_new)
dupentry->conflict_new = apr_pstrdup(pool, entry->conflict_new);
if (entry->conflict_wrk)
dupentry->conflict_wrk = apr_pstrdup(pool, entry->conflict_wrk);
if (entry->prejfile)
dupentry->prejfile = apr_pstrdup(pool, entry->prejfile);
if (entry->checksum)
dupentry->checksum = apr_pstrdup(pool, entry->checksum);
if (entry->cmt_author)
dupentry->cmt_author = apr_pstrdup(pool, entry->cmt_author);
if (entry->lock_token)
dupentry->lock_token = apr_pstrdup(pool, entry->lock_token);
if (entry->lock_owner)
dupentry->lock_owner = apr_pstrdup(pool, entry->lock_owner);
if (entry->lock_comment)
dupentry->lock_comment = apr_pstrdup(pool, entry->lock_comment);
if (entry->changelist)
dupentry->changelist = apr_pstrdup(pool, entry->changelist);
dupentry->cachable_props = "";
dupentry->present_props = "";
if (entry->tree_conflict_data)
dupentry->tree_conflict_data = apr_pstrdup(pool,
entry->tree_conflict_data);
if (entry->file_external_path)
dupentry->file_external_path = apr_pstrdup(pool,
entry->file_external_path);
return dupentry;
}
static svn_error_t *
walker_helper(const char *dirpath,
svn_wc_adm_access_t *adm_access,
const svn_wc_entry_callbacks2_t *walk_callbacks,
void *walk_baton,
svn_depth_t depth,
svn_boolean_t show_hidden,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *pool)
{
apr_pool_t *subpool = svn_pool_create(pool);
apr_hash_t *entries;
apr_hash_index_t *hi;
svn_wc_entry_t *dot_entry;
svn_error_t *err;
svn_wc__db_t *db = svn_wc__adm_get_db(adm_access);
err = svn_wc_entries_read(&entries, adm_access, show_hidden, pool);
if (err)
SVN_ERR(walk_callbacks->handle_error(dirpath, err, walk_baton, pool));
dot_entry = apr_hash_get(entries, SVN_WC_ENTRY_THIS_DIR,
APR_HASH_KEY_STRING);
if (! dot_entry)
return walk_callbacks->handle_error
(dirpath, svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, NULL,
_("Directory '%s' has no THIS_DIR entry"),
svn_dirent_local_style(dirpath, pool)),
walk_baton, pool);
err = walk_callbacks->found_entry(dirpath, dot_entry, walk_baton, subpool);
if(err)
SVN_ERR(walk_callbacks->handle_error(dirpath, err, walk_baton, pool));
if (depth == svn_depth_empty)
return SVN_NO_ERROR;
for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
{
const char *name = svn__apr_hash_index_key(hi);
const svn_wc_entry_t *current_entry = svn__apr_hash_index_val(hi);
const char *entrypath;
const char *entry_abspath;
svn_boolean_t hidden;
svn_pool_clear(subpool);
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
if (strcmp(current_entry->name, SVN_WC_ENTRY_THIS_DIR) == 0)
continue;
entrypath = svn_dirent_join(dirpath, name, subpool);
SVN_ERR(svn_wc__entry_is_hidden(&hidden, current_entry));
SVN_ERR(svn_dirent_get_absolute(&entry_abspath, entrypath, subpool));
if (current_entry->kind == svn_node_file
|| depth >= svn_depth_immediates)
{
err = walk_callbacks->found_entry(entrypath, current_entry,
walk_baton, subpool);
if (err)
SVN_ERR(walk_callbacks->handle_error(entrypath, err,
walk_baton, pool));
}
if (current_entry->kind == svn_node_dir
&& !hidden
&& depth >= svn_depth_immediates)
{
svn_wc_adm_access_t *entry_access;
svn_depth_t depth_below_here = depth;
if (depth == svn_depth_immediates)
depth_below_here = svn_depth_empty;
entry_access = svn_wc__adm_retrieve_internal2(db, entry_abspath,
subpool);
if (entry_access)
SVN_ERR(walker_helper(entrypath, entry_access,
walk_callbacks, walk_baton,
depth_below_here, show_hidden,
cancel_func, cancel_baton,
subpool));
}
}
svn_pool_destroy(subpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__walker_default_error_handler(const char *path,
svn_error_t *err,
void *walk_baton,
apr_pool_t *pool)
{
return svn_error_trace(err);
}
svn_error_t *
svn_wc_walk_entries3(const char *path,
svn_wc_adm_access_t *adm_access,
const svn_wc_entry_callbacks2_t *walk_callbacks,
void *walk_baton,
svn_depth_t walk_depth,
svn_boolean_t show_hidden,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *pool)
{
const char *local_abspath;
svn_wc__db_t *db = svn_wc__adm_get_db(adm_access);
svn_error_t *err;
svn_wc__db_kind_t kind;
svn_depth_t depth;
SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
err = svn_wc__db_read_info(NULL, &kind, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, &depth, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
db, local_abspath,
pool, pool);
if (err)
{
if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
return svn_error_trace(err);
svn_error_clear(err);
return walk_callbacks->handle_error(
path, svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL,
_("'%s' is not under version control"),
svn_dirent_local_style(local_abspath, pool)),
walk_baton, pool);
}
if (kind == svn_wc__db_kind_file || depth == svn_depth_exclude)
{
const svn_wc_entry_t *entry;
if (!show_hidden)
{
svn_boolean_t hidden;
SVN_ERR(svn_wc__db_node_hidden(&hidden, db, local_abspath, pool));
if (hidden)
{
return walk_callbacks->handle_error(
path, svn_error_createf(
SVN_ERR_UNVERSIONED_RESOURCE, NULL,
_("'%s' is not under version control"),
svn_dirent_local_style(local_abspath, pool)),
walk_baton, pool);
}
}
SVN_ERR(svn_wc__get_entry(&entry, db, local_abspath, FALSE,
svn_node_file, pool, pool));
err = walk_callbacks->found_entry(path, entry, walk_baton, pool);
if (err)
return walk_callbacks->handle_error(path, err, walk_baton, pool);
return SVN_NO_ERROR;
}
if (kind == svn_wc__db_kind_dir)
return walker_helper(path, adm_access, walk_callbacks, walk_baton,
walk_depth, show_hidden, cancel_func, cancel_baton,
pool);
return walk_callbacks->handle_error(
path, svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
_("'%s' has an unrecognized node kind"),
svn_dirent_local_style(local_abspath, pool)),
walk_baton, pool);
}