1251881Speter/* 2251881Speter * node_tree.c: an editor for tracking repository deltas changes 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter/* ==================================================================== */ 25251881Speter 26251881Speter 27251881Speter 28251881Speter 29251881Speter#include <stdio.h> 30251881Speter 31251881Speter#define APR_WANT_STRFUNC 32251881Speter#include <apr_want.h> 33251881Speter#include <apr_pools.h> 34251881Speter 35251881Speter#include "svn_types.h" 36251881Speter#include "svn_error.h" 37251881Speter#include "svn_dirent_uri.h" 38251881Speter#include "svn_path.h" 39251881Speter#include "svn_delta.h" 40251881Speter#include "svn_fs.h" 41251881Speter#include "svn_repos.h" 42251881Speter#include "repos.h" 43251881Speter#include "svn_private_config.h" 44251881Speter#include "private/svn_fspath.h" 45251881Speter 46251881Speter/*** NOTE: This editor is unique in that it currently is hard-coded to 47251881Speter be anchored at the root directory of the filesystem. This 48251881Speter affords us the ability to use the same paths for filesystem 49251881Speter locations and editor paths. ***/ 50251881Speter 51251881Speter 52251881Speter 53251881Speter/*** Node creation and assembly structures and routines. ***/ 54251881Speterstatic svn_repos_node_t * 55251881Spetercreate_node(const char *name, 56251881Speter svn_repos_node_t *parent, 57251881Speter apr_pool_t *pool) 58251881Speter{ 59251881Speter svn_repos_node_t *node = apr_pcalloc(pool, sizeof(*node)); 60251881Speter node->action = 'R'; 61251881Speter node->kind = svn_node_unknown; 62251881Speter node->name = apr_pstrdup(pool, name); 63251881Speter node->parent = parent; 64251881Speter return node; 65251881Speter} 66251881Speter 67251881Speter 68251881Speterstatic svn_repos_node_t * 69251881Spetercreate_sibling_node(svn_repos_node_t *elder, 70251881Speter const char *name, 71251881Speter apr_pool_t *pool) 72251881Speter{ 73251881Speter svn_repos_node_t *tmp_node; 74251881Speter 75251881Speter /* No ELDER sibling? That's just not gonna work out. */ 76251881Speter if (! elder) 77251881Speter return NULL; 78251881Speter 79251881Speter /* Run to the end of the list of siblings of ELDER. */ 80251881Speter tmp_node = elder; 81251881Speter while (tmp_node->sibling) 82251881Speter tmp_node = tmp_node->sibling; 83251881Speter 84251881Speter /* Create a new youngest sibling and return that. */ 85251881Speter return (tmp_node->sibling = create_node(name, elder->parent, pool)); 86251881Speter} 87251881Speter 88251881Speter 89251881Speterstatic svn_repos_node_t * 90251881Spetercreate_child_node(svn_repos_node_t *parent, 91251881Speter const char *name, 92251881Speter apr_pool_t *pool) 93251881Speter{ 94251881Speter /* No PARENT node? That's just not gonna work out. */ 95251881Speter if (! parent) 96251881Speter return NULL; 97251881Speter 98251881Speter /* If PARENT has no children, create its first one and return that. */ 99251881Speter if (! parent->child) 100251881Speter return (parent->child = create_node(name, parent, pool)); 101251881Speter 102251881Speter /* If PARENT already has a child, create a new sibling for its first 103251881Speter child and return that. */ 104251881Speter return create_sibling_node(parent->child, name, pool); 105251881Speter} 106251881Speter 107251881Speter 108251881Speterstatic svn_repos_node_t * 109251881Speterfind_child_by_name(svn_repos_node_t *parent, 110251881Speter const char *name) 111251881Speter{ 112251881Speter svn_repos_node_t *tmp_node; 113251881Speter 114251881Speter /* No PARENT node, or a barren PARENT? Nothing to find. */ 115251881Speter if ((! parent) || (! parent->child)) 116251881Speter return NULL; 117251881Speter 118251881Speter /* Look through the children for a node with a matching name. */ 119251881Speter tmp_node = parent->child; 120251881Speter while (1) 121251881Speter { 122251881Speter if (! strcmp(tmp_node->name, name)) 123251881Speter { 124251881Speter return tmp_node; 125251881Speter } 126251881Speter else 127251881Speter { 128251881Speter if (tmp_node->sibling) 129251881Speter tmp_node = tmp_node->sibling; 130251881Speter else 131251881Speter break; 132251881Speter } 133251881Speter } 134251881Speter 135251881Speter return NULL; 136251881Speter} 137251881Speter 138251881Speter 139251881Speterstatic void 140251881Speterfind_real_base_location(const char **path_p, 141251881Speter svn_revnum_t *rev_p, 142251881Speter svn_repos_node_t *node, 143251881Speter apr_pool_t *pool) 144251881Speter{ 145251881Speter /* If NODE is an add-with-history, then its real base location is 146251881Speter the copy source. */ 147251881Speter if ((node->action == 'A') 148251881Speter && node->copyfrom_path 149251881Speter && SVN_IS_VALID_REVNUM(node->copyfrom_rev)) 150251881Speter { 151251881Speter *path_p = node->copyfrom_path; 152251881Speter *rev_p = node->copyfrom_rev; 153251881Speter return; 154251881Speter } 155251881Speter 156251881Speter /* Otherwise, if NODE has a parent, we'll recurse, and add NODE's 157251881Speter name to whatever the parent's real base path turns out to be (and 158251881Speter pass the base revision on through). */ 159251881Speter if (node->parent) 160251881Speter { 161251881Speter const char *path; 162251881Speter svn_revnum_t rev; 163251881Speter 164251881Speter find_real_base_location(&path, &rev, node->parent, pool); 165251881Speter *path_p = svn_fspath__join(path, node->name, pool); 166251881Speter *rev_p = rev; 167251881Speter return; 168251881Speter } 169251881Speter 170251881Speter /* Finally, if the node has no parent, then its name is "/", and it 171251881Speter has no interesting base revision. */ 172251881Speter *path_p = "/"; 173251881Speter *rev_p = SVN_INVALID_REVNUM; 174251881Speter return; 175251881Speter} 176251881Speter 177251881Speter 178251881Speter 179251881Speter 180251881Speter/*** Editor functions and batons. ***/ 181251881Speter 182251881Speterstruct edit_baton 183251881Speter{ 184251881Speter svn_fs_t *fs; 185251881Speter svn_fs_root_t *root; 186251881Speter svn_fs_root_t *base_root; 187251881Speter apr_pool_t *node_pool; 188251881Speter svn_repos_node_t *node; 189251881Speter}; 190251881Speter 191251881Speter 192251881Speterstruct node_baton 193251881Speter{ 194251881Speter struct edit_baton *edit_baton; 195251881Speter struct node_baton *parent_baton; 196251881Speter svn_repos_node_t *node; 197251881Speter}; 198251881Speter 199251881Speter 200251881Speterstatic svn_error_t * 201251881Speterdelete_entry(const char *path, 202251881Speter svn_revnum_t revision, 203251881Speter void *parent_baton, 204251881Speter apr_pool_t *pool) 205251881Speter{ 206251881Speter struct node_baton *d = parent_baton; 207251881Speter struct edit_baton *eb = d->edit_baton; 208251881Speter svn_repos_node_t *node; 209251881Speter const char *name; 210251881Speter const char *base_path; 211251881Speter svn_revnum_t base_rev; 212251881Speter svn_fs_root_t *base_root; 213251881Speter svn_node_kind_t kind; 214251881Speter 215251881Speter /* Get (or create) the change node and update it. */ 216251881Speter name = svn_relpath_basename(path, pool); 217251881Speter node = find_child_by_name(d->node, name); 218251881Speter if (! node) 219251881Speter node = create_child_node(d->node, name, eb->node_pool); 220251881Speter node->action = 'D'; 221251881Speter 222251881Speter /* We need to look up this node's parents to see what its original 223251881Speter path in the filesystem was. Why? Because if this deletion 224251881Speter occurred underneath a copied path, the thing that was deleted 225251881Speter probably lived at a different location (relative to the copy 226251881Speter source). */ 227251881Speter find_real_base_location(&base_path, &base_rev, node, pool); 228251881Speter if (! SVN_IS_VALID_REVNUM(base_rev)) 229251881Speter { 230251881Speter /* No interesting base revision? We'll just look for the path 231251881Speter in our base root. */ 232251881Speter base_root = eb->base_root; 233251881Speter } 234251881Speter else 235251881Speter { 236251881Speter /* Oh. Perhaps some copy goodness happened somewhere? */ 237251881Speter SVN_ERR(svn_fs_revision_root(&base_root, eb->fs, base_rev, pool)); 238251881Speter } 239251881Speter 240251881Speter /* Now figure out if this thing was a file or a dir. */ 241251881Speter SVN_ERR(svn_fs_check_path(&kind, base_root, base_path, pool)); 242251881Speter if (kind == svn_node_none) 243251881Speter return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL, 244251881Speter _("'%s' not found in filesystem"), path); 245251881Speter node->kind = kind; 246251881Speter 247251881Speter return SVN_NO_ERROR; 248251881Speter} 249251881Speter 250251881Speter 251251881Speter 252251881Speterstatic svn_error_t * 253251881Speteradd_open_helper(const char *path, 254251881Speter char action, 255251881Speter svn_node_kind_t kind, 256251881Speter void *parent_baton, 257251881Speter const char *copyfrom_path, 258251881Speter svn_revnum_t copyfrom_rev, 259251881Speter apr_pool_t *pool, 260251881Speter void **child_baton) 261251881Speter{ 262251881Speter struct node_baton *pb = parent_baton; 263251881Speter struct edit_baton *eb = pb->edit_baton; 264251881Speter struct node_baton *nb = apr_pcalloc(pool, sizeof(*nb)); 265251881Speter 266251881Speter SVN_ERR_ASSERT(parent_baton && path); 267251881Speter 268251881Speter nb->edit_baton = eb; 269251881Speter nb->parent_baton = pb; 270251881Speter 271251881Speter /* Create and populate the node. */ 272251881Speter nb->node = create_child_node(pb->node, svn_relpath_basename(path, NULL), 273251881Speter eb->node_pool); 274251881Speter nb->node->kind = kind; 275251881Speter nb->node->action = action; 276251881Speter nb->node->copyfrom_rev = copyfrom_rev; 277251881Speter nb->node->copyfrom_path = 278251881Speter copyfrom_path ? apr_pstrdup(eb->node_pool, copyfrom_path) : NULL; 279251881Speter 280251881Speter *child_baton = nb; 281251881Speter return SVN_NO_ERROR; 282251881Speter} 283251881Speter 284251881Speter 285251881Speterstatic svn_error_t * 286251881Speteropen_root(void *edit_baton, 287251881Speter svn_revnum_t base_revision, 288251881Speter apr_pool_t *pool, 289251881Speter void **root_baton) 290251881Speter{ 291251881Speter struct edit_baton *eb = edit_baton; 292251881Speter struct node_baton *d = apr_pcalloc(pool, sizeof(*d)); 293251881Speter 294251881Speter d->edit_baton = eb; 295251881Speter d->parent_baton = NULL; 296251881Speter d->node = (eb->node = create_node("", NULL, eb->node_pool)); 297251881Speter d->node->kind = svn_node_dir; 298251881Speter d->node->action = 'R'; 299251881Speter *root_baton = d; 300251881Speter 301251881Speter return SVN_NO_ERROR; 302251881Speter} 303251881Speter 304251881Speter 305251881Speterstatic svn_error_t * 306251881Speteropen_directory(const char *path, 307251881Speter void *parent_baton, 308251881Speter svn_revnum_t base_revision, 309251881Speter apr_pool_t *pool, 310251881Speter void **child_baton) 311251881Speter{ 312251881Speter return add_open_helper(path, 'R', svn_node_dir, parent_baton, 313251881Speter NULL, SVN_INVALID_REVNUM, 314251881Speter pool, child_baton); 315251881Speter} 316251881Speter 317251881Speter 318251881Speterstatic svn_error_t * 319251881Speteradd_directory(const char *path, 320251881Speter void *parent_baton, 321251881Speter const char *copyfrom_path, 322251881Speter svn_revnum_t copyfrom_revision, 323251881Speter apr_pool_t *pool, 324251881Speter void **child_baton) 325251881Speter{ 326251881Speter return add_open_helper(path, 'A', svn_node_dir, parent_baton, 327251881Speter copyfrom_path, copyfrom_revision, 328251881Speter pool, child_baton); 329251881Speter} 330251881Speter 331251881Speter 332251881Speterstatic svn_error_t * 333251881Speteropen_file(const char *path, 334251881Speter void *parent_baton, 335251881Speter svn_revnum_t base_revision, 336251881Speter apr_pool_t *pool, 337251881Speter void **file_baton) 338251881Speter{ 339251881Speter return add_open_helper(path, 'R', svn_node_file, parent_baton, 340251881Speter NULL, SVN_INVALID_REVNUM, 341251881Speter pool, file_baton); 342251881Speter} 343251881Speter 344251881Speter 345251881Speterstatic svn_error_t * 346251881Speteradd_file(const char *path, 347251881Speter void *parent_baton, 348251881Speter const char *copyfrom_path, 349251881Speter svn_revnum_t copyfrom_revision, 350251881Speter apr_pool_t *pool, 351251881Speter void **file_baton) 352251881Speter{ 353251881Speter return add_open_helper(path, 'A', svn_node_file, parent_baton, 354251881Speter copyfrom_path, copyfrom_revision, 355251881Speter pool, file_baton); 356251881Speter} 357251881Speter 358251881Speter 359251881Speterstatic svn_error_t * 360251881Speterapply_textdelta(void *file_baton, 361251881Speter const char *base_checksum, 362251881Speter apr_pool_t *pool, 363251881Speter svn_txdelta_window_handler_t *handler, 364251881Speter void **handler_baton) 365251881Speter{ 366251881Speter struct node_baton *fb = file_baton; 367251881Speter fb->node->text_mod = TRUE; 368251881Speter *handler = svn_delta_noop_window_handler; 369251881Speter *handler_baton = NULL; 370251881Speter return SVN_NO_ERROR; 371251881Speter} 372251881Speter 373251881Speter 374251881Speter 375251881Speterstatic svn_error_t * 376251881Speterchange_node_prop(void *node_baton, 377251881Speter const char *name, 378251881Speter const svn_string_t *value, 379251881Speter apr_pool_t *pool) 380251881Speter{ 381251881Speter struct node_baton *nb = node_baton; 382251881Speter nb->node->prop_mod = TRUE; 383251881Speter return SVN_NO_ERROR; 384251881Speter} 385251881Speter 386251881Speter 387251881Spetersvn_error_t * 388251881Spetersvn_repos_node_editor(const svn_delta_editor_t **editor, 389251881Speter void **edit_baton, 390251881Speter svn_repos_t *repos, 391251881Speter svn_fs_root_t *base_root, 392251881Speter svn_fs_root_t *root, 393251881Speter apr_pool_t *node_pool, 394251881Speter apr_pool_t *pool) 395251881Speter{ 396251881Speter svn_delta_editor_t *my_editor; 397251881Speter struct edit_baton *my_edit_baton; 398251881Speter 399251881Speter /* Set up the editor. */ 400251881Speter my_editor = svn_delta_default_editor(pool); 401251881Speter my_editor->open_root = open_root; 402251881Speter my_editor->delete_entry = delete_entry; 403251881Speter my_editor->add_directory = add_directory; 404251881Speter my_editor->open_directory = open_directory; 405251881Speter my_editor->add_file = add_file; 406251881Speter my_editor->open_file = open_file; 407251881Speter my_editor->apply_textdelta = apply_textdelta; 408251881Speter my_editor->change_file_prop = change_node_prop; 409251881Speter my_editor->change_dir_prop = change_node_prop; 410251881Speter 411251881Speter /* Set up the edit baton. */ 412251881Speter my_edit_baton = apr_pcalloc(pool, sizeof(*my_edit_baton)); 413251881Speter my_edit_baton->node_pool = node_pool; 414251881Speter my_edit_baton->fs = repos->fs; 415251881Speter my_edit_baton->root = root; 416251881Speter my_edit_baton->base_root = base_root; 417251881Speter 418251881Speter *editor = my_editor; 419251881Speter *edit_baton = my_edit_baton; 420251881Speter 421251881Speter return SVN_NO_ERROR; 422251881Speter} 423251881Speter 424251881Speter 425251881Speter 426251881Spetersvn_repos_node_t * 427251881Spetersvn_repos_node_from_baton(void *edit_baton) 428251881Speter{ 429251881Speter struct edit_baton *eb = edit_baton; 430251881Speter return eb->node; 431251881Speter} 432