1/* 2 * node.c: routines for getting information about nodes in the working copy. 3 * 4 * ==================================================================== 5 * Licensed to the Apache Software Foundation (ASF) under one 6 * or more contributor license agreements. See the NOTICE file 7 * distributed with this work for additional information 8 * regarding copyright ownership. The ASF licenses this file 9 * to you under the Apache License, Version 2.0 (the 10 * "License"); you may not use this file except in compliance 11 * with the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, 16 * software distributed under the License is distributed on an 17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 * KIND, either express or implied. See the License for the 19 * specific language governing permissions and limitations 20 * under the License. 21 * ==================================================================== 22 */ 23 24/* A note about these functions: 25 26 We aren't really sure yet which bits of data libsvn_client needs about 27 nodes. In wc-1, we just grab the entry, and then use whatever we want 28 from it. Such a pattern is Bad. 29 30 This file is intended to hold functions which retrieve specific bits of 31 information about a node, and will hopefully give us a better idea about 32 what data libsvn_client needs, and how to best provide that data in 1.7 33 final. As such, these functions should only be called from outside 34 libsvn_wc; any internal callers are encouraged to use the appropriate 35 information fetching function, such as svn_wc__db_read_info(). 36*/ 37 38#include <apr_pools.h> 39#include <apr_time.h> 40 41#include "svn_pools.h" 42#include "svn_dirent_uri.h" 43#include "svn_path.h" 44#include "svn_hash.h" 45#include "svn_types.h" 46 47#include "wc.h" 48#include "props.h" 49#include "entries.h" 50#include "wc_db.h" 51 52#include "svn_private_config.h" 53#include "private/svn_wc_private.h" 54 55 56/* Set *CHILDREN_ABSPATHS to a new array of the full paths formed by joining 57 * each name in REL_CHILDREN onto DIR_ABSPATH. 58 * 59 * Allocate the output array and its elements in RESULT_POOL. */ 60static void 61make_absolute(const apr_array_header_t **children_abspaths, 62 const char *dir_abspath, 63 const apr_array_header_t *rel_children, 64 apr_pool_t *result_pool) 65{ 66 apr_array_header_t *children; 67 int i; 68 69 children = apr_array_make(result_pool, rel_children->nelts, 70 sizeof(const char *)); 71 for (i = 0; i < rel_children->nelts; i++) 72 { 73 const char *name = APR_ARRAY_IDX(rel_children, i, const char *); 74 APR_ARRAY_PUSH(children, const char *) = 75 svn_dirent_join(dir_abspath, name, 76 result_pool); 77 } 78 79 *children_abspaths = children; 80} 81 82 83svn_error_t * 84svn_wc__node_get_children_of_working_node(const apr_array_header_t **children, 85 svn_wc_context_t *wc_ctx, 86 const char *dir_abspath, 87 apr_pool_t *result_pool, 88 apr_pool_t *scratch_pool) 89{ 90 const apr_array_header_t *child_names; 91 92 SVN_ERR(svn_wc__db_read_children_of_working_node(&child_names, 93 wc_ctx->db, dir_abspath, 94 scratch_pool, scratch_pool)); 95 make_absolute(children, dir_abspath, child_names, result_pool); 96 return SVN_NO_ERROR; 97} 98 99svn_error_t * 100svn_wc__node_get_not_present_children(const apr_array_header_t **children, 101 svn_wc_context_t *wc_ctx, 102 const char *dir_abspath, 103 apr_pool_t *result_pool, 104 apr_pool_t *scratch_pool) 105{ 106 const apr_array_header_t *child_names; 107 108 SVN_ERR(svn_wc__db_base_read_not_present_children( 109 &child_names, 110 wc_ctx->db, dir_abspath, 111 scratch_pool, scratch_pool)); 112 make_absolute(children, dir_abspath, child_names, result_pool); 113 return SVN_NO_ERROR; 114} 115 116 117svn_error_t * 118svn_wc__node_get_repos_info(svn_revnum_t *revision, 119 const char **repos_relpath, 120 const char **repos_root_url, 121 const char **repos_uuid, 122 svn_wc_context_t *wc_ctx, 123 const char *local_abspath, 124 apr_pool_t *result_pool, 125 apr_pool_t *scratch_pool) 126{ 127 return svn_error_trace( 128 svn_wc__db_read_repos_info(revision, 129 repos_relpath, 130 repos_root_url, 131 repos_uuid, 132 wc_ctx->db, local_abspath, 133 result_pool, scratch_pool)); 134} 135 136/* Convert DB_KIND into the appropriate NODE_KIND value. 137 * If SHOW_HIDDEN is TRUE, report the node kind as found in the DB 138 * even if DB_STATUS indicates that the node is hidden. 139 * Else, return svn_node_none for such nodes. 140 * 141 * ### This is a bit ugly. We should consider promoting svn_kind_t 142 * ### to the de-facto node kind type instead of converting between them 143 * ### in non-backwards compat code. 144 * ### See also comments at the definition of svn_kind_t. 145 * 146 * ### In reality, the previous comment is out of date, as there is 147 * ### now only one enumeration for node kinds, and that is 148 * ### svn_node_kind_t (svn_kind_t was merged with that). But it's 149 * ### still ugly. 150 */ 151static svn_error_t * 152convert_db_kind_to_node_kind(svn_node_kind_t *node_kind, 153 svn_node_kind_t db_kind, 154 svn_wc__db_status_t db_status, 155 svn_boolean_t show_hidden) 156{ 157 *node_kind = db_kind; 158 159 /* Make sure hidden nodes return svn_node_none. */ 160 if (! show_hidden) 161 switch (db_status) 162 { 163 case svn_wc__db_status_not_present: 164 case svn_wc__db_status_server_excluded: 165 case svn_wc__db_status_excluded: 166 *node_kind = svn_node_none; 167 168 default: 169 break; 170 } 171 172 return SVN_NO_ERROR; 173} 174 175svn_error_t * 176svn_wc_read_kind2(svn_node_kind_t *kind, 177 svn_wc_context_t *wc_ctx, 178 const char *local_abspath, 179 svn_boolean_t show_deleted, 180 svn_boolean_t show_hidden, 181 apr_pool_t *scratch_pool) 182{ 183 svn_node_kind_t db_kind; 184 185 SVN_ERR(svn_wc__db_read_kind(&db_kind, 186 wc_ctx->db, local_abspath, 187 TRUE, 188 show_deleted, 189 show_hidden, 190 scratch_pool)); 191 192 if (db_kind == svn_node_dir) 193 *kind = svn_node_dir; 194 else if (db_kind == svn_node_file || db_kind == svn_node_symlink) 195 *kind = svn_node_file; 196 else 197 *kind = svn_node_none; 198 199 return SVN_NO_ERROR; 200} 201 202svn_error_t * 203svn_wc__node_get_changed_info(svn_revnum_t *changed_rev, 204 apr_time_t *changed_date, 205 const char **changed_author, 206 svn_wc_context_t *wc_ctx, 207 const char *local_abspath, 208 apr_pool_t *result_pool, 209 apr_pool_t *scratch_pool) 210{ 211 return svn_error_trace( 212 svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, changed_rev, 213 changed_date, changed_author, NULL, NULL, NULL, 214 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 215 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 216 wc_ctx->db, local_abspath, result_pool, 217 scratch_pool)); 218} 219 220svn_error_t * 221svn_wc__node_get_url(const char **url, 222 svn_wc_context_t *wc_ctx, 223 const char *local_abspath, 224 apr_pool_t *result_pool, 225 apr_pool_t *scratch_pool) 226{ 227 const char *repos_root_url; 228 const char *repos_relpath; 229 230 SVN_ERR(svn_wc__db_read_repos_info(NULL, &repos_relpath, &repos_root_url, 231 NULL, 232 wc_ctx->db, local_abspath, 233 scratch_pool, scratch_pool)); 234 235 *url = svn_path_url_add_component2(repos_root_url, repos_relpath, 236 result_pool); 237 238 return SVN_NO_ERROR; 239} 240 241/* A recursive node-walker, helper for svn_wc__internal_walk_children(). 242 * 243 * Call WALK_CALLBACK with WALK_BATON on all children (recursively) of 244 * DIR_ABSPATH in DB, but not on DIR_ABSPATH itself. DIR_ABSPATH must be a 245 * versioned directory. If SHOW_HIDDEN is true, visit hidden nodes, else 246 * ignore them. Restrict the depth of the walk to DEPTH. 247 * 248 * ### Is it possible for a subdirectory to be hidden and known to be a 249 * directory? If so, and if show_hidden is true, this will try to 250 * recurse into it. */ 251static svn_error_t * 252walker_helper(svn_wc__db_t *db, 253 const char *dir_abspath, 254 svn_boolean_t show_hidden, 255 const apr_hash_t *changelist_filter, 256 svn_wc__node_found_func_t walk_callback, 257 void *walk_baton, 258 svn_depth_t depth, 259 svn_cancel_func_t cancel_func, 260 void *cancel_baton, 261 apr_pool_t *scratch_pool) 262{ 263 apr_pool_t *iterpool; 264 const apr_array_header_t *items; 265 int i; 266 267 if (depth == svn_depth_empty) 268 return SVN_NO_ERROR; 269 270 iterpool = svn_pool_create(scratch_pool); 271 272 SVN_ERR(svn_wc__db_read_children_walker_info(&items, db, 273 dir_abspath, scratch_pool, 274 iterpool)); 275 276 for (i = 0; i < items->nelts; i++) 277 { 278 struct svn_wc__db_walker_info_t *wi = 279 APR_ARRAY_IDX(items, i, struct svn_wc__db_walker_info_t *); 280 const char *child_name = wi->name; 281 svn_node_kind_t child_kind = wi->kind; 282 svn_wc__db_status_t child_status = wi->status; 283 const char *child_abspath; 284 285 svn_pool_clear(iterpool); 286 287 /* See if someone wants to cancel this operation. */ 288 if (cancel_func) 289 SVN_ERR(cancel_func(cancel_baton)); 290 291 child_abspath = svn_dirent_join(dir_abspath, child_name, iterpool); 292 293 if (!show_hidden) 294 switch (child_status) 295 { 296 case svn_wc__db_status_not_present: 297 case svn_wc__db_status_server_excluded: 298 case svn_wc__db_status_excluded: 299 continue; 300 default: 301 break; 302 } 303 304 /* Return the child, if appropriate. */ 305 if ( (child_kind == svn_node_file 306 || depth >= svn_depth_immediates) 307 && svn_wc__internal_changelist_match(db, child_abspath, 308 changelist_filter, 309 scratch_pool) ) 310 { 311 svn_node_kind_t kind; 312 313 SVN_ERR(convert_db_kind_to_node_kind(&kind, child_kind, 314 child_status, show_hidden)); 315 /* ### We might want to pass child_status as well because at least 316 * ### one callee is asking for it. 317 * ### But is it OK to use an svn_wc__db type in this API? 318 * ### Not yet, we need to get the node walker 319 * ### libsvn_wc-internal first. -hkw */ 320 SVN_ERR(walk_callback(child_abspath, kind, walk_baton, iterpool)); 321 } 322 323 /* Recurse into this directory, if appropriate. */ 324 if (child_kind == svn_node_dir 325 && depth >= svn_depth_immediates) 326 { 327 svn_depth_t depth_below_here = depth; 328 329 if (depth == svn_depth_immediates) 330 depth_below_here = svn_depth_empty; 331 332 SVN_ERR(walker_helper(db, child_abspath, show_hidden, 333 changelist_filter, 334 walk_callback, walk_baton, 335 depth_below_here, 336 cancel_func, cancel_baton, 337 iterpool)); 338 } 339 } 340 341 svn_pool_destroy(iterpool); 342 343 return SVN_NO_ERROR; 344} 345 346 347svn_error_t * 348svn_wc__internal_walk_children(svn_wc__db_t *db, 349 const char *local_abspath, 350 svn_boolean_t show_hidden, 351 const apr_array_header_t *changelist_filter, 352 svn_wc__node_found_func_t walk_callback, 353 void *walk_baton, 354 svn_depth_t walk_depth, 355 svn_cancel_func_t cancel_func, 356 void *cancel_baton, 357 apr_pool_t *scratch_pool) 358{ 359 svn_node_kind_t db_kind; 360 svn_node_kind_t kind; 361 svn_wc__db_status_t status; 362 apr_hash_t *changelist_hash = NULL; 363 const char *changelist = NULL; 364 365 SVN_ERR_ASSERT(walk_depth >= svn_depth_empty 366 && walk_depth <= svn_depth_infinity); 367 368 if (changelist_filter && changelist_filter->nelts) 369 SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter, 370 scratch_pool)); 371 372 /* Check if the node exists before the first callback */ 373 SVN_ERR(svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, 374 NULL, NULL, NULL, NULL, NULL, NULL, 375 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 376 changelist_hash ? &changelist : NULL, 377 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 378 db, local_abspath, scratch_pool, scratch_pool)); 379 380 SVN_ERR(convert_db_kind_to_node_kind(&kind, db_kind, status, show_hidden)); 381 382 if (!changelist_hash 383 || (changelist && svn_hash_gets(changelist_hash, changelist))) 384 { 385 SVN_ERR(walk_callback(local_abspath, kind, walk_baton, scratch_pool)); 386 } 387 388 if (db_kind == svn_node_file 389 || status == svn_wc__db_status_not_present 390 || status == svn_wc__db_status_excluded 391 || status == svn_wc__db_status_server_excluded) 392 return SVN_NO_ERROR; 393 394 if (db_kind == svn_node_dir) 395 { 396 return svn_error_trace( 397 walker_helper(db, local_abspath, show_hidden, changelist_hash, 398 walk_callback, walk_baton, 399 walk_depth, cancel_func, cancel_baton, scratch_pool)); 400 } 401 402 return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL, 403 _("'%s' has an unrecognized node kind"), 404 svn_dirent_local_style(local_abspath, 405 scratch_pool)); 406} 407 408svn_error_t * 409svn_wc__node_is_not_present(svn_boolean_t *is_not_present, 410 svn_boolean_t *is_excluded, 411 svn_boolean_t *is_server_excluded, 412 svn_wc_context_t *wc_ctx, 413 const char *local_abspath, 414 svn_boolean_t base_only, 415 apr_pool_t *scratch_pool) 416{ 417 svn_wc__db_status_t status; 418 419 if (base_only) 420 { 421 SVN_ERR(svn_wc__db_base_get_info(&status, 422 NULL, NULL, NULL, NULL, NULL, NULL, 423 NULL, NULL, NULL, NULL, NULL, NULL, 424 NULL, NULL, NULL, 425 wc_ctx->db, local_abspath, 426 scratch_pool, scratch_pool)); 427 } 428 else 429 { 430 SVN_ERR(svn_wc__db_read_info(&status, 431 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 432 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 433 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 434 NULL, NULL, NULL, NULL, NULL, 435 wc_ctx->db, local_abspath, 436 scratch_pool, scratch_pool)); 437 } 438 439 if (is_not_present) 440 *is_not_present = (status == svn_wc__db_status_not_present); 441 442 if (is_excluded) 443 *is_excluded = (status == svn_wc__db_status_excluded); 444 445 if (is_server_excluded) 446 *is_server_excluded = (status == svn_wc__db_status_server_excluded); 447 448 return SVN_NO_ERROR; 449} 450 451svn_error_t * 452svn_wc__node_is_added(svn_boolean_t *is_added, 453 svn_wc_context_t *wc_ctx, 454 const char *local_abspath, 455 apr_pool_t *scratch_pool) 456{ 457 svn_wc__db_status_t status; 458 459 SVN_ERR(svn_wc__db_read_info(&status, 460 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 461 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 462 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 463 NULL, NULL, NULL, NULL, NULL, 464 wc_ctx->db, local_abspath, 465 scratch_pool, scratch_pool)); 466 *is_added = (status == svn_wc__db_status_added); 467 468 return SVN_NO_ERROR; 469} 470 471svn_error_t * 472svn_wc__node_has_working(svn_boolean_t *has_working, 473 svn_wc_context_t *wc_ctx, 474 const char *local_abspath, 475 apr_pool_t *scratch_pool) 476{ 477 svn_wc__db_status_t status; 478 479 SVN_ERR(svn_wc__db_read_info(&status, 480 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 481 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 482 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 483 NULL, NULL, NULL, NULL, has_working, 484 wc_ctx->db, local_abspath, 485 scratch_pool, scratch_pool)); 486 487 return SVN_NO_ERROR; 488} 489 490 491svn_error_t * 492svn_wc__node_get_base(svn_node_kind_t *kind, 493 svn_revnum_t *revision, 494 const char **repos_relpath, 495 const char **repos_root_url, 496 const char **repos_uuid, 497 const char **lock_token, 498 svn_wc_context_t *wc_ctx, 499 const char *local_abspath, 500 svn_boolean_t ignore_enoent, 501 apr_pool_t *result_pool, 502 apr_pool_t *scratch_pool) 503{ 504 svn_error_t *err; 505 svn_wc__db_status_t status; 506 svn_wc__db_lock_t *lock; 507 svn_node_kind_t db_kind; 508 509 err = svn_wc__db_base_get_info(&status, &db_kind, revision, repos_relpath, 510 repos_root_url, repos_uuid, NULL, 511 NULL, NULL, NULL, NULL, NULL, 512 lock_token ? &lock : NULL, 513 NULL, NULL, NULL, 514 wc_ctx->db, local_abspath, 515 result_pool, scratch_pool); 516 517 if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND) 518 return svn_error_trace(err); 519 else if (err 520 || (status != svn_wc__db_status_normal 521 && status != svn_wc__db_status_incomplete)) 522 { 523 if (!ignore_enoent) 524 { 525 if (err) 526 return svn_error_trace(err); 527 else 528 return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, 529 _("The node '%s' was not found."), 530 svn_dirent_local_style(local_abspath, 531 scratch_pool)); 532 } 533 svn_error_clear(err); 534 535 if (kind) 536 *kind = svn_node_unknown; 537 if (revision) 538 *revision = SVN_INVALID_REVNUM; 539 if (repos_relpath) 540 *repos_relpath = NULL; 541 if (repos_root_url) 542 *repos_root_url = NULL; 543 if (repos_uuid) 544 *repos_uuid = NULL; 545 if (lock_token) 546 *lock_token = NULL; 547 return SVN_NO_ERROR; 548 } 549 550 if (kind) 551 *kind = db_kind; 552 if (lock_token) 553 *lock_token = lock ? lock->token : NULL; 554 555 SVN_ERR_ASSERT(!revision || SVN_IS_VALID_REVNUM(*revision)); 556 SVN_ERR_ASSERT(!repos_relpath || *repos_relpath); 557 SVN_ERR_ASSERT(!repos_root_url || *repos_root_url); 558 SVN_ERR_ASSERT(!repos_uuid || *repos_uuid); 559 return SVN_NO_ERROR; 560} 561 562svn_error_t * 563svn_wc__node_get_pre_ng_status_data(svn_revnum_t *revision, 564 svn_revnum_t *changed_rev, 565 apr_time_t *changed_date, 566 const char **changed_author, 567 svn_wc_context_t *wc_ctx, 568 const char *local_abspath, 569 apr_pool_t *result_pool, 570 apr_pool_t *scratch_pool) 571{ 572 svn_wc__db_status_t status; 573 svn_boolean_t have_base, have_more_work, have_work; 574 575 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL, NULL, NULL, 576 changed_rev, changed_date, changed_author, 577 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 578 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 579 &have_base, &have_more_work, &have_work, 580 wc_ctx->db, local_abspath, 581 result_pool, scratch_pool)); 582 583 if (!have_work 584 || ((!changed_rev || SVN_IS_VALID_REVNUM(*changed_rev)) 585 && (!revision || SVN_IS_VALID_REVNUM(*revision))) 586 || ((status != svn_wc__db_status_added) 587 && (status != svn_wc__db_status_deleted))) 588 { 589 return SVN_NO_ERROR; /* We got everything we need */ 590 } 591 592 if (have_base && !have_more_work) 593 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL, 594 changed_rev, changed_date, changed_author, 595 NULL, NULL, NULL, 596 NULL, NULL, NULL, NULL, 597 wc_ctx->db, local_abspath, 598 result_pool, scratch_pool)); 599 else if (status == svn_wc__db_status_deleted) 600 /* Check the information below a WORKING delete */ 601 SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, changed_rev, 602 changed_date, changed_author, NULL, 603 NULL, NULL, NULL, NULL, 604 wc_ctx->db, local_abspath, 605 result_pool, scratch_pool)); 606 607 return SVN_NO_ERROR; 608} 609 610svn_error_t * 611svn_wc__node_clear_dav_cache_recursive(svn_wc_context_t *wc_ctx, 612 const char *local_abspath, 613 apr_pool_t *scratch_pool) 614{ 615 return svn_error_trace(svn_wc__db_base_clear_dav_cache_recursive( 616 wc_ctx->db, local_abspath, scratch_pool)); 617} 618 619 620svn_error_t * 621svn_wc__node_get_lock_tokens_recursive(apr_hash_t **lock_tokens, 622 svn_wc_context_t *wc_ctx, 623 const char *local_abspath, 624 apr_pool_t *result_pool, 625 apr_pool_t *scratch_pool) 626{ 627 return svn_error_trace(svn_wc__db_base_get_lock_tokens_recursive( 628 lock_tokens, wc_ctx->db, local_abspath, 629 result_pool, scratch_pool)); 630} 631 632svn_error_t * 633svn_wc__get_excluded_subtrees(apr_hash_t **server_excluded_subtrees, 634 svn_wc_context_t *wc_ctx, 635 const char *local_abspath, 636 apr_pool_t *result_pool, 637 apr_pool_t *scratch_pool) 638{ 639 return svn_error_trace( 640 svn_wc__db_get_excluded_subtrees(server_excluded_subtrees, 641 wc_ctx->db, 642 local_abspath, 643 result_pool, 644 scratch_pool)); 645} 646 647svn_error_t * 648svn_wc__internal_get_origin(svn_boolean_t *is_copy, 649 svn_revnum_t *revision, 650 const char **repos_relpath, 651 const char **repos_root_url, 652 const char **repos_uuid, 653 svn_depth_t *depth, 654 const char **copy_root_abspath, 655 svn_wc__db_t *db, 656 const char *local_abspath, 657 svn_boolean_t scan_deleted, 658 apr_pool_t *result_pool, 659 apr_pool_t *scratch_pool) 660{ 661 const char *original_repos_relpath; 662 const char *original_repos_root_url; 663 const char *original_repos_uuid; 664 svn_revnum_t original_revision; 665 svn_wc__db_status_t status; 666 svn_boolean_t have_more_work; 667 svn_boolean_t op_root; 668 669 const char *tmp_repos_relpath; 670 671 if (copy_root_abspath) 672 *copy_root_abspath = NULL; 673 if (!repos_relpath) 674 repos_relpath = &tmp_repos_relpath; 675 676 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath, 677 repos_root_url, repos_uuid, NULL, NULL, NULL, 678 depth, NULL, NULL, 679 &original_repos_relpath, 680 &original_repos_root_url, 681 &original_repos_uuid, &original_revision, 682 NULL, NULL, NULL, NULL, NULL, &op_root, NULL, 683 NULL, NULL, &have_more_work, is_copy, 684 db, local_abspath, result_pool, scratch_pool)); 685 686 if (*repos_relpath) 687 { 688 return SVN_NO_ERROR; /* Returned BASE information */ 689 } 690 691 if (status == svn_wc__db_status_deleted && !scan_deleted) 692 { 693 if (is_copy) 694 *is_copy = FALSE; /* Deletes are stored in working; default to FALSE */ 695 696 return SVN_NO_ERROR; /* No info */ 697 } 698 699 if (original_repos_relpath) 700 { 701 /* We an have a copy */ 702 *repos_relpath = original_repos_relpath; 703 if (revision) 704 *revision = original_revision; 705 if (repos_root_url) 706 *repos_root_url = original_repos_root_url; 707 if (repos_uuid) 708 *repos_uuid = original_repos_uuid; 709 710 if (copy_root_abspath == NULL) 711 return SVN_NO_ERROR; 712 else if (op_root) 713 { 714 *copy_root_abspath = apr_pstrdup(result_pool, local_abspath); 715 return SVN_NO_ERROR; 716 } 717 } 718 719 { 720 svn_boolean_t scan_working = FALSE; 721 722 if (status == svn_wc__db_status_added 723 || (status == svn_wc__db_status_deleted && have_more_work)) 724 scan_working = TRUE; 725 726 if (scan_working) 727 { 728 const char *op_root_abspath; 729 730 SVN_ERR(svn_wc__db_scan_addition(&status, &op_root_abspath, NULL, 731 NULL, NULL, &original_repos_relpath, 732 repos_root_url, 733 repos_uuid, revision, 734 db, local_abspath, 735 result_pool, scratch_pool)); 736 737 if (status == svn_wc__db_status_added) 738 { 739 if (is_copy) 740 *is_copy = FALSE; 741 return SVN_NO_ERROR; /* Local addition */ 742 } 743 744 /* We don't know how the following error condition can be fulfilled 745 * but we have seen that happening in the wild. Better to create 746 * an error than a SEGFAULT. */ 747 if (status == svn_wc__db_status_incomplete && !original_repos_relpath) 748 return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, 749 _("Incomplete copy information on path '%s'."), 750 svn_dirent_local_style(local_abspath, 751 scratch_pool)); 752 753 *repos_relpath = svn_relpath_join( 754 original_repos_relpath, 755 svn_dirent_skip_ancestor(op_root_abspath, 756 local_abspath), 757 result_pool); 758 if (copy_root_abspath) 759 *copy_root_abspath = op_root_abspath; 760 } 761 else /* Deleted, excluded, not-present, server-excluded, ... */ 762 { 763 if (is_copy) 764 *is_copy = FALSE; 765 766 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, repos_relpath, 767 repos_root_url, repos_uuid, NULL, 768 NULL, NULL, NULL, NULL, NULL, NULL, 769 NULL, NULL, NULL, 770 db, local_abspath, 771 result_pool, scratch_pool)); 772 } 773 774 return SVN_NO_ERROR; 775 } 776} 777 778svn_error_t * 779svn_wc__node_get_origin(svn_boolean_t *is_copy, 780 svn_revnum_t *revision, 781 const char **repos_relpath, 782 const char **repos_root_url, 783 const char **repos_uuid, 784 svn_depth_t *depth, 785 const char **copy_root_abspath, 786 svn_wc_context_t *wc_ctx, 787 const char *local_abspath, 788 svn_boolean_t scan_deleted, 789 apr_pool_t *result_pool, 790 apr_pool_t *scratch_pool) 791{ 792 return svn_error_trace(svn_wc__internal_get_origin(is_copy, revision, 793 repos_relpath, repos_root_url, repos_uuid, 794 depth, copy_root_abspath, 795 wc_ctx->db, local_abspath, scan_deleted, 796 result_pool, scratch_pool)); 797} 798 799svn_error_t * 800svn_wc__node_get_commit_status(svn_boolean_t *added, 801 svn_boolean_t *deleted, 802 svn_boolean_t *is_replace_root, 803 svn_boolean_t *is_op_root, 804 svn_revnum_t *revision, 805 svn_revnum_t *original_revision, 806 const char **original_repos_relpath, 807 svn_wc_context_t *wc_ctx, 808 const char *local_abspath, 809 apr_pool_t *result_pool, 810 apr_pool_t *scratch_pool) 811{ 812 svn_wc__db_status_t status; 813 svn_boolean_t have_base; 814 svn_boolean_t have_more_work; 815 svn_boolean_t op_root; 816 817 /* ### All of this should be handled inside a single read transaction */ 818 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL, 819 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 820 original_repos_relpath, NULL, NULL, 821 original_revision, NULL, NULL, NULL, 822 NULL, NULL, 823 &op_root, NULL, NULL, 824 &have_base, &have_more_work, NULL, 825 wc_ctx->db, local_abspath, 826 result_pool, scratch_pool)); 827 828 if (added) 829 *added = (status == svn_wc__db_status_added); 830 if (deleted) 831 *deleted = (status == svn_wc__db_status_deleted); 832 if (is_op_root) 833 *is_op_root = op_root; 834 835 if (is_replace_root) 836 { 837 if (status == svn_wc__db_status_added 838 && op_root 839 && (have_base || have_more_work)) 840 SVN_ERR(svn_wc__db_node_check_replace(is_replace_root, NULL, NULL, 841 wc_ctx->db, local_abspath, 842 scratch_pool)); 843 else 844 *is_replace_root = FALSE; 845 } 846 847 /* Retrieve some information from BASE which is needed for replacing 848 and/or deleting BASE nodes. */ 849 if (have_base 850 && !have_more_work 851 && op_root 852 && (revision && !SVN_IS_VALID_REVNUM(*revision))) 853 { 854 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL, 855 NULL, NULL, NULL, NULL, NULL, NULL, 856 NULL, NULL, NULL, NULL, 857 wc_ctx->db, local_abspath, 858 scratch_pool, scratch_pool)); 859 } 860 861 return SVN_NO_ERROR; 862} 863 864svn_error_t * 865svn_wc__node_get_md5_from_sha1(const svn_checksum_t **md5_checksum, 866 svn_wc_context_t *wc_ctx, 867 const char *wri_abspath, 868 const svn_checksum_t *sha1_checksum, 869 apr_pool_t *result_pool, 870 apr_pool_t *scratch_pool) 871{ 872 return svn_error_trace(svn_wc__db_pristine_get_md5(md5_checksum, 873 wc_ctx->db, 874 wri_abspath, 875 sha1_checksum, 876 result_pool, 877 scratch_pool)); 878} 879 880svn_error_t * 881svn_wc__get_not_present_descendants(const apr_array_header_t **descendants, 882 svn_wc_context_t *wc_ctx, 883 const char *local_abspath, 884 apr_pool_t *result_pool, 885 apr_pool_t *scratch_pool) 886{ 887 return svn_error_trace( 888 svn_wc__db_get_not_present_descendants(descendants, 889 wc_ctx->db, 890 local_abspath, 891 result_pool, 892 scratch_pool)); 893} 894 895svn_error_t * 896svn_wc__rename_wc(svn_wc_context_t *wc_ctx, 897 const char *from_abspath, 898 const char *dst_abspath, 899 apr_pool_t *scratch_pool) 900{ 901 const char *wcroot_abspath; 902 SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, wc_ctx->db, from_abspath, 903 scratch_pool, scratch_pool)); 904 905 if (! strcmp(from_abspath, wcroot_abspath)) 906 { 907 SVN_ERR(svn_wc__db_drop_root(wc_ctx->db, wcroot_abspath, scratch_pool)); 908 909 SVN_ERR(svn_io_file_rename2(from_abspath, dst_abspath, FALSE, 910 scratch_pool)); 911 } 912 else 913 return svn_error_createf( 914 SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, 915 _("'%s' is not the root of the working copy '%s'"), 916 svn_dirent_local_style(from_abspath, scratch_pool), 917 svn_dirent_local_style(wcroot_abspath, scratch_pool)); 918 919 return SVN_NO_ERROR; 920} 921 922svn_error_t * 923svn_wc__check_for_obstructions(svn_wc_notify_state_t *obstruction_state, 924 svn_node_kind_t *kind, 925 svn_boolean_t *deleted, 926 svn_boolean_t *excluded, 927 svn_depth_t *parent_depth, 928 svn_wc_context_t *wc_ctx, 929 const char *local_abspath, 930 svn_boolean_t no_wcroot_check, 931 apr_pool_t *scratch_pool) 932{ 933 svn_wc__db_status_t status; 934 svn_node_kind_t db_kind; 935 svn_node_kind_t disk_kind; 936 svn_error_t *err; 937 938 *obstruction_state = svn_wc_notify_state_inapplicable; 939 if (kind) 940 *kind = svn_node_none; 941 if (deleted) 942 *deleted = FALSE; 943 if (excluded) 944 *excluded = FALSE; 945 if (parent_depth) 946 *parent_depth = svn_depth_unknown; 947 948 SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, scratch_pool)); 949 950 err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, NULL, 951 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 952 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 953 NULL, NULL, NULL, NULL, NULL, 954 wc_ctx->db, local_abspath, 955 scratch_pool, scratch_pool); 956 957 if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) 958 { 959 svn_error_clear(err); 960 961 if (disk_kind != svn_node_none) 962 { 963 /* Nothing in the DB, but something on disk */ 964 *obstruction_state = svn_wc_notify_state_obstructed; 965 return SVN_NO_ERROR; 966 } 967 968 err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, 969 NULL, NULL, NULL, parent_depth, NULL, NULL, 970 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 971 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 972 NULL, 973 wc_ctx->db, svn_dirent_dirname(local_abspath, 974 scratch_pool), 975 scratch_pool, scratch_pool); 976 977 if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) 978 { 979 svn_error_clear(err); 980 /* No versioned parent; we can't add a node here */ 981 *obstruction_state = svn_wc_notify_state_obstructed; 982 return SVN_NO_ERROR; 983 } 984 else 985 SVN_ERR(err); 986 987 if (db_kind != svn_node_dir 988 || (status != svn_wc__db_status_normal 989 && status != svn_wc__db_status_added)) 990 { 991 /* The parent doesn't allow nodes to be added below it */ 992 *obstruction_state = svn_wc_notify_state_obstructed; 993 } 994 995 return SVN_NO_ERROR; 996 } 997 else 998 SVN_ERR(err); 999 1000 /* Check for obstructing working copies */ 1001 if (!no_wcroot_check 1002 && db_kind == svn_node_dir 1003 && status == svn_wc__db_status_normal) 1004 { 1005 svn_boolean_t is_root; 1006 SVN_ERR(svn_wc__db_is_wcroot(&is_root, wc_ctx->db, local_abspath, 1007 scratch_pool)); 1008 1009 if (is_root) 1010 { 1011 /* Callers should handle this as unversioned */ 1012 *obstruction_state = svn_wc_notify_state_obstructed; 1013 return SVN_NO_ERROR; 1014 } 1015 } 1016 1017 if (kind) 1018 SVN_ERR(convert_db_kind_to_node_kind(kind, db_kind, status, FALSE)); 1019 1020 switch (status) 1021 { 1022 case svn_wc__db_status_deleted: 1023 if (deleted) 1024 *deleted = TRUE; 1025 /* Fall through to svn_wc__db_status_not_present */ 1026 case svn_wc__db_status_not_present: 1027 if (disk_kind != svn_node_none) 1028 *obstruction_state = svn_wc_notify_state_obstructed; 1029 break; 1030 1031 case svn_wc__db_status_excluded: 1032 case svn_wc__db_status_server_excluded: 1033 if (excluded) 1034 *excluded = TRUE; 1035 /* fall through */ 1036 case svn_wc__db_status_incomplete: 1037 *obstruction_state = svn_wc_notify_state_missing; 1038 break; 1039 1040 case svn_wc__db_status_added: 1041 case svn_wc__db_status_normal: 1042 if (disk_kind == svn_node_none) 1043 *obstruction_state = svn_wc_notify_state_missing; 1044 else 1045 { 1046 svn_node_kind_t expected_kind; 1047 1048 SVN_ERR(convert_db_kind_to_node_kind(&expected_kind, db_kind, 1049 status, FALSE)); 1050 1051 if (disk_kind != expected_kind) 1052 *obstruction_state = svn_wc_notify_state_obstructed; 1053 } 1054 break; 1055 default: 1056 SVN_ERR_MALFUNCTION(); 1057 } 1058 1059 return SVN_NO_ERROR; 1060} 1061 1062 1063svn_error_t * 1064svn_wc__node_was_moved_away(const char **moved_to_abspath, 1065 const char **op_root_abspath, 1066 svn_wc_context_t *wc_ctx, 1067 const char *local_abspath, 1068 apr_pool_t *result_pool, 1069 apr_pool_t *scratch_pool) 1070{ 1071 svn_wc__db_status_t status; 1072 1073 if (moved_to_abspath) 1074 *moved_to_abspath = NULL; 1075 if (op_root_abspath) 1076 *op_root_abspath = NULL; 1077 1078 SVN_ERR(svn_wc__db_read_info(&status, 1079 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1080 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1081 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1082 NULL, NULL, NULL, NULL, NULL, 1083 wc_ctx->db, local_abspath, 1084 scratch_pool, scratch_pool)); 1085 1086 if (status == svn_wc__db_status_deleted) 1087 SVN_ERR(svn_wc__db_scan_deletion(NULL, moved_to_abspath, NULL, 1088 op_root_abspath, wc_ctx->db, 1089 local_abspath, 1090 result_pool, scratch_pool)); 1091 1092 return SVN_NO_ERROR; 1093} 1094 1095 1096svn_error_t * 1097svn_wc__node_was_moved_here(const char **moved_from_abspath, 1098 const char **delete_op_root_abspath, 1099 svn_wc_context_t *wc_ctx, 1100 const char *local_abspath, 1101 apr_pool_t *result_pool, 1102 apr_pool_t *scratch_pool) 1103{ 1104 svn_error_t *err; 1105 1106 if (moved_from_abspath) 1107 *moved_from_abspath = NULL; 1108 if (delete_op_root_abspath) 1109 *delete_op_root_abspath = NULL; 1110 1111 err = svn_wc__db_scan_moved(moved_from_abspath, NULL, NULL, 1112 delete_op_root_abspath, 1113 wc_ctx->db, local_abspath, 1114 result_pool, scratch_pool); 1115 1116 if (err) 1117 { 1118 /* Return error for not added nodes */ 1119 if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS) 1120 return svn_error_trace(err); 1121 1122 /* Path not moved here */ 1123 svn_error_clear(err); 1124 return SVN_NO_ERROR; 1125 } 1126 1127 return SVN_NO_ERROR; 1128} 1129 1130svn_error_t * 1131svn_wc__find_working_nodes_with_basename(apr_array_header_t **abspaths, 1132 const char *wri_abspath, 1133 const char *basename, 1134 svn_node_kind_t kind, 1135 svn_wc_context_t *wc_ctx, 1136 apr_pool_t *result_pool, 1137 apr_pool_t *scratch_pool) 1138{ 1139 return svn_error_trace(svn_wc__db_find_working_nodes_with_basename( 1140 abspaths, wc_ctx->db, wri_abspath, basename, kind, 1141 result_pool, scratch_pool)); 1142} 1143 1144svn_error_t * 1145svn_wc__find_copies_of_repos_path(apr_array_header_t **abspaths, 1146 const char *wri_abspath, 1147 const char *repos_relpath, 1148 svn_node_kind_t kind, 1149 svn_wc_context_t *wc_ctx, 1150 apr_pool_t *result_pool, 1151 apr_pool_t *scratch_pool) 1152{ 1153 return svn_error_trace(svn_wc__db_find_copies_of_repos_path( 1154 abspaths, wc_ctx->db, wri_abspath, repos_relpath, 1155 kind, result_pool, scratch_pool)); 1156} 1157