#include <stdio.h>
#define APR_WANT_STRFUNC
#include <apr_want.h>
#include <apr_pools.h>
#include "svn_types.h"
#include "svn_error.h"
#include "svn_path.h"
#include "svn_delta.h"
#include "svn_fs.h"
#include "svn_repos.h"
#include "repos.h"
#include "svn_private_config.h"
static svn_repos_node_t *
create_node(const char *name,
svn_repos_node_t *parent,
apr_pool_t *pool)
{
svn_repos_node_t *node = apr_pcalloc(pool, sizeof(*node));
node->action = 'R';
node->kind = svn_node_unknown;
node->name = apr_pstrdup(pool, name);
node->parent = parent;
return node;
}
static svn_repos_node_t *
create_sibling_node(svn_repos_node_t *elder,
const char *name,
apr_pool_t *pool)
{
svn_repos_node_t *tmp_node;
if (! elder)
return NULL;
tmp_node = elder;
while (tmp_node->sibling)
tmp_node = tmp_node->sibling;
return (tmp_node->sibling = create_node(name, elder->parent, pool));
}
static svn_repos_node_t *
create_child_node(svn_repos_node_t *parent,
const char *name,
apr_pool_t *pool)
{
if (! parent)
return NULL;
if (! parent->child)
return (parent->child = create_node(name, parent, pool));
return create_sibling_node(parent->child, name, pool);
}
static svn_repos_node_t *
find_child_by_name(svn_repos_node_t *parent,
const char *name)
{
svn_repos_node_t *tmp_node;
if ((! parent) || (! parent->child))
return NULL;
tmp_node = parent->child;
while (1)
{
if (! strcmp(tmp_node->name, name))
{
return tmp_node;
}
else
{
if (tmp_node->sibling)
tmp_node = tmp_node->sibling;
else
break;
}
}
return NULL;
}
static void
find_real_base_location(const char **path_p,
svn_revnum_t *rev_p,
svn_repos_node_t *node,
apr_pool_t *pool)
{
if ((node->action == 'A')
&& node->copyfrom_path
&& SVN_IS_VALID_REVNUM(node->copyfrom_rev))
{
*path_p = node->copyfrom_path;
*rev_p = node->copyfrom_rev;
return;
}
if (node->parent)
{
const char *path;
svn_revnum_t rev;
find_real_base_location(&path, &rev, node->parent, pool);
*path_p = svn_path_join(path, node->name, pool);
*rev_p = rev;
return;
}
*path_p = "/";
*rev_p = SVN_INVALID_REVNUM;
return;
}
struct edit_baton
{
svn_fs_t *fs;
svn_fs_root_t *root;
svn_fs_root_t *base_root;
apr_pool_t *node_pool;
svn_repos_node_t *node;
};
struct node_baton
{
struct edit_baton *edit_baton;
struct node_baton *parent_baton;
svn_repos_node_t *node;
};
static svn_error_t *
delete_entry(const char *path,
svn_revnum_t revision,
void *parent_baton,
apr_pool_t *pool)
{
struct node_baton *d = parent_baton;
struct edit_baton *eb = d->edit_baton;
svn_repos_node_t *node;
const char *name;
const char *base_path;
svn_revnum_t base_rev;
svn_fs_root_t *base_root;
svn_node_kind_t kind;
name = svn_path_basename(path, pool);
node = find_child_by_name(d->node, name);
if (! node)
node = create_child_node(d->node, name, eb->node_pool);
node->action = 'D';
find_real_base_location(&base_path, &base_rev, node, pool);
if (! SVN_IS_VALID_REVNUM(base_rev))
{
base_root = eb->base_root;
}
else
{
SVN_ERR(svn_fs_revision_root(&base_root, eb->fs, base_rev, pool));
}
SVN_ERR(svn_fs_check_path(&kind, base_root, base_path, pool));
if (kind == svn_node_none)
return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
_("'%s' not found in filesystem"), path);
node->kind = kind;
return SVN_NO_ERROR;
}
static svn_error_t *
add_open_helper(const char *path,
char action,
svn_node_kind_t kind,
void *parent_baton,
const char *copyfrom_path,
svn_revnum_t copyfrom_rev,
apr_pool_t *pool,
void **child_baton)
{
struct node_baton *pb = parent_baton;
struct edit_baton *eb = pb->edit_baton;
struct node_baton *nb = apr_pcalloc(pool, sizeof(*nb));
SVN_ERR_ASSERT(parent_baton && path);
nb->edit_baton = eb;
nb->parent_baton = pb;
nb->node = create_child_node(pb->node, svn_path_basename(path, pool),
eb->node_pool);
nb->node->kind = kind;
nb->node->action = action;
nb->node->copyfrom_rev = copyfrom_rev;
nb->node->copyfrom_path =
copyfrom_path ? apr_pstrdup(eb->node_pool, copyfrom_path) : NULL;
*child_baton = nb;
return SVN_NO_ERROR;
}
static svn_error_t *
open_root(void *edit_baton,
svn_revnum_t base_revision,
apr_pool_t *pool,
void **root_baton)
{
struct edit_baton *eb = edit_baton;
struct node_baton *d = apr_pcalloc(pool, sizeof(*d));
d->edit_baton = eb;
d->parent_baton = NULL;
d->node = (eb->node = create_node("", NULL, eb->node_pool));
d->node->kind = svn_node_dir;
d->node->action = 'R';
*root_baton = d;
return SVN_NO_ERROR;
}
static svn_error_t *
open_directory(const char *path,
void *parent_baton,
svn_revnum_t base_revision,
apr_pool_t *pool,
void **child_baton)
{
return add_open_helper(path, 'R', svn_node_dir, parent_baton,
NULL, SVN_INVALID_REVNUM,
pool, child_baton);
}
static svn_error_t *
add_directory(const char *path,
void *parent_baton,
const char *copyfrom_path,
svn_revnum_t copyfrom_revision,
apr_pool_t *pool,
void **child_baton)
{
return add_open_helper(path, 'A', svn_node_dir, parent_baton,
copyfrom_path, copyfrom_revision,
pool, child_baton);
}
static svn_error_t *
open_file(const char *path,
void *parent_baton,
svn_revnum_t base_revision,
apr_pool_t *pool,
void **file_baton)
{
return add_open_helper(path, 'R', svn_node_file, parent_baton,
NULL, SVN_INVALID_REVNUM,
pool, file_baton);
}
static svn_error_t *
add_file(const char *path,
void *parent_baton,
const char *copyfrom_path,
svn_revnum_t copyfrom_revision,
apr_pool_t *pool,
void **file_baton)
{
return add_open_helper(path, 'A', svn_node_file, parent_baton,
copyfrom_path, copyfrom_revision,
pool, file_baton);
}
static svn_error_t *
apply_textdelta(void *file_baton,
const char *base_checksum,
apr_pool_t *pool,
svn_txdelta_window_handler_t *handler,
void **handler_baton)
{
struct node_baton *fb = file_baton;
fb->node->text_mod = TRUE;
*handler = svn_delta_noop_window_handler;
*handler_baton = NULL;
return SVN_NO_ERROR;
}
static svn_error_t *
change_node_prop(void *node_baton,
const char *name,
const svn_string_t *value,
apr_pool_t *pool)
{
struct node_baton *nb = node_baton;
nb->node->prop_mod = TRUE;
return SVN_NO_ERROR;
}
svn_error_t *
svn_repos_node_editor(const svn_delta_editor_t **editor,
void **edit_baton,
svn_repos_t *repos,
svn_fs_root_t *base_root,
svn_fs_root_t *root,
apr_pool_t *node_pool,
apr_pool_t *pool)
{
svn_delta_editor_t *my_editor;
struct edit_baton *my_edit_baton;
my_editor = svn_delta_default_editor(pool);
my_editor->open_root = open_root;
my_editor->delete_entry = delete_entry;
my_editor->add_directory = add_directory;
my_editor->open_directory = open_directory;
my_editor->add_file = add_file;
my_editor->open_file = open_file;
my_editor->apply_textdelta = apply_textdelta;
my_editor->change_file_prop = change_node_prop;
my_editor->change_dir_prop = change_node_prop;
my_edit_baton = apr_pcalloc(pool, sizeof(*my_edit_baton));
my_edit_baton->node_pool = node_pool;
my_edit_baton->fs = repos->fs;
my_edit_baton->root = root;
my_edit_baton->base_root = base_root;
*editor = my_editor;
*edit_baton = my_edit_baton;
return SVN_NO_ERROR;
}
svn_repos_node_t *
svn_repos_node_from_baton(void *edit_baton)
{
struct edit_baton *eb = edit_baton;
return eb->node;
}