1/* 2 * diff_tree.c : default diff tree processor 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#include <apr.h> 25#include <apr_pools.h> 26#include <apr_general.h> 27 28#include <assert.h> 29 30#include "svn_dirent_uri.h" 31#include "svn_error.h" 32#include "svn_io.h" 33#include "svn_pools.h" 34#include "svn_props.h" 35#include "svn_types.h" 36 37#include "private/svn_diff_tree.h" 38#include "svn_private_config.h" 39 40typedef struct tree_processor_t 41{ 42 svn_diff_tree_processor_t tp; 43 44 /* void *future_extension */ 45} tree_processor_t; 46 47 48static svn_error_t * 49default_dir_opened(void **new_dir_baton, 50 svn_boolean_t *skip, 51 svn_boolean_t *skip_children, 52 const char *relpath, 53 const svn_diff_source_t *left_source, 54 const svn_diff_source_t *right_source, 55 const svn_diff_source_t *copyfrom_source, 56 void *parent_dir_baton, 57 const svn_diff_tree_processor_t *processor, 58 apr_pool_t *result_pool, 59 apr_pool_t *scratch_pool) 60{ 61 *new_dir_baton = NULL; 62 return SVN_NO_ERROR; 63} 64 65static svn_error_t * 66default_dir_added(const char *relpath, 67 const svn_diff_source_t *copyfrom_source, 68 const svn_diff_source_t *right_source, 69 /*const*/ apr_hash_t *copyfrom_props, 70 /*const*/ apr_hash_t *right_props, 71 void *dir_baton, 72 const svn_diff_tree_processor_t *processor, 73 apr_pool_t *scratch_pool) 74{ 75 SVN_ERR(processor->dir_closed(relpath, NULL, right_source, 76 dir_baton, processor, 77 scratch_pool)); 78 79 return SVN_NO_ERROR; 80} 81 82static svn_error_t * 83default_dir_deleted(const char *relpath, 84 const svn_diff_source_t *left_source, 85 /*const*/ apr_hash_t *left_props, 86 void *dir_baton, 87 const svn_diff_tree_processor_t *processor, 88 apr_pool_t *scratch_pool) 89{ 90 SVN_ERR(processor->dir_closed(relpath, left_source, NULL, 91 dir_baton, processor, 92 scratch_pool)); 93 return SVN_NO_ERROR; 94} 95 96static svn_error_t * 97default_dir_changed(const char *relpath, 98 const svn_diff_source_t *left_source, 99 const svn_diff_source_t *right_source, 100 /*const*/ apr_hash_t *left_props, 101 /*const*/ apr_hash_t *right_props, 102 const apr_array_header_t *prop_changes, 103 void *dir_baton, 104 const struct svn_diff_tree_processor_t *processor, 105 apr_pool_t *scratch_pool) 106{ 107 SVN_ERR(processor->dir_closed(relpath, 108 left_source, right_source, 109 dir_baton, 110 processor, scratch_pool)); 111 return SVN_NO_ERROR; 112} 113 114static svn_error_t * 115default_dir_closed(const char *relpath, 116 const svn_diff_source_t *left_source, 117 const svn_diff_source_t *right_source, 118 void *dir_baton, 119 const svn_diff_tree_processor_t *processor, 120 apr_pool_t *scratch_pool) 121{ 122 return SVN_NO_ERROR; 123} 124 125static svn_error_t * 126default_file_opened(void **new_file_baton, 127 svn_boolean_t *skip, 128 const char *relpath, 129 const svn_diff_source_t *left_source, 130 const svn_diff_source_t *right_source, 131 const svn_diff_source_t *copyfrom_source, 132 void *dir_baton, 133 const svn_diff_tree_processor_t *processor, 134 apr_pool_t *result_pool, 135 apr_pool_t *scratch_pool) 136{ 137 *new_file_baton = dir_baton; 138 return SVN_NO_ERROR; 139} 140 141static svn_error_t * 142default_file_added(const char *relpath, 143 const svn_diff_source_t *copyfrom_source, 144 const svn_diff_source_t *right_source, 145 const char *copyfrom_file, 146 const char *right_file, 147 /*const*/ apr_hash_t *copyfrom_props, 148 /*const*/ apr_hash_t *right_props, 149 void *file_baton, 150 const svn_diff_tree_processor_t *processor, 151 apr_pool_t *scratch_pool) 152{ 153 SVN_ERR(processor->file_closed(relpath, 154 NULL, right_source, 155 file_baton, processor, scratch_pool)); 156 return SVN_NO_ERROR; 157} 158 159static svn_error_t * 160default_file_deleted(const char *relpath, 161 const svn_diff_source_t *left_source, 162 const char *left_file, 163 /*const*/ apr_hash_t *left_props, 164 void *file_baton, 165 const svn_diff_tree_processor_t *processor, 166 apr_pool_t *scratch_pool) 167{ 168 SVN_ERR(processor->file_closed(relpath, 169 left_source, NULL, 170 file_baton, processor, scratch_pool)); 171 return SVN_NO_ERROR; 172} 173 174static svn_error_t * 175default_file_changed(const char *relpath, 176 const svn_diff_source_t *left_source, 177 const svn_diff_source_t *right_source, 178 const char *left_file, 179 const char *right_file, 180 /*const*/ apr_hash_t *left_props, 181 /*const*/ apr_hash_t *right_props, 182 svn_boolean_t file_modified, 183 const apr_array_header_t *prop_changes, 184 void *file_baton, 185 const svn_diff_tree_processor_t *processor, 186 apr_pool_t *scratch_pool) 187{ 188 SVN_ERR(processor->file_closed(relpath, 189 left_source, right_source, 190 file_baton, processor, scratch_pool)); 191 return SVN_NO_ERROR; 192} 193 194static svn_error_t * 195default_file_closed(const char *relpath, 196 const svn_diff_source_t *left_source, 197 const svn_diff_source_t *right_source, 198 void *file_baton, 199 const svn_diff_tree_processor_t *processor, 200 apr_pool_t *scratch_pool) 201{ 202 return SVN_NO_ERROR; 203} 204 205static svn_error_t * 206default_node_absent(const char *relpath, 207 void *dir_baton, 208 const svn_diff_tree_processor_t *processor, 209 apr_pool_t *scratch_pool) 210{ 211 return SVN_NO_ERROR; 212} 213 214svn_diff_tree_processor_t * 215svn_diff__tree_processor_create(void *baton, 216 apr_pool_t *result_pool) 217{ 218 tree_processor_t *wrapper; 219 wrapper = apr_pcalloc(result_pool, sizeof(*wrapper)); 220 221 wrapper->tp.baton = baton; 222 223 wrapper->tp.dir_opened = default_dir_opened; 224 wrapper->tp.dir_added = default_dir_added; 225 wrapper->tp.dir_deleted = default_dir_deleted; 226 wrapper->tp.dir_changed = default_dir_changed; 227 wrapper->tp.dir_closed = default_dir_closed; 228 229 wrapper->tp.file_opened = default_file_opened; 230 wrapper->tp.file_added = default_file_added; 231 wrapper->tp.file_deleted = default_file_deleted; 232 wrapper->tp.file_changed = default_file_changed; 233 wrapper->tp.file_closed = default_file_closed; 234 235 wrapper->tp.node_absent = default_node_absent; 236 237 238 return &wrapper->tp; 239} 240 241struct reverse_tree_baton_t 242{ 243 const svn_diff_tree_processor_t *processor; 244 const char *prefix_relpath; 245}; 246 247static svn_error_t * 248reverse_dir_opened(void **new_dir_baton, 249 svn_boolean_t *skip, 250 svn_boolean_t *skip_children, 251 const char *relpath, 252 const svn_diff_source_t *left_source, 253 const svn_diff_source_t *right_source, 254 const svn_diff_source_t *copyfrom_source, 255 void *parent_dir_baton, 256 const svn_diff_tree_processor_t *processor, 257 apr_pool_t *result_pool, 258 apr_pool_t *scratch_pool) 259{ 260 struct reverse_tree_baton_t *rb = processor->baton; 261 262 if (rb->prefix_relpath) 263 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); 264 265 SVN_ERR(rb->processor->dir_opened(new_dir_baton, skip, skip_children, 266 relpath, 267 right_source, left_source, 268 NULL /* copyfrom */, 269 parent_dir_baton, 270 rb->processor, 271 result_pool, scratch_pool)); 272 return SVN_NO_ERROR; 273} 274 275static svn_error_t * 276reverse_dir_added(const char *relpath, 277 const svn_diff_source_t *copyfrom_source, 278 const svn_diff_source_t *right_source, 279 /*const*/ apr_hash_t *copyfrom_props, 280 /*const*/ apr_hash_t *right_props, 281 void *dir_baton, 282 const svn_diff_tree_processor_t *processor, 283 apr_pool_t *scratch_pool) 284{ 285 struct reverse_tree_baton_t *rb = processor->baton; 286 287 if (rb->prefix_relpath) 288 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); 289 290 SVN_ERR(rb->processor->dir_deleted(relpath, 291 right_source, 292 right_props, 293 dir_baton, 294 rb->processor, 295 scratch_pool)); 296 297 return SVN_NO_ERROR; 298} 299 300static svn_error_t * 301reverse_dir_deleted(const char *relpath, 302 const svn_diff_source_t *left_source, 303 /*const*/ apr_hash_t *left_props, 304 void *dir_baton, 305 const svn_diff_tree_processor_t *processor, 306 apr_pool_t *scratch_pool) 307{ 308 struct reverse_tree_baton_t *rb = processor->baton; 309 310 if (rb->prefix_relpath) 311 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); 312 313 SVN_ERR(rb->processor->dir_added(relpath, 314 NULL, 315 left_source, 316 NULL, 317 left_props, 318 dir_baton, 319 rb->processor, 320 scratch_pool)); 321 return SVN_NO_ERROR; 322} 323 324static svn_error_t * 325reverse_dir_changed(const char *relpath, 326 const svn_diff_source_t *left_source, 327 const svn_diff_source_t *right_source, 328 /*const*/ apr_hash_t *left_props, 329 /*const*/ apr_hash_t *right_props, 330 const apr_array_header_t *prop_changes, 331 void *dir_baton, 332 const struct svn_diff_tree_processor_t *processor, 333 apr_pool_t *scratch_pool) 334{ 335 struct reverse_tree_baton_t *rb = processor->baton; 336 apr_array_header_t *reversed_prop_changes = NULL; 337 338 if (rb->prefix_relpath) 339 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); 340 341 if (prop_changes) 342 { 343 SVN_ERR_ASSERT(left_props != NULL && right_props != NULL); 344 SVN_ERR(svn_prop_diffs(&reversed_prop_changes, left_props, right_props, 345 scratch_pool)); 346 } 347 348 SVN_ERR(rb->processor->dir_changed(relpath, 349 right_source, 350 left_source, 351 right_props, 352 left_props, 353 reversed_prop_changes, 354 dir_baton, 355 rb->processor, 356 scratch_pool)); 357 return SVN_NO_ERROR; 358} 359 360static svn_error_t * 361reverse_dir_closed(const char *relpath, 362 const svn_diff_source_t *left_source, 363 const svn_diff_source_t *right_source, 364 void *dir_baton, 365 const svn_diff_tree_processor_t *processor, 366 apr_pool_t *scratch_pool) 367{ 368 struct reverse_tree_baton_t *rb = processor->baton; 369 370 if (rb->prefix_relpath) 371 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); 372 373 SVN_ERR(rb->processor->dir_closed(relpath, 374 right_source, 375 left_source, 376 dir_baton, 377 rb->processor, 378 scratch_pool)); 379 return SVN_NO_ERROR; 380} 381 382static svn_error_t * 383reverse_file_opened(void **new_file_baton, 384 svn_boolean_t *skip, 385 const char *relpath, 386 const svn_diff_source_t *left_source, 387 const svn_diff_source_t *right_source, 388 const svn_diff_source_t *copyfrom_source, 389 void *dir_baton, 390 const svn_diff_tree_processor_t *processor, 391 apr_pool_t *result_pool, 392 apr_pool_t *scratch_pool) 393{ 394 struct reverse_tree_baton_t *rb = processor->baton; 395 396 if (rb->prefix_relpath) 397 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); 398 399 SVN_ERR(rb->processor->file_opened(new_file_baton, 400 skip, 401 relpath, 402 right_source, 403 left_source, 404 NULL /* copy_from */, 405 dir_baton, 406 rb->processor, 407 result_pool, 408 scratch_pool)); 409 return SVN_NO_ERROR; 410} 411 412static svn_error_t * 413reverse_file_added(const char *relpath, 414 const svn_diff_source_t *copyfrom_source, 415 const svn_diff_source_t *right_source, 416 const char *copyfrom_file, 417 const char *right_file, 418 /*const*/ apr_hash_t *copyfrom_props, 419 /*const*/ apr_hash_t *right_props, 420 void *file_baton, 421 const svn_diff_tree_processor_t *processor, 422 apr_pool_t *scratch_pool) 423{ 424 struct reverse_tree_baton_t *rb = processor->baton; 425 426 if (rb->prefix_relpath) 427 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); 428 429 SVN_ERR(rb->processor->file_deleted(relpath, 430 right_source, 431 right_file, 432 right_props, 433 file_baton, 434 rb->processor, 435 scratch_pool)); 436 return SVN_NO_ERROR; 437} 438 439static svn_error_t * 440reverse_file_deleted(const char *relpath, 441 const svn_diff_source_t *left_source, 442 const char *left_file, 443 /*const*/ apr_hash_t *left_props, 444 void *file_baton, 445 const svn_diff_tree_processor_t *processor, 446 apr_pool_t *scratch_pool) 447{ 448 struct reverse_tree_baton_t *rb = processor->baton; 449 450 if (rb->prefix_relpath) 451 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); 452 453 SVN_ERR(rb->processor->file_added(relpath, 454 NULL /* copyfrom src */, 455 left_source, 456 NULL /* copyfrom file */, 457 left_file, 458 NULL /* copyfrom props */, 459 left_props, 460 file_baton, 461 rb->processor, 462 scratch_pool)); 463 return SVN_NO_ERROR; 464} 465 466static svn_error_t * 467reverse_file_changed(const char *relpath, 468 const svn_diff_source_t *left_source, 469 const svn_diff_source_t *right_source, 470 const char *left_file, 471 const char *right_file, 472 /*const*/ apr_hash_t *left_props, 473 /*const*/ apr_hash_t *right_props, 474 svn_boolean_t file_modified, 475 const apr_array_header_t *prop_changes, 476 void *file_baton, 477 const svn_diff_tree_processor_t *processor, 478 apr_pool_t *scratch_pool) 479{ 480 struct reverse_tree_baton_t *rb = processor->baton; 481 apr_array_header_t *reversed_prop_changes = NULL; 482 483 if (rb->prefix_relpath) 484 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); 485 486 if (prop_changes) 487 { 488 SVN_ERR_ASSERT(left_props != NULL && right_props != NULL); 489 SVN_ERR(svn_prop_diffs(&reversed_prop_changes, left_props, right_props, 490 scratch_pool)); 491 } 492 493 SVN_ERR(rb->processor->file_changed(relpath, 494 right_source, 495 left_source, 496 right_file, 497 left_file, 498 right_props, 499 left_props, 500 file_modified, 501 reversed_prop_changes, 502 file_baton, 503 rb->processor, 504 scratch_pool)); 505 return SVN_NO_ERROR; 506} 507 508static svn_error_t * 509reverse_file_closed(const char *relpath, 510 const svn_diff_source_t *left_source, 511 const svn_diff_source_t *right_source, 512 void *file_baton, 513 const svn_diff_tree_processor_t *processor, 514 apr_pool_t *scratch_pool) 515{ 516 struct reverse_tree_baton_t *rb = processor->baton; 517 518 if (rb->prefix_relpath) 519 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); 520 521 SVN_ERR(rb->processor->file_closed(relpath, 522 right_source, 523 left_source, 524 file_baton, 525 rb->processor, 526 scratch_pool)); 527 528 return SVN_NO_ERROR; 529} 530 531static svn_error_t * 532reverse_node_absent(const char *relpath, 533 void *dir_baton, 534 const svn_diff_tree_processor_t *processor, 535 apr_pool_t *scratch_pool) 536{ 537 struct reverse_tree_baton_t *rb = processor->baton; 538 539 if (rb->prefix_relpath) 540 relpath = svn_relpath_join(rb->prefix_relpath, relpath, scratch_pool); 541 542 SVN_ERR(rb->processor->node_absent(relpath, 543 dir_baton, 544 rb->processor, 545 scratch_pool)); 546 return SVN_NO_ERROR; 547} 548 549 550const svn_diff_tree_processor_t * 551svn_diff__tree_processor_reverse_create(const svn_diff_tree_processor_t * processor, 552 const char *prefix_relpath, 553 apr_pool_t *result_pool) 554{ 555 struct reverse_tree_baton_t *rb; 556 svn_diff_tree_processor_t *reverse; 557 558 rb = apr_pcalloc(result_pool, sizeof(*rb)); 559 rb->processor = processor; 560 if (prefix_relpath) 561 rb->prefix_relpath = apr_pstrdup(result_pool, prefix_relpath); 562 563 reverse = svn_diff__tree_processor_create(rb, result_pool); 564 565 reverse->dir_opened = reverse_dir_opened; 566 reverse->dir_added = reverse_dir_added; 567 reverse->dir_deleted = reverse_dir_deleted; 568 reverse->dir_changed = reverse_dir_changed; 569 reverse->dir_closed = reverse_dir_closed; 570 571 reverse->file_opened = reverse_file_opened; 572 reverse->file_added = reverse_file_added; 573 reverse->file_deleted = reverse_file_deleted; 574 reverse->file_changed = reverse_file_changed; 575 reverse->file_closed = reverse_file_closed; 576 577 reverse->node_absent = reverse_node_absent; 578 579 return reverse; 580} 581 582struct filter_tree_baton_t 583{ 584 const svn_diff_tree_processor_t *processor; 585 const char *prefix_relpath; 586}; 587 588static svn_error_t * 589filter_dir_opened(void **new_dir_baton, 590 svn_boolean_t *skip, 591 svn_boolean_t *skip_children, 592 const char *relpath, 593 const svn_diff_source_t *left_source, 594 const svn_diff_source_t *right_source, 595 const svn_diff_source_t *copyfrom_source, 596 void *parent_dir_baton, 597 const svn_diff_tree_processor_t *processor, 598 apr_pool_t *result_pool, 599 apr_pool_t *scratch_pool) 600{ 601 struct filter_tree_baton_t *fb = processor->baton; 602 603 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); 604 605 if (! relpath) 606 { 607 /* Skip work for this, but NOT for DESCENDANTS */ 608 *skip = TRUE; 609 return SVN_NO_ERROR; 610 } 611 612 SVN_ERR(fb->processor->dir_opened(new_dir_baton, skip, skip_children, 613 relpath, 614 left_source, right_source, 615 copyfrom_source, 616 parent_dir_baton, 617 fb->processor, 618 result_pool, scratch_pool)); 619 return SVN_NO_ERROR; 620} 621 622static svn_error_t * 623filter_dir_added(const char *relpath, 624 const svn_diff_source_t *copyfrom_source, 625 const svn_diff_source_t *right_source, 626 /*const*/ apr_hash_t *copyfrom_props, 627 /*const*/ apr_hash_t *right_props, 628 void *dir_baton, 629 const svn_diff_tree_processor_t *processor, 630 apr_pool_t *scratch_pool) 631{ 632 struct filter_tree_baton_t *fb = processor->baton; 633 634 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); 635 assert(relpath != NULL); /* Driver error */ 636 637 SVN_ERR(fb->processor->dir_added(relpath, 638 copyfrom_source, 639 right_source, 640 copyfrom_props, 641 right_props, 642 dir_baton, 643 fb->processor, 644 scratch_pool)); 645 646 return SVN_NO_ERROR; 647} 648 649static svn_error_t * 650filter_dir_deleted(const char *relpath, 651 const svn_diff_source_t *left_source, 652 /*const*/ apr_hash_t *left_props, 653 void *dir_baton, 654 const svn_diff_tree_processor_t *processor, 655 apr_pool_t *scratch_pool) 656{ 657 struct filter_tree_baton_t *fb = processor->baton; 658 659 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); 660 assert(relpath != NULL); /* Driver error */ 661 662 SVN_ERR(fb->processor->dir_deleted(relpath, 663 left_source, 664 left_props, 665 dir_baton, 666 fb->processor, 667 scratch_pool)); 668 669 return SVN_NO_ERROR; 670} 671 672static svn_error_t * 673filter_dir_changed(const char *relpath, 674 const svn_diff_source_t *left_source, 675 const svn_diff_source_t *right_source, 676 /*const*/ apr_hash_t *left_props, 677 /*const*/ apr_hash_t *right_props, 678 const apr_array_header_t *prop_changes, 679 void *dir_baton, 680 const struct svn_diff_tree_processor_t *processor, 681 apr_pool_t *scratch_pool) 682{ 683 struct filter_tree_baton_t *fb = processor->baton; 684 685 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); 686 assert(relpath != NULL); /* Driver error */ 687 688 SVN_ERR(fb->processor->dir_changed(relpath, 689 left_source, 690 right_source, 691 left_props, 692 right_props, 693 prop_changes, 694 dir_baton, 695 fb->processor, 696 scratch_pool)); 697 return SVN_NO_ERROR; 698} 699 700static svn_error_t * 701filter_dir_closed(const char *relpath, 702 const svn_diff_source_t *left_source, 703 const svn_diff_source_t *right_source, 704 void *dir_baton, 705 const svn_diff_tree_processor_t *processor, 706 apr_pool_t *scratch_pool) 707{ 708 struct filter_tree_baton_t *fb = processor->baton; 709 710 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); 711 assert(relpath != NULL); /* Driver error */ 712 713 SVN_ERR(fb->processor->dir_closed(relpath, 714 left_source, 715 right_source, 716 dir_baton, 717 fb->processor, 718 scratch_pool)); 719 return SVN_NO_ERROR; 720} 721 722static svn_error_t * 723filter_file_opened(void **new_file_baton, 724 svn_boolean_t *skip, 725 const char *relpath, 726 const svn_diff_source_t *left_source, 727 const svn_diff_source_t *right_source, 728 const svn_diff_source_t *copyfrom_source, 729 void *dir_baton, 730 const svn_diff_tree_processor_t *processor, 731 apr_pool_t *result_pool, 732 apr_pool_t *scratch_pool) 733{ 734 struct filter_tree_baton_t *fb = processor->baton; 735 736 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); 737 738 if (! relpath) 739 { 740 *skip = TRUE; 741 return SVN_NO_ERROR; 742 } 743 744 SVN_ERR(fb->processor->file_opened(new_file_baton, 745 skip, 746 relpath, 747 left_source, 748 right_source, 749 copyfrom_source, 750 dir_baton, 751 fb->processor, 752 result_pool, 753 scratch_pool)); 754 return SVN_NO_ERROR; 755} 756 757static svn_error_t * 758filter_file_added(const char *relpath, 759 const svn_diff_source_t *copyfrom_source, 760 const svn_diff_source_t *right_source, 761 const char *copyfrom_file, 762 const char *right_file, 763 /*const*/ apr_hash_t *copyfrom_props, 764 /*const*/ apr_hash_t *right_props, 765 void *file_baton, 766 const svn_diff_tree_processor_t *processor, 767 apr_pool_t *scratch_pool) 768{ 769 struct filter_tree_baton_t *fb = processor->baton; 770 771 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); 772 assert(relpath != NULL); /* Driver error */ 773 774 SVN_ERR(fb->processor->file_added(relpath, 775 copyfrom_source, 776 right_source, 777 copyfrom_file, 778 right_file, 779 copyfrom_props, 780 right_props, 781 file_baton, 782 fb->processor, 783 scratch_pool)); 784 return SVN_NO_ERROR; 785} 786 787static svn_error_t * 788filter_file_deleted(const char *relpath, 789 const svn_diff_source_t *left_source, 790 const char *left_file, 791 /*const*/ apr_hash_t *left_props, 792 void *file_baton, 793 const svn_diff_tree_processor_t *processor, 794 apr_pool_t *scratch_pool) 795{ 796 struct filter_tree_baton_t *fb = processor->baton; 797 798 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); 799 assert(relpath != NULL); /* Driver error */ 800 801 SVN_ERR(fb->processor->file_deleted(relpath, 802 left_source, 803 left_file, 804 left_props, 805 file_baton, 806 fb->processor, 807 scratch_pool)); 808 809 return SVN_NO_ERROR; 810} 811 812static svn_error_t * 813filter_file_changed(const char *relpath, 814 const svn_diff_source_t *left_source, 815 const svn_diff_source_t *right_source, 816 const char *left_file, 817 const char *right_file, 818 /*const*/ apr_hash_t *left_props, 819 /*const*/ apr_hash_t *right_props, 820 svn_boolean_t file_modified, 821 const apr_array_header_t *prop_changes, 822 void *file_baton, 823 const svn_diff_tree_processor_t *processor, 824 apr_pool_t *scratch_pool) 825{ 826 struct filter_tree_baton_t *fb = processor->baton; 827 828 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); 829 assert(relpath != NULL); /* Driver error */ 830 831 SVN_ERR(fb->processor->file_changed(relpath, 832 left_source, 833 right_source, 834 left_file, 835 right_file, 836 left_props, 837 right_props, 838 file_modified, 839 prop_changes, 840 file_baton, 841 fb->processor, 842 scratch_pool)); 843 return SVN_NO_ERROR; 844} 845 846static svn_error_t * 847filter_file_closed(const char *relpath, 848 const svn_diff_source_t *left_source, 849 const svn_diff_source_t *right_source, 850 void *file_baton, 851 const svn_diff_tree_processor_t *processor, 852 apr_pool_t *scratch_pool) 853{ 854 struct filter_tree_baton_t *fb = processor->baton; 855 856 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); 857 assert(relpath != NULL); /* Driver error */ 858 859 SVN_ERR(fb->processor->file_closed(relpath, 860 left_source, 861 right_source, 862 file_baton, 863 fb->processor, 864 scratch_pool)); 865 866 return SVN_NO_ERROR; 867} 868 869static svn_error_t * 870filter_node_absent(const char *relpath, 871 void *dir_baton, 872 const svn_diff_tree_processor_t *processor, 873 apr_pool_t *scratch_pool) 874{ 875 struct filter_tree_baton_t *fb = processor->baton; 876 877 relpath = svn_relpath_skip_ancestor(fb->prefix_relpath, relpath); 878 assert(relpath != NULL); /* Driver error */ 879 880 SVN_ERR(fb->processor->node_absent(relpath, 881 dir_baton, 882 fb->processor, 883 scratch_pool)); 884 return SVN_NO_ERROR; 885} 886 887 888const svn_diff_tree_processor_t * 889svn_diff__tree_processor_filter_create(const svn_diff_tree_processor_t * processor, 890 const char *prefix_relpath, 891 apr_pool_t *result_pool) 892{ 893 struct filter_tree_baton_t *fb; 894 svn_diff_tree_processor_t *filter; 895 896 fb = apr_pcalloc(result_pool, sizeof(*fb)); 897 fb->processor = processor; 898 if (prefix_relpath) 899 fb->prefix_relpath = apr_pstrdup(result_pool, prefix_relpath); 900 901 filter = svn_diff__tree_processor_create(fb, result_pool); 902 903 filter->dir_opened = filter_dir_opened; 904 filter->dir_added = filter_dir_added; 905 filter->dir_deleted = filter_dir_deleted; 906 filter->dir_changed = filter_dir_changed; 907 filter->dir_closed = filter_dir_closed; 908 909 filter->file_opened = filter_file_opened; 910 filter->file_added = filter_file_added; 911 filter->file_deleted = filter_file_deleted; 912 filter->file_changed = filter_file_changed; 913 filter->file_closed = filter_file_closed; 914 915 filter->node_absent = filter_node_absent; 916 917 return filter; 918} 919 920struct copy_as_changed_baton_t 921{ 922 const svn_diff_tree_processor_t *processor; 923}; 924 925static svn_error_t * 926copy_as_changed_dir_opened(void **new_dir_baton, 927 svn_boolean_t *skip, 928 svn_boolean_t *skip_children, 929 const char *relpath, 930 const svn_diff_source_t *left_source, 931 const svn_diff_source_t *right_source, 932 const svn_diff_source_t *copyfrom_source, 933 void *parent_dir_baton, 934 const svn_diff_tree_processor_t *processor, 935 apr_pool_t *result_pool, 936 apr_pool_t *scratch_pool) 937{ 938 struct copy_as_changed_baton_t *cb = processor->baton; 939 940 if (!left_source && copyfrom_source) 941 { 942 assert(right_source != NULL); 943 944 left_source = copyfrom_source; 945 copyfrom_source = NULL; 946 } 947 948 SVN_ERR(cb->processor->dir_opened(new_dir_baton, skip, skip_children, 949 relpath, 950 left_source, right_source, 951 copyfrom_source, 952 parent_dir_baton, 953 cb->processor, 954 result_pool, scratch_pool)); 955 return SVN_NO_ERROR; 956} 957 958static svn_error_t * 959copy_as_changed_dir_added(const char *relpath, 960 const svn_diff_source_t *copyfrom_source, 961 const svn_diff_source_t *right_source, 962 /*const*/ apr_hash_t *copyfrom_props, 963 /*const*/ apr_hash_t *right_props, 964 void *dir_baton, 965 const svn_diff_tree_processor_t *processor, 966 apr_pool_t *scratch_pool) 967{ 968 struct copy_as_changed_baton_t *cb = processor->baton; 969 970 if (copyfrom_source) 971 { 972 apr_array_header_t *propchanges; 973 SVN_ERR(svn_prop_diffs(&propchanges, right_props, copyfrom_props, 974 scratch_pool)); 975 SVN_ERR(cb->processor->dir_changed(relpath, 976 copyfrom_source, 977 right_source, 978 copyfrom_props, 979 right_props, 980 propchanges, 981 dir_baton, 982 cb->processor, 983 scratch_pool)); 984 } 985 else 986 { 987 SVN_ERR(cb->processor->dir_added(relpath, 988 copyfrom_source, 989 right_source, 990 copyfrom_props, 991 right_props, 992 dir_baton, 993 cb->processor, 994 scratch_pool)); 995 } 996 997 return SVN_NO_ERROR; 998} 999 1000static svn_error_t * 1001copy_as_changed_dir_deleted(const char *relpath, 1002 const svn_diff_source_t *left_source, 1003 /*const*/ apr_hash_t *left_props, 1004 void *dir_baton, 1005 const svn_diff_tree_processor_t *processor, 1006 apr_pool_t *scratch_pool) 1007{ 1008 struct copy_as_changed_baton_t *cb = processor->baton; 1009 1010 SVN_ERR(cb->processor->dir_deleted(relpath, 1011 left_source, 1012 left_props, 1013 dir_baton, 1014 cb->processor, 1015 scratch_pool)); 1016 1017 return SVN_NO_ERROR; 1018} 1019 1020static svn_error_t * 1021copy_as_changed_dir_changed(const char *relpath, 1022 const svn_diff_source_t *left_source, 1023 const svn_diff_source_t *right_source, 1024 /*const*/ apr_hash_t *left_props, 1025 /*const*/ apr_hash_t *right_props, 1026 const apr_array_header_t *prop_changes, 1027 void *dir_baton, 1028 const struct svn_diff_tree_processor_t *processor, 1029 apr_pool_t *scratch_pool) 1030{ 1031 struct copy_as_changed_baton_t *cb = processor->baton; 1032 1033 SVN_ERR(cb->processor->dir_changed(relpath, 1034 left_source, 1035 right_source, 1036 left_props, 1037 right_props, 1038 prop_changes, 1039 dir_baton, 1040 cb->processor, 1041 scratch_pool)); 1042 return SVN_NO_ERROR; 1043} 1044 1045static svn_error_t * 1046copy_as_changed_dir_closed(const char *relpath, 1047 const svn_diff_source_t *left_source, 1048 const svn_diff_source_t *right_source, 1049 void *dir_baton, 1050 const svn_diff_tree_processor_t *processor, 1051 apr_pool_t *scratch_pool) 1052{ 1053 struct copy_as_changed_baton_t *cb = processor->baton; 1054 1055 SVN_ERR(cb->processor->dir_closed(relpath, 1056 left_source, 1057 right_source, 1058 dir_baton, 1059 cb->processor, 1060 scratch_pool)); 1061 return SVN_NO_ERROR; 1062} 1063 1064static svn_error_t * 1065copy_as_changed_file_opened(void **new_file_baton, 1066 svn_boolean_t *skip, 1067 const char *relpath, 1068 const svn_diff_source_t *left_source, 1069 const svn_diff_source_t *right_source, 1070 const svn_diff_source_t *copyfrom_source, 1071 void *dir_baton, 1072 const svn_diff_tree_processor_t *processor, 1073 apr_pool_t *result_pool, 1074 apr_pool_t *scratch_pool) 1075{ 1076 struct copy_as_changed_baton_t *cb = processor->baton; 1077 1078 if (!left_source && copyfrom_source) 1079 { 1080 assert(right_source != NULL); 1081 1082 left_source = copyfrom_source; 1083 copyfrom_source = NULL; 1084 } 1085 1086 SVN_ERR(cb->processor->file_opened(new_file_baton, 1087 skip, 1088 relpath, 1089 left_source, 1090 right_source, 1091 copyfrom_source, 1092 dir_baton, 1093 cb->processor, 1094 result_pool, 1095 scratch_pool)); 1096 return SVN_NO_ERROR; 1097} 1098 1099static svn_error_t * 1100copy_as_changed_file_added(const char *relpath, 1101 const svn_diff_source_t *copyfrom_source, 1102 const svn_diff_source_t *right_source, 1103 const char *copyfrom_file, 1104 const char *right_file, 1105 /*const*/ apr_hash_t *copyfrom_props, 1106 /*const*/ apr_hash_t *right_props, 1107 void *file_baton, 1108 const svn_diff_tree_processor_t *processor, 1109 apr_pool_t *scratch_pool) 1110{ 1111 struct copy_as_changed_baton_t *cb = processor->baton; 1112 1113 if (copyfrom_source) 1114 { 1115 apr_array_header_t *propchanges; 1116 svn_boolean_t same; 1117 SVN_ERR(svn_prop_diffs(&propchanges, right_props, copyfrom_props, 1118 scratch_pool)); 1119 1120 /* "" is sometimes a marker for just modified (E.g. no-textdeltas), 1121 and it is certainly not a file */ 1122 if (*copyfrom_file && *right_file) 1123 { 1124 SVN_ERR(svn_io_files_contents_same_p(&same, copyfrom_file, 1125 right_file, scratch_pool)); 1126 } 1127 else 1128 same = FALSE; 1129 1130 SVN_ERR(cb->processor->file_changed(relpath, 1131 copyfrom_source, 1132 right_source, 1133 copyfrom_file, 1134 right_file, 1135 copyfrom_props, 1136 right_props, 1137 !same, 1138 propchanges, 1139 file_baton, 1140 cb->processor, 1141 scratch_pool)); 1142 } 1143 else 1144 { 1145 SVN_ERR(cb->processor->file_added(relpath, 1146 copyfrom_source, 1147 right_source, 1148 copyfrom_file, 1149 right_file, 1150 copyfrom_props, 1151 right_props, 1152 file_baton, 1153 cb->processor, 1154 scratch_pool)); 1155 } 1156 return SVN_NO_ERROR; 1157} 1158 1159static svn_error_t * 1160copy_as_changed_file_deleted(const char *relpath, 1161 const svn_diff_source_t *left_source, 1162 const char *left_file, 1163 /*const*/ apr_hash_t *left_props, 1164 void *file_baton, 1165 const svn_diff_tree_processor_t *processor, 1166 apr_pool_t *scratch_pool) 1167{ 1168 struct copy_as_changed_baton_t *cb = processor->baton; 1169 1170 SVN_ERR(cb->processor->file_deleted(relpath, 1171 left_source, 1172 left_file, 1173 left_props, 1174 file_baton, 1175 cb->processor, 1176 scratch_pool)); 1177 1178 return SVN_NO_ERROR; 1179} 1180 1181static svn_error_t * 1182copy_as_changed_file_changed(const char *relpath, 1183 const svn_diff_source_t *left_source, 1184 const svn_diff_source_t *right_source, 1185 const char *left_file, 1186 const char *right_file, 1187 /*const*/ apr_hash_t *left_props, 1188 /*const*/ apr_hash_t *right_props, 1189 svn_boolean_t file_modified, 1190 const apr_array_header_t *prop_changes, 1191 void *file_baton, 1192 const svn_diff_tree_processor_t *processor, 1193 apr_pool_t *scratch_pool) 1194{ 1195 struct copy_as_changed_baton_t *cb = processor->baton; 1196 1197 SVN_ERR(cb->processor->file_changed(relpath, 1198 left_source, 1199 right_source, 1200 left_file, 1201 right_file, 1202 left_props, 1203 right_props, 1204 file_modified, 1205 prop_changes, 1206 file_baton, 1207 cb->processor, 1208 scratch_pool)); 1209 return SVN_NO_ERROR; 1210} 1211 1212static svn_error_t * 1213copy_as_changed_file_closed(const char *relpath, 1214 const svn_diff_source_t *left_source, 1215 const svn_diff_source_t *right_source, 1216 void *file_baton, 1217 const svn_diff_tree_processor_t *processor, 1218 apr_pool_t *scratch_pool) 1219{ 1220 struct copy_as_changed_baton_t *cb = processor->baton; 1221 1222 SVN_ERR(cb->processor->file_closed(relpath, 1223 left_source, 1224 right_source, 1225 file_baton, 1226 cb->processor, 1227 scratch_pool)); 1228 1229 return SVN_NO_ERROR; 1230} 1231 1232static svn_error_t * 1233copy_as_changed_node_absent(const char *relpath, 1234 void *dir_baton, 1235 const svn_diff_tree_processor_t *processor, 1236 apr_pool_t *scratch_pool) 1237{ 1238 struct copy_as_changed_baton_t *cb = processor->baton; 1239 1240 SVN_ERR(cb->processor->node_absent(relpath, 1241 dir_baton, 1242 cb->processor, 1243 scratch_pool)); 1244 return SVN_NO_ERROR; 1245} 1246 1247 1248const svn_diff_tree_processor_t * 1249svn_diff__tree_processor_copy_as_changed_create( 1250 const svn_diff_tree_processor_t * processor, 1251 apr_pool_t *result_pool) 1252{ 1253 struct copy_as_changed_baton_t *cb; 1254 svn_diff_tree_processor_t *filter; 1255 1256 cb = apr_pcalloc(result_pool, sizeof(*cb)); 1257 cb->processor = processor; 1258 1259 filter = svn_diff__tree_processor_create(cb, result_pool); 1260 filter->dir_opened = copy_as_changed_dir_opened; 1261 filter->dir_added = copy_as_changed_dir_added; 1262 filter->dir_deleted = copy_as_changed_dir_deleted; 1263 filter->dir_changed = copy_as_changed_dir_changed; 1264 filter->dir_closed = copy_as_changed_dir_closed; 1265 1266 filter->file_opened = copy_as_changed_file_opened; 1267 filter->file_added = copy_as_changed_file_added; 1268 filter->file_deleted = copy_as_changed_file_deleted; 1269 filter->file_changed = copy_as_changed_file_changed; 1270 filter->file_closed = copy_as_changed_file_closed; 1271 1272 filter->node_absent = copy_as_changed_node_absent; 1273 1274 return filter; 1275} 1276 1277 1278/* Processor baton for the tee tree processor */ 1279struct tee_baton_t 1280{ 1281 const svn_diff_tree_processor_t *p1; 1282 const svn_diff_tree_processor_t *p2; 1283}; 1284 1285/* Wrapper baton for file and directory batons in the tee processor */ 1286struct tee_node_baton_t 1287{ 1288 void *baton1; 1289 void *baton2; 1290}; 1291 1292static svn_error_t * 1293tee_dir_opened(void **new_dir_baton, 1294 svn_boolean_t *skip, 1295 svn_boolean_t *skip_children, 1296 const char *relpath, 1297 const svn_diff_source_t *left_source, 1298 const svn_diff_source_t *right_source, 1299 const svn_diff_source_t *copyfrom_source, 1300 void *parent_dir_baton, 1301 const svn_diff_tree_processor_t *processor, 1302 apr_pool_t *result_pool, 1303 apr_pool_t *scratch_pool) 1304{ 1305 struct tee_baton_t *tb = processor->baton; 1306 struct tee_node_baton_t *pb = parent_dir_baton; 1307 struct tee_node_baton_t *nb = apr_pcalloc(result_pool, sizeof(*nb)); 1308 1309 SVN_ERR(tb->p1->dir_opened(&(nb->baton1), 1310 skip, 1311 skip_children, 1312 relpath, 1313 left_source, 1314 right_source, 1315 copyfrom_source, 1316 pb ? pb->baton1 : NULL, 1317 tb->p1, 1318 result_pool, 1319 scratch_pool)); 1320 1321 SVN_ERR(tb->p2->dir_opened(&(nb->baton2), 1322 skip, 1323 skip_children, 1324 relpath, 1325 left_source, 1326 right_source, 1327 copyfrom_source, 1328 pb ? pb->baton2 : NULL, 1329 tb->p2, 1330 result_pool, 1331 scratch_pool)); 1332 1333 *new_dir_baton = nb; 1334 1335 return SVN_NO_ERROR; 1336} 1337 1338static svn_error_t * 1339tee_dir_added(const char *relpath, 1340 const svn_diff_source_t *copyfrom_source, 1341 const svn_diff_source_t *right_source, 1342 /*const*/ apr_hash_t *copyfrom_props, 1343 /*const*/ apr_hash_t *right_props, 1344 void *dir_baton, 1345 const svn_diff_tree_processor_t *processor, 1346 apr_pool_t *scratch_pool) 1347{ 1348 struct tee_baton_t *tb = processor->baton; 1349 struct tee_node_baton_t *db = dir_baton; 1350 1351 SVN_ERR(tb->p1->dir_added(relpath, 1352 copyfrom_source, 1353 right_source, 1354 copyfrom_props, 1355 right_props, 1356 db->baton1, 1357 tb->p1, 1358 scratch_pool)); 1359 1360 SVN_ERR(tb->p2->dir_added(relpath, 1361 copyfrom_source, 1362 right_source, 1363 copyfrom_props, 1364 right_props, 1365 db->baton2, 1366 tb->p2, 1367 scratch_pool)); 1368 1369 return SVN_NO_ERROR; 1370} 1371 1372static svn_error_t * 1373tee_dir_deleted(const char *relpath, 1374 const svn_diff_source_t *left_source, 1375 /*const*/ apr_hash_t *left_props, 1376 void *dir_baton, 1377 const svn_diff_tree_processor_t *processor, 1378 apr_pool_t *scratch_pool) 1379{ 1380 struct tee_baton_t *tb = processor->baton; 1381 struct tee_node_baton_t *db = dir_baton; 1382 1383 SVN_ERR(tb->p1->dir_deleted(relpath, 1384 left_source, 1385 left_props, 1386 db->baton1, 1387 tb->p1, 1388 scratch_pool)); 1389 1390 SVN_ERR(tb->p2->dir_deleted(relpath, 1391 left_source, 1392 left_props, 1393 db->baton2, 1394 tb->p2, 1395 scratch_pool)); 1396 1397 return SVN_NO_ERROR; 1398} 1399 1400static svn_error_t * 1401tee_dir_changed(const char *relpath, 1402 const svn_diff_source_t *left_source, 1403 const svn_diff_source_t *right_source, 1404 /*const*/ apr_hash_t *left_props, 1405 /*const*/ apr_hash_t *right_props, 1406 const apr_array_header_t *prop_changes, 1407 void *dir_baton, 1408 const struct svn_diff_tree_processor_t *processor, 1409 apr_pool_t *scratch_pool) 1410{ 1411 struct tee_baton_t *tb = processor->baton; 1412 struct tee_node_baton_t *db = dir_baton; 1413 1414 SVN_ERR(tb->p1->dir_changed(relpath, 1415 left_source, 1416 right_source, 1417 left_props, 1418 right_props, 1419 prop_changes, 1420 db->baton1, 1421 tb->p1, 1422 scratch_pool)); 1423 1424 SVN_ERR(tb->p2->dir_changed(relpath, 1425 left_source, 1426 right_source, 1427 left_props, 1428 right_props, 1429 prop_changes, 1430 db->baton2, 1431 tb->p2, 1432 scratch_pool)); 1433 return SVN_NO_ERROR; 1434} 1435 1436static svn_error_t * 1437tee_dir_closed(const char *relpath, 1438 const svn_diff_source_t *left_source, 1439 const svn_diff_source_t *right_source, 1440 void *dir_baton, 1441 const svn_diff_tree_processor_t *processor, 1442 apr_pool_t *scratch_pool) 1443{ 1444 struct tee_baton_t *tb = processor->baton; 1445 struct tee_node_baton_t *db = dir_baton; 1446 1447 SVN_ERR(tb->p1->dir_closed(relpath, 1448 left_source, 1449 right_source, 1450 db->baton1, 1451 tb->p1, 1452 scratch_pool)); 1453 1454 SVN_ERR(tb->p2->dir_closed(relpath, 1455 left_source, 1456 right_source, 1457 db->baton2, 1458 tb->p2, 1459 scratch_pool)); 1460 return SVN_NO_ERROR; 1461} 1462 1463static svn_error_t * 1464tee_file_opened(void **new_file_baton, 1465 svn_boolean_t *skip, 1466 const char *relpath, 1467 const svn_diff_source_t *left_source, 1468 const svn_diff_source_t *right_source, 1469 const svn_diff_source_t *copyfrom_source, 1470 void *dir_baton, 1471 const svn_diff_tree_processor_t *processor, 1472 apr_pool_t *result_pool, 1473 apr_pool_t *scratch_pool) 1474{ 1475 struct tee_baton_t *tb = processor->baton; 1476 struct tee_node_baton_t *pb = dir_baton; 1477 struct tee_node_baton_t *nb = apr_pcalloc(result_pool, sizeof(*nb)); 1478 1479 SVN_ERR(tb->p1->file_opened(&(nb->baton1), 1480 skip, 1481 relpath, 1482 left_source, 1483 right_source, 1484 copyfrom_source, 1485 pb ? pb->baton1 : NULL, 1486 tb->p1, 1487 result_pool, 1488 scratch_pool)); 1489 1490 SVN_ERR(tb->p2->file_opened(&(nb->baton2), 1491 skip, 1492 relpath, 1493 left_source, 1494 right_source, 1495 copyfrom_source, 1496 pb ? pb->baton2 : NULL, 1497 tb->p2, 1498 result_pool, 1499 scratch_pool)); 1500 1501 *new_file_baton = nb; 1502 1503 return SVN_NO_ERROR; 1504} 1505 1506static svn_error_t * 1507tee_file_added(const char *relpath, 1508 const svn_diff_source_t *copyfrom_source, 1509 const svn_diff_source_t *right_source, 1510 const char *copyfrom_file, 1511 const char *right_file, 1512 /*const*/ apr_hash_t *copyfrom_props, 1513 /*const*/ apr_hash_t *right_props, 1514 void *file_baton, 1515 const svn_diff_tree_processor_t *processor, 1516 apr_pool_t *scratch_pool) 1517{ 1518 struct tee_baton_t *tb = processor->baton; 1519 struct tee_node_baton_t *fb = file_baton; 1520 1521 SVN_ERR(tb->p1->file_added(relpath, 1522 copyfrom_source, 1523 right_source, 1524 copyfrom_file, 1525 right_file, 1526 copyfrom_props, 1527 right_props, 1528 fb->baton1, 1529 tb->p1, 1530 scratch_pool)); 1531 1532 SVN_ERR(tb->p2->file_added(relpath, 1533 copyfrom_source, 1534 right_source, 1535 copyfrom_file, 1536 right_file, 1537 copyfrom_props, 1538 right_props, 1539 fb->baton2, 1540 tb->p2, 1541 scratch_pool)); 1542 return SVN_NO_ERROR; 1543} 1544 1545static svn_error_t * 1546tee_file_deleted(const char *relpath, 1547 const svn_diff_source_t *left_source, 1548 const char *left_file, 1549 /*const*/ apr_hash_t *left_props, 1550 void *file_baton, 1551 const svn_diff_tree_processor_t *processor, 1552 apr_pool_t *scratch_pool) 1553{ 1554 struct tee_baton_t *tb = processor->baton; 1555 struct tee_node_baton_t *fb = file_baton; 1556 1557 SVN_ERR(tb->p1->file_deleted(relpath, 1558 left_source, 1559 left_file, 1560 left_props, 1561 fb->baton1, 1562 tb->p1, 1563 scratch_pool)); 1564 1565 SVN_ERR(tb->p2->file_deleted(relpath, 1566 left_source, 1567 left_file, 1568 left_props, 1569 fb->baton2, 1570 tb->p2, 1571 scratch_pool)); 1572 return SVN_NO_ERROR; 1573} 1574 1575static svn_error_t * 1576tee_file_changed(const char *relpath, 1577 const svn_diff_source_t *left_source, 1578 const svn_diff_source_t *right_source, 1579 const char *left_file, 1580 const char *right_file, 1581 /*const*/ apr_hash_t *left_props, 1582 /*const*/ apr_hash_t *right_props, 1583 svn_boolean_t file_modified, 1584 const apr_array_header_t *prop_changes, 1585 void *file_baton, 1586 const svn_diff_tree_processor_t *processor, 1587 apr_pool_t *scratch_pool) 1588{ 1589 struct tee_baton_t *tb = processor->baton; 1590 struct tee_node_baton_t *fb = file_baton; 1591 1592 SVN_ERR(tb->p1->file_changed(relpath, 1593 left_source, 1594 right_source, 1595 left_file, 1596 right_file, 1597 left_props, 1598 right_props, 1599 file_modified, 1600 prop_changes, 1601 fb->baton1, 1602 tb->p1, 1603 scratch_pool)); 1604 1605 SVN_ERR(tb->p2->file_changed(relpath, 1606 left_source, 1607 right_source, 1608 left_file, 1609 right_file, 1610 left_props, 1611 right_props, 1612 file_modified, 1613 prop_changes, 1614 fb->baton2, 1615 tb->p2, 1616 scratch_pool)); 1617 return SVN_NO_ERROR; 1618} 1619 1620static svn_error_t * 1621tee_file_closed(const char *relpath, 1622 const svn_diff_source_t *left_source, 1623 const svn_diff_source_t *right_source, 1624 void *file_baton, 1625 const svn_diff_tree_processor_t *processor, 1626 apr_pool_t *scratch_pool) 1627{ 1628 struct tee_baton_t *tb = processor->baton; 1629 struct tee_node_baton_t *fb = file_baton; 1630 1631 SVN_ERR(tb->p1->file_closed(relpath, 1632 left_source, 1633 right_source, 1634 fb->baton1, 1635 tb->p1, 1636 scratch_pool)); 1637 1638 SVN_ERR(tb->p2->file_closed(relpath, 1639 left_source, 1640 right_source, 1641 fb->baton2, 1642 tb->p2, 1643 scratch_pool)); 1644 1645 return SVN_NO_ERROR; 1646} 1647 1648static svn_error_t * 1649tee_node_absent(const char *relpath, 1650 void *dir_baton, 1651 const svn_diff_tree_processor_t *processor, 1652 apr_pool_t *scratch_pool) 1653{ 1654 struct tee_baton_t *tb = processor->baton; 1655 struct tee_node_baton_t *db = dir_baton; 1656 1657 SVN_ERR(tb->p1->node_absent(relpath, 1658 db ? db->baton1 : NULL, 1659 tb->p1, 1660 scratch_pool)); 1661 1662 SVN_ERR(tb->p2->node_absent(relpath, 1663 db ? db->baton2 : NULL, 1664 tb->p2, 1665 scratch_pool)); 1666 1667 return SVN_NO_ERROR; 1668} 1669 1670const svn_diff_tree_processor_t * 1671svn_diff__tree_processor_tee_create(const svn_diff_tree_processor_t *processor1, 1672 const svn_diff_tree_processor_t *processor2, 1673 apr_pool_t *result_pool) 1674{ 1675 struct tee_baton_t *tb = apr_pcalloc(result_pool, sizeof(*tb)); 1676 svn_diff_tree_processor_t *tee; 1677 tb->p1 = processor1; 1678 tb->p2 = processor2; 1679 1680 tee = svn_diff__tree_processor_create(tb, result_pool); 1681 1682 tee->dir_opened = tee_dir_opened; 1683 tee->dir_added = tee_dir_added; 1684 tee->dir_deleted = tee_dir_deleted; 1685 tee->dir_changed = tee_dir_changed; 1686 tee->dir_closed = tee_dir_closed; 1687 tee->file_opened = tee_file_opened; 1688 tee->file_added = tee_file_added; 1689 tee->file_deleted = tee_file_deleted; 1690 tee->file_changed = tee_file_changed; 1691 tee->file_closed = tee_file_closed; 1692 tee->node_absent = tee_node_absent; 1693 1694 return tee; 1695} 1696 1697svn_diff_source_t * 1698svn_diff__source_create(svn_revnum_t revision, 1699 apr_pool_t *result_pool) 1700{ 1701 svn_diff_source_t *src = apr_pcalloc(result_pool, sizeof(*src)); 1702 1703 src->revision = revision; 1704 return src; 1705} 1706