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. If SHOW_HIDDEN is false then 58 * omit any paths that are reported as 'hidden' by svn_wc__db_node_hidden(). 59 * 60 * Allocate the output array and its elements in RESULT_POOL. */ 61static svn_error_t * 62filter_and_make_absolute(const apr_array_header_t **children_abspaths, 63 svn_wc_context_t *wc_ctx, 64 const char *dir_abspath, 65 const apr_array_header_t *rel_children, 66 svn_boolean_t show_hidden, 67 apr_pool_t *result_pool, 68 apr_pool_t *scratch_pool) 69{ 70 apr_array_header_t *children; 71 int i; 72 73 children = apr_array_make(result_pool, rel_children->nelts, 74 sizeof(const char *)); 75 for (i = 0; i < rel_children->nelts; i++) 76 { 77 const char *child_abspath = svn_dirent_join(dir_abspath, 78 APR_ARRAY_IDX(rel_children, 79 i, 80 const char *), 81 result_pool); 82 83 /* Don't add hidden nodes to *CHILDREN if we don't want them. */ 84 if (!show_hidden) 85 { 86 svn_boolean_t child_is_hidden; 87 88 SVN_ERR(svn_wc__db_node_hidden(&child_is_hidden, wc_ctx->db, 89 child_abspath, scratch_pool)); 90 if (child_is_hidden) 91 continue; 92 } 93 94 APR_ARRAY_PUSH(children, const char *) = child_abspath; 95 } 96 97 *children_abspaths = children; 98 99 return SVN_NO_ERROR; 100} 101 102 103svn_error_t * 104svn_wc__node_get_children_of_working_node(const apr_array_header_t **children, 105 svn_wc_context_t *wc_ctx, 106 const char *dir_abspath, 107 svn_boolean_t show_hidden, 108 apr_pool_t *result_pool, 109 apr_pool_t *scratch_pool) 110{ 111 const apr_array_header_t *rel_children; 112 113 SVN_ERR(svn_wc__db_read_children_of_working_node(&rel_children, 114 wc_ctx->db, dir_abspath, 115 scratch_pool, scratch_pool)); 116 SVN_ERR(filter_and_make_absolute(children, wc_ctx, dir_abspath, 117 rel_children, show_hidden, 118 result_pool, scratch_pool)); 119 return SVN_NO_ERROR; 120} 121 122svn_error_t * 123svn_wc__node_get_children(const apr_array_header_t **children, 124 svn_wc_context_t *wc_ctx, 125 const char *dir_abspath, 126 svn_boolean_t show_hidden, 127 apr_pool_t *result_pool, 128 apr_pool_t *scratch_pool) 129{ 130 const apr_array_header_t *rel_children; 131 132 SVN_ERR(svn_wc__db_read_children(&rel_children, wc_ctx->db, dir_abspath, 133 scratch_pool, scratch_pool)); 134 SVN_ERR(filter_and_make_absolute(children, wc_ctx, dir_abspath, 135 rel_children, show_hidden, 136 result_pool, scratch_pool)); 137 return SVN_NO_ERROR; 138} 139 140 141svn_error_t * 142svn_wc__internal_get_repos_info(svn_revnum_t *revision, 143 const char **repos_relpath, 144 const char **repos_root_url, 145 const char **repos_uuid, 146 svn_wc__db_t *db, 147 const char *local_abspath, 148 apr_pool_t *result_pool, 149 apr_pool_t *scratch_pool) 150{ 151 svn_wc__db_status_t status; 152 svn_boolean_t have_work; 153 154 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath, 155 repos_root_url, repos_uuid, 156 NULL, NULL, NULL, NULL, NULL, NULL, 157 NULL, NULL, NULL, NULL, NULL, NULL, 158 NULL, NULL, NULL, NULL, NULL, NULL, 159 NULL, NULL, &have_work, 160 db, local_abspath, 161 result_pool, scratch_pool)); 162 163 if ((repos_relpath ? *repos_relpath != NULL : TRUE) 164 && (repos_root_url ? *repos_root_url != NULL: TRUE) 165 && (repos_uuid ? *repos_uuid != NULL : TRUE)) 166 return SVN_NO_ERROR; /* We got the requested information */ 167 168 if (!have_work) /* not-present, (server-)excluded? */ 169 { 170 return SVN_NO_ERROR; /* Can't fetch more */ 171 } 172 173 if (status == svn_wc__db_status_deleted) 174 { 175 const char *base_del_abspath, *wrk_del_abspath; 176 177 SVN_ERR(svn_wc__db_scan_deletion(&base_del_abspath, NULL, 178 &wrk_del_abspath, NULL, 179 db, local_abspath, 180 scratch_pool, scratch_pool)); 181 182 if (base_del_abspath) 183 { 184 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, repos_relpath, 185 repos_root_url, repos_uuid, NULL, 186 NULL, NULL, NULL, NULL, NULL, NULL, 187 NULL, NULL, NULL, 188 db, base_del_abspath, 189 result_pool, scratch_pool)); 190 191 /* If we have a repos_relpath, it is of the op-root */ 192 if (repos_relpath) 193 *repos_relpath = svn_relpath_join(*repos_relpath, 194 svn_dirent_skip_ancestor(base_del_abspath, 195 local_abspath), 196 result_pool); 197 /* We keep revision as SVN_INVALID_REVNUM */ 198 } 199 else if (wrk_del_abspath) 200 { 201 const char *op_root_abspath = NULL; 202 203 SVN_ERR(svn_wc__db_scan_addition(NULL, repos_relpath 204 ? &op_root_abspath : NULL, 205 repos_relpath, repos_root_url, 206 repos_uuid, NULL, NULL, NULL, NULL, 207 db, svn_dirent_dirname( 208 wrk_del_abspath, 209 scratch_pool), 210 result_pool, scratch_pool)); 211 212 /* If we have a repos_relpath, it is of the op-root */ 213 if (repos_relpath) 214 *repos_relpath = svn_relpath_join( 215 *repos_relpath, 216 svn_dirent_skip_ancestor(op_root_abspath, 217 local_abspath), 218 result_pool); 219 } 220 } 221 else /* added, or WORKING incomplete */ 222 { 223 const char *op_root_abspath = NULL; 224 225 /* We have an addition. scan_addition() will find the intended 226 repository location by scanning up the tree. */ 227 SVN_ERR(svn_wc__db_scan_addition(NULL, repos_relpath 228 ? &op_root_abspath : NULL, 229 repos_relpath, repos_root_url, 230 repos_uuid, NULL, NULL, NULL, NULL, 231 db, local_abspath, 232 result_pool, scratch_pool)); 233 } 234 235 SVN_ERR_ASSERT(repos_root_url == NULL || *repos_root_url != NULL); 236 SVN_ERR_ASSERT(repos_uuid == NULL || *repos_uuid != NULL); 237 return SVN_NO_ERROR; 238} 239 240svn_error_t * 241svn_wc__node_get_repos_info(svn_revnum_t *revision, 242 const char **repos_relpath, 243 const char **repos_root_url, 244 const char **repos_uuid, 245 svn_wc_context_t *wc_ctx, 246 const char *local_abspath, 247 apr_pool_t *result_pool, 248 apr_pool_t *scratch_pool) 249{ 250 return svn_error_trace( 251 svn_wc__internal_get_repos_info(revision, 252 repos_relpath, 253 repos_root_url, 254 repos_uuid, 255 wc_ctx->db, local_abspath, 256 result_pool, scratch_pool)); 257} 258 259/* Convert DB_KIND into the appropriate NODE_KIND value. 260 * If SHOW_HIDDEN is TRUE, report the node kind as found in the DB 261 * even if DB_STATUS indicates that the node is hidden. 262 * Else, return svn_node_none for such nodes. 263 * 264 * ### This is a bit ugly. We should consider promoting svn_kind_t 265 * ### to the de-facto node kind type instead of converting between them 266 * ### in non-backwards compat code. 267 * ### See also comments at the definition of svn_kind_t. 268 * 269 * ### In reality, the previous comment is out of date, as there is 270 * ### now only one enumeration for node kinds, and that is 271 * ### svn_node_kind_t (svn_kind_t was merged with that). But it's 272 * ### still ugly. 273 */ 274static svn_error_t * 275convert_db_kind_to_node_kind(svn_node_kind_t *node_kind, 276 svn_node_kind_t db_kind, 277 svn_wc__db_status_t db_status, 278 svn_boolean_t show_hidden) 279{ 280 *node_kind = db_kind; 281 282 /* Make sure hidden nodes return svn_node_none. */ 283 if (! show_hidden) 284 switch (db_status) 285 { 286 case svn_wc__db_status_not_present: 287 case svn_wc__db_status_server_excluded: 288 case svn_wc__db_status_excluded: 289 *node_kind = svn_node_none; 290 291 default: 292 break; 293 } 294 295 return SVN_NO_ERROR; 296} 297 298svn_error_t * 299svn_wc_read_kind2(svn_node_kind_t *kind, 300 svn_wc_context_t *wc_ctx, 301 const char *local_abspath, 302 svn_boolean_t show_deleted, 303 svn_boolean_t show_hidden, 304 apr_pool_t *scratch_pool) 305{ 306 svn_node_kind_t db_kind; 307 308 SVN_ERR(svn_wc__db_read_kind(&db_kind, 309 wc_ctx->db, local_abspath, 310 TRUE, 311 show_deleted, 312 show_hidden, 313 scratch_pool)); 314 315 if (db_kind == svn_node_dir) 316 *kind = svn_node_dir; 317 else if (db_kind == svn_node_file || db_kind == svn_node_symlink) 318 *kind = svn_node_file; 319 else 320 *kind = svn_node_none; 321 322 return SVN_NO_ERROR; 323} 324 325svn_error_t * 326svn_wc__node_get_depth(svn_depth_t *depth, 327 svn_wc_context_t *wc_ctx, 328 const char *local_abspath, 329 apr_pool_t *scratch_pool) 330{ 331 return svn_error_trace( 332 svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, NULL, 333 NULL, NULL, depth, NULL, NULL, NULL, NULL, 334 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 335 NULL, NULL, NULL, NULL, NULL, NULL, 336 wc_ctx->db, local_abspath, scratch_pool, 337 scratch_pool)); 338} 339 340svn_error_t * 341svn_wc__node_get_changed_info(svn_revnum_t *changed_rev, 342 apr_time_t *changed_date, 343 const char **changed_author, 344 svn_wc_context_t *wc_ctx, 345 const char *local_abspath, 346 apr_pool_t *result_pool, 347 apr_pool_t *scratch_pool) 348{ 349 return svn_error_trace( 350 svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, changed_rev, 351 changed_date, changed_author, NULL, NULL, NULL, 352 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 353 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 354 wc_ctx->db, local_abspath, result_pool, 355 scratch_pool)); 356} 357 358svn_error_t * 359svn_wc__node_get_url(const char **url, 360 svn_wc_context_t *wc_ctx, 361 const char *local_abspath, 362 apr_pool_t *result_pool, 363 apr_pool_t *scratch_pool) 364{ 365 return svn_error_trace(svn_wc__db_read_url(url, wc_ctx->db, local_abspath, 366 result_pool, scratch_pool)); 367} 368 369/* A recursive node-walker, helper for svn_wc__internal_walk_children(). 370 * 371 * Call WALK_CALLBACK with WALK_BATON on all children (recursively) of 372 * DIR_ABSPATH in DB, but not on DIR_ABSPATH itself. DIR_ABSPATH must be a 373 * versioned directory. If SHOW_HIDDEN is true, visit hidden nodes, else 374 * ignore them. Restrict the depth of the walk to DEPTH. 375 * 376 * ### Is it possible for a subdirectory to be hidden and known to be a 377 * directory? If so, and if show_hidden is true, this will try to 378 * recurse into it. */ 379static svn_error_t * 380walker_helper(svn_wc__db_t *db, 381 const char *dir_abspath, 382 svn_boolean_t show_hidden, 383 const apr_hash_t *changelist_filter, 384 svn_wc__node_found_func_t walk_callback, 385 void *walk_baton, 386 svn_depth_t depth, 387 svn_cancel_func_t cancel_func, 388 void *cancel_baton, 389 apr_pool_t *scratch_pool) 390{ 391 apr_hash_t *rel_children_info; 392 apr_hash_index_t *hi; 393 apr_pool_t *iterpool; 394 395 if (depth == svn_depth_empty) 396 return SVN_NO_ERROR; 397 398 SVN_ERR(svn_wc__db_read_children_walker_info(&rel_children_info, db, 399 dir_abspath, scratch_pool, 400 scratch_pool)); 401 402 403 iterpool = svn_pool_create(scratch_pool); 404 for (hi = apr_hash_first(scratch_pool, rel_children_info); 405 hi; 406 hi = apr_hash_next(hi)) 407 { 408 const char *child_name = svn__apr_hash_index_key(hi); 409 struct svn_wc__db_walker_info_t *wi = svn__apr_hash_index_val(hi); 410 svn_node_kind_t child_kind = wi->kind; 411 svn_wc__db_status_t child_status = wi->status; 412 const char *child_abspath; 413 414 svn_pool_clear(iterpool); 415 416 /* See if someone wants to cancel this operation. */ 417 if (cancel_func) 418 SVN_ERR(cancel_func(cancel_baton)); 419 420 child_abspath = svn_dirent_join(dir_abspath, child_name, iterpool); 421 422 if (!show_hidden) 423 switch (child_status) 424 { 425 case svn_wc__db_status_not_present: 426 case svn_wc__db_status_server_excluded: 427 case svn_wc__db_status_excluded: 428 continue; 429 default: 430 break; 431 } 432 433 /* Return the child, if appropriate. */ 434 if ( (child_kind == svn_node_file 435 || depth >= svn_depth_immediates) 436 && svn_wc__internal_changelist_match(db, child_abspath, 437 changelist_filter, 438 scratch_pool) ) 439 { 440 svn_node_kind_t kind; 441 442 SVN_ERR(convert_db_kind_to_node_kind(&kind, child_kind, 443 child_status, show_hidden)); 444 /* ### We might want to pass child_status as well because at least 445 * ### one callee is asking for it. 446 * ### But is it OK to use an svn_wc__db type in this API? 447 * ### Not yet, we need to get the node walker 448 * ### libsvn_wc-internal first. -hkw */ 449 SVN_ERR(walk_callback(child_abspath, kind, walk_baton, iterpool)); 450 } 451 452 /* Recurse into this directory, if appropriate. */ 453 if (child_kind == svn_node_dir 454 && depth >= svn_depth_immediates) 455 { 456 svn_depth_t depth_below_here = depth; 457 458 if (depth == svn_depth_immediates) 459 depth_below_here = svn_depth_empty; 460 461 SVN_ERR(walker_helper(db, child_abspath, show_hidden, 462 changelist_filter, 463 walk_callback, walk_baton, 464 depth_below_here, 465 cancel_func, cancel_baton, 466 iterpool)); 467 } 468 } 469 470 svn_pool_destroy(iterpool); 471 472 return SVN_NO_ERROR; 473} 474 475 476svn_error_t * 477svn_wc__internal_walk_children(svn_wc__db_t *db, 478 const char *local_abspath, 479 svn_boolean_t show_hidden, 480 const apr_array_header_t *changelist_filter, 481 svn_wc__node_found_func_t walk_callback, 482 void *walk_baton, 483 svn_depth_t walk_depth, 484 svn_cancel_func_t cancel_func, 485 void *cancel_baton, 486 apr_pool_t *scratch_pool) 487{ 488 svn_node_kind_t db_kind; 489 svn_node_kind_t kind; 490 svn_wc__db_status_t status; 491 apr_hash_t *changelist_hash = NULL; 492 493 SVN_ERR_ASSERT(walk_depth >= svn_depth_empty 494 && walk_depth <= svn_depth_infinity); 495 496 if (changelist_filter && changelist_filter->nelts) 497 SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter, 498 scratch_pool)); 499 500 /* Check if the node exists before the first callback */ 501 SVN_ERR(svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, 502 NULL, NULL, NULL, NULL, NULL, NULL, 503 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 504 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 505 db, local_abspath, scratch_pool, scratch_pool)); 506 507 SVN_ERR(convert_db_kind_to_node_kind(&kind, db_kind, status, show_hidden)); 508 509 if (svn_wc__internal_changelist_match(db, local_abspath, 510 changelist_hash, scratch_pool)) 511 SVN_ERR(walk_callback(local_abspath, kind, walk_baton, scratch_pool)); 512 513 if (db_kind == svn_node_file 514 || status == svn_wc__db_status_not_present 515 || status == svn_wc__db_status_excluded 516 || status == svn_wc__db_status_server_excluded) 517 return SVN_NO_ERROR; 518 519 if (db_kind == svn_node_dir) 520 { 521 return svn_error_trace( 522 walker_helper(db, local_abspath, show_hidden, changelist_hash, 523 walk_callback, walk_baton, 524 walk_depth, cancel_func, cancel_baton, scratch_pool)); 525 } 526 527 return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL, 528 _("'%s' has an unrecognized node kind"), 529 svn_dirent_local_style(local_abspath, 530 scratch_pool)); 531} 532 533svn_error_t * 534svn_wc__node_is_status_deleted(svn_boolean_t *is_deleted, 535 svn_wc_context_t *wc_ctx, 536 const char *local_abspath, 537 apr_pool_t *scratch_pool) 538{ 539 svn_wc__db_status_t status; 540 541 SVN_ERR(svn_wc__db_read_info(&status, 542 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 543 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 544 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 545 NULL, NULL, NULL, NULL, NULL, 546 wc_ctx->db, local_abspath, 547 scratch_pool, scratch_pool)); 548 549 *is_deleted = (status == svn_wc__db_status_deleted); 550 551 return SVN_NO_ERROR; 552} 553 554svn_error_t * 555svn_wc__node_get_deleted_ancestor(const char **deleted_ancestor_abspath, 556 svn_wc_context_t *wc_ctx, 557 const char *local_abspath, 558 apr_pool_t *result_pool, 559 apr_pool_t *scratch_pool) 560{ 561 svn_wc__db_status_t status; 562 563 *deleted_ancestor_abspath = NULL; 564 565 SVN_ERR(svn_wc__db_read_info(&status, 566 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 567 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 568 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 569 NULL, NULL, NULL, NULL, NULL, 570 wc_ctx->db, local_abspath, 571 scratch_pool, scratch_pool)); 572 573 if (status == svn_wc__db_status_deleted) 574 SVN_ERR(svn_wc__db_scan_deletion(deleted_ancestor_abspath, NULL, NULL, 575 NULL, wc_ctx->db, local_abspath, 576 result_pool, scratch_pool)); 577 578 return SVN_NO_ERROR; 579} 580 581svn_error_t * 582svn_wc__node_is_not_present(svn_boolean_t *is_not_present, 583 svn_boolean_t *is_excluded, 584 svn_boolean_t *is_server_excluded, 585 svn_wc_context_t *wc_ctx, 586 const char *local_abspath, 587 svn_boolean_t base_only, 588 apr_pool_t *scratch_pool) 589{ 590 svn_wc__db_status_t status; 591 592 if (base_only) 593 { 594 SVN_ERR(svn_wc__db_base_get_info(&status, 595 NULL, NULL, NULL, NULL, NULL, NULL, 596 NULL, NULL, NULL, NULL, NULL, NULL, 597 NULL, NULL, NULL, 598 wc_ctx->db, local_abspath, 599 scratch_pool, scratch_pool)); 600 } 601 else 602 { 603 SVN_ERR(svn_wc__db_read_info(&status, 604 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 605 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 606 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 607 NULL, NULL, NULL, NULL, NULL, 608 wc_ctx->db, local_abspath, 609 scratch_pool, scratch_pool)); 610 } 611 612 if (is_not_present) 613 *is_not_present = (status == svn_wc__db_status_not_present); 614 615 if (is_excluded) 616 *is_excluded = (status == svn_wc__db_status_excluded); 617 618 if (is_server_excluded) 619 *is_server_excluded = (status == svn_wc__db_status_server_excluded); 620 621 return SVN_NO_ERROR; 622} 623 624svn_error_t * 625svn_wc__node_is_added(svn_boolean_t *is_added, 626 svn_wc_context_t *wc_ctx, 627 const char *local_abspath, 628 apr_pool_t *scratch_pool) 629{ 630 svn_wc__db_status_t status; 631 632 SVN_ERR(svn_wc__db_read_info(&status, 633 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 634 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 635 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 636 NULL, NULL, NULL, NULL, NULL, 637 wc_ctx->db, local_abspath, 638 scratch_pool, scratch_pool)); 639 *is_added = (status == svn_wc__db_status_added); 640 641 return SVN_NO_ERROR; 642} 643 644svn_error_t * 645svn_wc__node_has_working(svn_boolean_t *has_working, 646 svn_wc_context_t *wc_ctx, 647 const char *local_abspath, 648 apr_pool_t *scratch_pool) 649{ 650 svn_wc__db_status_t status; 651 652 SVN_ERR(svn_wc__db_read_info(&status, 653 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 654 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 655 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 656 NULL, NULL, NULL, NULL, has_working, 657 wc_ctx->db, local_abspath, 658 scratch_pool, scratch_pool)); 659 660 return SVN_NO_ERROR; 661} 662 663 664svn_error_t * 665svn_wc__node_get_base(svn_node_kind_t *kind, 666 svn_revnum_t *revision, 667 const char **repos_relpath, 668 const char **repos_root_url, 669 const char **repos_uuid, 670 const char **lock_token, 671 svn_wc_context_t *wc_ctx, 672 const char *local_abspath, 673 svn_boolean_t ignore_enoent, 674 svn_boolean_t show_hidden, 675 apr_pool_t *result_pool, 676 apr_pool_t *scratch_pool) 677{ 678 svn_error_t *err; 679 svn_wc__db_status_t status; 680 svn_wc__db_lock_t *lock; 681 svn_node_kind_t db_kind; 682 683 err = svn_wc__db_base_get_info(&status, &db_kind, revision, repos_relpath, 684 repos_root_url, repos_uuid, NULL, 685 NULL, NULL, NULL, NULL, NULL, 686 lock_token ? &lock : NULL, 687 NULL, NULL, NULL, 688 wc_ctx->db, local_abspath, 689 result_pool, scratch_pool); 690 691 if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND) 692 return svn_error_trace(err); 693 else if (err 694 || (!err && !show_hidden 695 && (status != svn_wc__db_status_normal 696 && status != svn_wc__db_status_incomplete))) 697 { 698 if (!ignore_enoent) 699 { 700 if (err) 701 return svn_error_trace(err); 702 else 703 return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, 704 _("The node '%s' was not found."), 705 svn_dirent_local_style(local_abspath, 706 scratch_pool)); 707 } 708 svn_error_clear(err); 709 710 if (kind) 711 *kind = svn_node_unknown; 712 if (revision) 713 *revision = SVN_INVALID_REVNUM; 714 if (repos_relpath) 715 *repos_relpath = NULL; 716 if (repos_root_url) 717 *repos_root_url = NULL; 718 if (repos_uuid) 719 *repos_uuid = NULL; 720 if (lock_token) 721 *lock_token = NULL; 722 return SVN_NO_ERROR; 723 } 724 725 if (kind) 726 *kind = db_kind; 727 if (lock_token) 728 *lock_token = lock ? lock->token : NULL; 729 730 SVN_ERR_ASSERT(!revision || SVN_IS_VALID_REVNUM(*revision)); 731 SVN_ERR_ASSERT(!repos_relpath || *repos_relpath); 732 SVN_ERR_ASSERT(!repos_root_url || *repos_root_url); 733 SVN_ERR_ASSERT(!repos_uuid || *repos_uuid); 734 return SVN_NO_ERROR; 735} 736 737svn_error_t * 738svn_wc__node_get_pre_ng_status_data(svn_revnum_t *revision, 739 svn_revnum_t *changed_rev, 740 apr_time_t *changed_date, 741 const char **changed_author, 742 svn_wc_context_t *wc_ctx, 743 const char *local_abspath, 744 apr_pool_t *result_pool, 745 apr_pool_t *scratch_pool) 746{ 747 svn_wc__db_status_t status; 748 svn_boolean_t have_base, have_more_work, have_work; 749 750 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL, NULL, NULL, 751 changed_rev, changed_date, changed_author, 752 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 753 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 754 &have_base, &have_more_work, &have_work, 755 wc_ctx->db, local_abspath, 756 result_pool, scratch_pool)); 757 758 if (!have_work 759 || ((!changed_rev || SVN_IS_VALID_REVNUM(*changed_rev)) 760 && (!revision || SVN_IS_VALID_REVNUM(*revision))) 761 || ((status != svn_wc__db_status_added) 762 && (status != svn_wc__db_status_deleted))) 763 { 764 return SVN_NO_ERROR; /* We got everything we need */ 765 } 766 767 if (have_base && !have_more_work) 768 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL, 769 changed_rev, changed_date, changed_author, 770 NULL, NULL, NULL, 771 NULL, NULL, NULL, NULL, 772 wc_ctx->db, local_abspath, 773 result_pool, scratch_pool)); 774 else if (status == svn_wc__db_status_deleted) 775 /* Check the information below a WORKING delete */ 776 SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, changed_rev, 777 changed_date, changed_author, NULL, 778 NULL, NULL, NULL, NULL, 779 wc_ctx->db, local_abspath, 780 result_pool, scratch_pool)); 781 782 return SVN_NO_ERROR; 783} 784 785svn_error_t * 786svn_wc__internal_node_get_schedule(svn_wc_schedule_t *schedule, 787 svn_boolean_t *copied, 788 svn_wc__db_t *db, 789 const char *local_abspath, 790 apr_pool_t *scratch_pool) 791{ 792 svn_wc__db_status_t status; 793 svn_boolean_t op_root; 794 svn_boolean_t have_base; 795 svn_boolean_t have_work; 796 svn_boolean_t have_more_work; 797 const char *copyfrom_relpath; 798 799 if (schedule) 800 *schedule = svn_wc_schedule_normal; 801 if (copied) 802 *copied = FALSE; 803 804 SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL, 805 NULL, NULL, NULL, NULL, NULL, ©from_relpath, 806 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 807 &op_root, NULL, NULL, 808 &have_base, &have_more_work, &have_work, 809 db, local_abspath, scratch_pool, scratch_pool)); 810 811 switch (status) 812 { 813 case svn_wc__db_status_not_present: 814 case svn_wc__db_status_server_excluded: 815 case svn_wc__db_status_excluded: 816 /* We used status normal in the entries world. */ 817 if (schedule) 818 *schedule = svn_wc_schedule_normal; 819 break; 820 case svn_wc__db_status_normal: 821 case svn_wc__db_status_incomplete: 822 break; 823 824 case svn_wc__db_status_deleted: 825 { 826 if (schedule) 827 *schedule = svn_wc_schedule_delete; 828 829 if (!copied) 830 break; 831 832 if (have_more_work || !have_base) 833 *copied = TRUE; 834 else 835 { 836 const char *work_del_abspath; 837 838 /* Find out details of our deletion. */ 839 SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL, 840 &work_del_abspath, NULL, 841 db, local_abspath, 842 scratch_pool, scratch_pool)); 843 844 if (work_del_abspath) 845 *copied = TRUE; /* Working deletion */ 846 } 847 break; 848 } 849 case svn_wc__db_status_added: 850 { 851 if (!op_root) 852 { 853 if (copied) 854 *copied = TRUE; 855 856 if (schedule) 857 *schedule = svn_wc_schedule_normal; 858 859 break; 860 } 861 862 if (copied) 863 *copied = (copyfrom_relpath != NULL); 864 865 if (schedule) 866 *schedule = svn_wc_schedule_add; 867 else 868 break; 869 870 /* Check for replaced */ 871 if (have_base || have_more_work) 872 { 873 svn_wc__db_status_t below_working; 874 SVN_ERR(svn_wc__db_info_below_working(&have_base, &have_work, 875 &below_working, 876 db, local_abspath, 877 scratch_pool)); 878 879 /* If the node is not present or deleted (read: not present 880 in working), then the node is not a replacement */ 881 if (below_working != svn_wc__db_status_not_present 882 && below_working != svn_wc__db_status_deleted) 883 { 884 *schedule = svn_wc_schedule_replace; 885 break; 886 } 887 } 888 break; 889 } 890 default: 891 SVN_ERR_MALFUNCTION(); 892 } 893 894 return SVN_NO_ERROR; 895} 896 897svn_error_t * 898svn_wc__node_get_schedule(svn_wc_schedule_t *schedule, 899 svn_boolean_t *copied, 900 svn_wc_context_t *wc_ctx, 901 const char *local_abspath, 902 apr_pool_t *scratch_pool) 903{ 904 return svn_error_trace( 905 svn_wc__internal_node_get_schedule(schedule, 906 copied, 907 wc_ctx->db, 908 local_abspath, 909 scratch_pool)); 910} 911 912svn_error_t * 913svn_wc__node_clear_dav_cache_recursive(svn_wc_context_t *wc_ctx, 914 const char *local_abspath, 915 apr_pool_t *scratch_pool) 916{ 917 return svn_error_trace(svn_wc__db_base_clear_dav_cache_recursive( 918 wc_ctx->db, local_abspath, scratch_pool)); 919} 920 921 922svn_error_t * 923svn_wc__node_get_lock_tokens_recursive(apr_hash_t **lock_tokens, 924 svn_wc_context_t *wc_ctx, 925 const char *local_abspath, 926 apr_pool_t *result_pool, 927 apr_pool_t *scratch_pool) 928{ 929 return svn_error_trace(svn_wc__db_base_get_lock_tokens_recursive( 930 lock_tokens, wc_ctx->db, local_abspath, 931 result_pool, scratch_pool)); 932} 933 934svn_error_t * 935svn_wc__get_excluded_subtrees(apr_hash_t **server_excluded_subtrees, 936 svn_wc_context_t *wc_ctx, 937 const char *local_abspath, 938 apr_pool_t *result_pool, 939 apr_pool_t *scratch_pool) 940{ 941 return svn_error_trace( 942 svn_wc__db_get_excluded_subtrees(server_excluded_subtrees, 943 wc_ctx->db, 944 local_abspath, 945 result_pool, 946 scratch_pool)); 947} 948 949svn_error_t * 950svn_wc__internal_get_origin(svn_boolean_t *is_copy, 951 svn_revnum_t *revision, 952 const char **repos_relpath, 953 const char **repos_root_url, 954 const char **repos_uuid, 955 const char **copy_root_abspath, 956 svn_wc__db_t *db, 957 const char *local_abspath, 958 svn_boolean_t scan_deleted, 959 apr_pool_t *result_pool, 960 apr_pool_t *scratch_pool) 961{ 962 const char *original_repos_relpath; 963 const char *original_repos_root_url; 964 const char *original_repos_uuid; 965 svn_revnum_t original_revision; 966 svn_wc__db_status_t status; 967 968 const char *tmp_repos_relpath; 969 970 if (!repos_relpath) 971 repos_relpath = &tmp_repos_relpath; 972 973 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath, 974 repos_root_url, repos_uuid, NULL, NULL, NULL, 975 NULL, NULL, NULL, 976 &original_repos_relpath, 977 &original_repos_root_url, 978 &original_repos_uuid, &original_revision, 979 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 980 NULL, NULL, is_copy, 981 db, local_abspath, result_pool, scratch_pool)); 982 983 if (*repos_relpath) 984 { 985 return SVN_NO_ERROR; /* Returned BASE information */ 986 } 987 988 if (status == svn_wc__db_status_deleted && !scan_deleted) 989 { 990 if (is_copy) 991 *is_copy = FALSE; /* Deletes are stored in working; default to FALSE */ 992 993 return SVN_NO_ERROR; /* No info */ 994 } 995 996 if (original_repos_relpath) 997 { 998 *repos_relpath = original_repos_relpath; 999 if (revision) 1000 *revision = original_revision; 1001 if (repos_root_url) 1002 *repos_root_url = original_repos_root_url; 1003 if (repos_uuid) 1004 *repos_uuid = original_repos_uuid; 1005 1006 if (copy_root_abspath == NULL) 1007 return SVN_NO_ERROR; 1008 } 1009 1010 { 1011 svn_boolean_t scan_working = FALSE; 1012 1013 if (status == svn_wc__db_status_added) 1014 scan_working = TRUE; 1015 else if (status == svn_wc__db_status_deleted) 1016 { 1017 svn_boolean_t have_base; 1018 /* Is this a BASE or a WORKING delete? */ 1019 SVN_ERR(svn_wc__db_info_below_working(&have_base, &scan_working, 1020 &status, db, local_abspath, 1021 scratch_pool)); 1022 } 1023 1024 if (scan_working) 1025 { 1026 const char *op_root_abspath; 1027 1028 SVN_ERR(svn_wc__db_scan_addition(&status, &op_root_abspath, NULL, 1029 NULL, NULL, &original_repos_relpath, 1030 repos_root_url, 1031 repos_uuid, revision, 1032 db, local_abspath, 1033 result_pool, scratch_pool)); 1034 1035 if (status == svn_wc__db_status_added) 1036 { 1037 if (is_copy) 1038 *is_copy = FALSE; 1039 return SVN_NO_ERROR; /* Local addition */ 1040 } 1041 1042 /* We don't know how the following error condition can be fulfilled 1043 * but we have seen that happening in the wild. Better to create 1044 * an error than a SEGFAULT. */ 1045 if (status == svn_wc__db_status_incomplete && !original_repos_relpath) 1046 return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, 1047 _("Incomplete copy information on path '%s'."), 1048 svn_dirent_local_style(local_abspath, 1049 scratch_pool)); 1050 1051 *repos_relpath = svn_relpath_join( 1052 original_repos_relpath, 1053 svn_dirent_skip_ancestor(op_root_abspath, 1054 local_abspath), 1055 result_pool); 1056 if (copy_root_abspath) 1057 *copy_root_abspath = op_root_abspath; 1058 } 1059 else /* Deleted, excluded, not-present, server-excluded, ... */ 1060 { 1061 if (is_copy) 1062 *is_copy = FALSE; 1063 1064 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, repos_relpath, 1065 repos_root_url, repos_uuid, NULL, 1066 NULL, NULL, NULL, NULL, NULL, NULL, 1067 NULL, NULL, NULL, 1068 db, local_abspath, 1069 result_pool, scratch_pool)); 1070 } 1071 1072 return SVN_NO_ERROR; 1073 } 1074} 1075 1076svn_error_t * 1077svn_wc__node_get_origin(svn_boolean_t *is_copy, 1078 svn_revnum_t *revision, 1079 const char **repos_relpath, 1080 const char **repos_root_url, 1081 const char **repos_uuid, 1082 const char **copy_root_abspath, 1083 svn_wc_context_t *wc_ctx, 1084 const char *local_abspath, 1085 svn_boolean_t scan_deleted, 1086 apr_pool_t *result_pool, 1087 apr_pool_t *scratch_pool) 1088{ 1089 return svn_error_trace(svn_wc__internal_get_origin(is_copy, revision, 1090 repos_relpath, repos_root_url, repos_uuid, 1091 copy_root_abspath, 1092 wc_ctx->db, local_abspath, scan_deleted, 1093 result_pool, scratch_pool)); 1094} 1095 1096svn_error_t * 1097svn_wc__node_get_commit_status(svn_boolean_t *added, 1098 svn_boolean_t *deleted, 1099 svn_boolean_t *is_replace_root, 1100 svn_boolean_t *is_op_root, 1101 svn_revnum_t *revision, 1102 svn_revnum_t *original_revision, 1103 const char **original_repos_relpath, 1104 svn_wc_context_t *wc_ctx, 1105 const char *local_abspath, 1106 apr_pool_t *result_pool, 1107 apr_pool_t *scratch_pool) 1108{ 1109 svn_wc__db_status_t status; 1110 svn_boolean_t have_base; 1111 svn_boolean_t have_more_work; 1112 svn_boolean_t op_root; 1113 1114 /* ### All of this should be handled inside a single read transaction */ 1115 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL, 1116 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1117 original_repos_relpath, NULL, NULL, 1118 original_revision, NULL, NULL, NULL, 1119 NULL, NULL, 1120 &op_root, NULL, NULL, 1121 &have_base, &have_more_work, NULL, 1122 wc_ctx->db, local_abspath, 1123 result_pool, scratch_pool)); 1124 1125 if (added) 1126 *added = (status == svn_wc__db_status_added); 1127 if (deleted) 1128 *deleted = (status == svn_wc__db_status_deleted); 1129 if (is_op_root) 1130 *is_op_root = op_root; 1131 1132 if (is_replace_root) 1133 { 1134 if (status == svn_wc__db_status_added 1135 && op_root 1136 && (have_base || have_more_work)) 1137 SVN_ERR(svn_wc__db_node_check_replace(is_replace_root, NULL, NULL, 1138 wc_ctx->db, local_abspath, 1139 scratch_pool)); 1140 else 1141 *is_replace_root = FALSE; 1142 } 1143 1144 /* Retrieve some information from BASE which is needed for replacing 1145 and/or deleting BASE nodes. */ 1146 if (have_base 1147 && !have_more_work 1148 && op_root 1149 && (revision && !SVN_IS_VALID_REVNUM(*revision))) 1150 { 1151 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL, 1152 NULL, NULL, NULL, NULL, NULL, NULL, 1153 NULL, NULL, NULL, NULL, 1154 wc_ctx->db, local_abspath, 1155 scratch_pool, scratch_pool)); 1156 } 1157 1158 return SVN_NO_ERROR; 1159} 1160 1161svn_error_t * 1162svn_wc__node_get_md5_from_sha1(const svn_checksum_t **md5_checksum, 1163 svn_wc_context_t *wc_ctx, 1164 const char *wri_abspath, 1165 const svn_checksum_t *sha1_checksum, 1166 apr_pool_t *result_pool, 1167 apr_pool_t *scratch_pool) 1168{ 1169 return svn_error_trace(svn_wc__db_pristine_get_md5(md5_checksum, 1170 wc_ctx->db, 1171 wri_abspath, 1172 sha1_checksum, 1173 result_pool, 1174 scratch_pool)); 1175} 1176 1177svn_error_t * 1178svn_wc__get_not_present_descendants(const apr_array_header_t **descendants, 1179 svn_wc_context_t *wc_ctx, 1180 const char *local_abspath, 1181 apr_pool_t *result_pool, 1182 apr_pool_t *scratch_pool) 1183{ 1184 return svn_error_trace( 1185 svn_wc__db_get_not_present_descendants(descendants, 1186 wc_ctx->db, 1187 local_abspath, 1188 result_pool, 1189 scratch_pool)); 1190} 1191 1192svn_error_t * 1193svn_wc__rename_wc(svn_wc_context_t *wc_ctx, 1194 const char *from_abspath, 1195 const char *dst_abspath, 1196 apr_pool_t *scratch_pool) 1197{ 1198 const char *wcroot_abspath; 1199 SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, wc_ctx->db, from_abspath, 1200 scratch_pool, scratch_pool)); 1201 1202 if (! strcmp(from_abspath, wcroot_abspath)) 1203 { 1204 SVN_ERR(svn_wc__db_drop_root(wc_ctx->db, wcroot_abspath, scratch_pool)); 1205 1206 SVN_ERR(svn_io_file_rename(from_abspath, dst_abspath, scratch_pool)); 1207 } 1208 else 1209 return svn_error_createf( 1210 SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, 1211 _("'%s' is not the root of the working copy '%s'"), 1212 svn_dirent_local_style(from_abspath, scratch_pool), 1213 svn_dirent_local_style(wcroot_abspath, scratch_pool)); 1214 1215 return SVN_NO_ERROR; 1216} 1217 1218svn_error_t * 1219svn_wc__check_for_obstructions(svn_wc_notify_state_t *obstruction_state, 1220 svn_node_kind_t *kind, 1221 svn_boolean_t *deleted, 1222 svn_boolean_t *excluded, 1223 svn_depth_t *parent_depth, 1224 svn_wc_context_t *wc_ctx, 1225 const char *local_abspath, 1226 svn_boolean_t no_wcroot_check, 1227 apr_pool_t *scratch_pool) 1228{ 1229 svn_wc__db_status_t status; 1230 svn_node_kind_t db_kind; 1231 svn_node_kind_t disk_kind; 1232 svn_error_t *err; 1233 1234 *obstruction_state = svn_wc_notify_state_inapplicable; 1235 if (kind) 1236 *kind = svn_node_none; 1237 if (deleted) 1238 *deleted = FALSE; 1239 if (excluded) 1240 *excluded = FALSE; 1241 if (parent_depth) 1242 *parent_depth = svn_depth_unknown; 1243 1244 SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, scratch_pool)); 1245 1246 err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, NULL, 1247 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1248 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1249 NULL, NULL, NULL, NULL, NULL, 1250 wc_ctx->db, local_abspath, 1251 scratch_pool, scratch_pool); 1252 1253 if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) 1254 { 1255 svn_error_clear(err); 1256 1257 if (disk_kind != svn_node_none) 1258 { 1259 /* Nothing in the DB, but something on disk */ 1260 *obstruction_state = svn_wc_notify_state_obstructed; 1261 return SVN_NO_ERROR; 1262 } 1263 1264 err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, 1265 NULL, NULL, NULL, parent_depth, NULL, NULL, 1266 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1267 NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1268 NULL, 1269 wc_ctx->db, svn_dirent_dirname(local_abspath, 1270 scratch_pool), 1271 scratch_pool, scratch_pool); 1272 1273 if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) 1274 { 1275 svn_error_clear(err); 1276 /* No versioned parent; we can't add a node here */ 1277 *obstruction_state = svn_wc_notify_state_obstructed; 1278 return SVN_NO_ERROR; 1279 } 1280 else 1281 SVN_ERR(err); 1282 1283 if (db_kind != svn_node_dir 1284 || (status != svn_wc__db_status_normal 1285 && status != svn_wc__db_status_added)) 1286 { 1287 /* The parent doesn't allow nodes to be added below it */ 1288 *obstruction_state = svn_wc_notify_state_obstructed; 1289 } 1290 1291 return SVN_NO_ERROR; 1292 } 1293 else 1294 SVN_ERR(err); 1295 1296 /* Check for obstructing working copies */ 1297 if (!no_wcroot_check 1298 && db_kind == svn_node_dir 1299 && status == svn_wc__db_status_normal) 1300 { 1301 svn_boolean_t is_root; 1302 SVN_ERR(svn_wc__db_is_wcroot(&is_root, wc_ctx->db, local_abspath, 1303 scratch_pool)); 1304 1305 if (is_root) 1306 { 1307 /* Callers should handle this as unversioned */ 1308 *obstruction_state = svn_wc_notify_state_obstructed; 1309 return SVN_NO_ERROR; 1310 } 1311 } 1312 1313 if (kind) 1314 SVN_ERR(convert_db_kind_to_node_kind(kind, db_kind, status, FALSE)); 1315 1316 switch (status) 1317 { 1318 case svn_wc__db_status_deleted: 1319 if (deleted) 1320 *deleted = TRUE; 1321 /* Fall through to svn_wc__db_status_not_present */ 1322 case svn_wc__db_status_not_present: 1323 if (disk_kind != svn_node_none) 1324 *obstruction_state = svn_wc_notify_state_obstructed; 1325 break; 1326 1327 case svn_wc__db_status_excluded: 1328 case svn_wc__db_status_server_excluded: 1329 if (excluded) 1330 *excluded = TRUE; 1331 /* fall through */ 1332 case svn_wc__db_status_incomplete: 1333 *obstruction_state = svn_wc_notify_state_missing; 1334 break; 1335 1336 case svn_wc__db_status_added: 1337 case svn_wc__db_status_normal: 1338 if (disk_kind == svn_node_none) 1339 *obstruction_state = svn_wc_notify_state_missing; 1340 else 1341 { 1342 svn_node_kind_t expected_kind; 1343 1344 SVN_ERR(convert_db_kind_to_node_kind(&expected_kind, db_kind, 1345 status, FALSE)); 1346 1347 if (disk_kind != expected_kind) 1348 *obstruction_state = svn_wc_notify_state_obstructed; 1349 } 1350 break; 1351 default: 1352 SVN_ERR_MALFUNCTION(); 1353 } 1354 1355 return SVN_NO_ERROR; 1356} 1357 1358 1359svn_error_t * 1360svn_wc__node_was_moved_away(const char **moved_to_abspath, 1361 const char **op_root_abspath, 1362 svn_wc_context_t *wc_ctx, 1363 const char *local_abspath, 1364 apr_pool_t *result_pool, 1365 apr_pool_t *scratch_pool) 1366{ 1367 svn_boolean_t is_deleted; 1368 1369 if (moved_to_abspath) 1370 *moved_to_abspath = NULL; 1371 if (op_root_abspath) 1372 *op_root_abspath = NULL; 1373 1374 SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, wc_ctx, local_abspath, 1375 scratch_pool)); 1376 if (is_deleted) 1377 SVN_ERR(svn_wc__db_scan_deletion(NULL, moved_to_abspath, NULL, 1378 op_root_abspath, wc_ctx->db, 1379 local_abspath, 1380 result_pool, scratch_pool)); 1381 1382 return SVN_NO_ERROR; 1383} 1384 1385 1386svn_error_t * 1387svn_wc__node_was_moved_here(const char **moved_from_abspath, 1388 const char **delete_op_root_abspath, 1389 svn_wc_context_t *wc_ctx, 1390 const char *local_abspath, 1391 apr_pool_t *result_pool, 1392 apr_pool_t *scratch_pool) 1393{ 1394 svn_error_t *err; 1395 1396 if (moved_from_abspath) 1397 *moved_from_abspath = NULL; 1398 if (delete_op_root_abspath) 1399 *delete_op_root_abspath = NULL; 1400 1401 err = svn_wc__db_scan_moved(moved_from_abspath, NULL, NULL, 1402 delete_op_root_abspath, 1403 wc_ctx->db, local_abspath, 1404 result_pool, scratch_pool); 1405 1406 if (err) 1407 { 1408 /* Return error for not added nodes */ 1409 if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS) 1410 return svn_error_trace(err); 1411 1412 /* Path not moved here */ 1413 svn_error_clear(err); 1414 return SVN_NO_ERROR; 1415 } 1416 1417 return SVN_NO_ERROR; 1418} 1419