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
40 typedef struct tree_processor_t
41 {
42 svn_diff_tree_processor_t tp;
43
44 /* void *future_extension */
45 } tree_processor_t;
46
47
48 static svn_error_t *
default_dir_opened(void ** new_dir_baton,svn_boolean_t * skip,svn_boolean_t * skip_children,const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const svn_diff_source_t * copyfrom_source,void * parent_dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * result_pool,apr_pool_t * scratch_pool)49 default_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
65 static svn_error_t *
default_dir_added(const char * relpath,const svn_diff_source_t * copyfrom_source,const svn_diff_source_t * right_source,apr_hash_t * copyfrom_props,apr_hash_t * right_props,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)66 default_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
82 static svn_error_t *
default_dir_deleted(const char * relpath,const svn_diff_source_t * left_source,apr_hash_t * left_props,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)83 default_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
96 static svn_error_t *
default_dir_changed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,apr_hash_t * left_props,apr_hash_t * right_props,const apr_array_header_t * prop_changes,void * dir_baton,const struct svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)97 default_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
114 static svn_error_t *
default_dir_closed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)115 default_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
125 static svn_error_t *
default_file_opened(void ** new_file_baton,svn_boolean_t * skip,const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const svn_diff_source_t * copyfrom_source,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * result_pool,apr_pool_t * scratch_pool)126 default_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
141 static svn_error_t *
default_file_added(const char * relpath,const svn_diff_source_t * copyfrom_source,const svn_diff_source_t * right_source,const char * copyfrom_file,const char * right_file,apr_hash_t * copyfrom_props,apr_hash_t * right_props,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)142 default_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
159 static svn_error_t *
default_file_deleted(const char * relpath,const svn_diff_source_t * left_source,const char * left_file,apr_hash_t * left_props,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)160 default_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
174 static svn_error_t *
default_file_changed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const char * left_file,const char * right_file,apr_hash_t * left_props,apr_hash_t * right_props,svn_boolean_t file_modified,const apr_array_header_t * prop_changes,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)175 default_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
194 static svn_error_t *
default_file_closed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)195 default_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
205 static svn_error_t *
default_node_absent(const char * relpath,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)206 default_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
214 svn_diff_tree_processor_t *
svn_diff__tree_processor_create(void * baton,apr_pool_t * result_pool)215 svn_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
241 struct reverse_tree_baton_t
242 {
243 const svn_diff_tree_processor_t *processor;
244 const char *prefix_relpath;
245 };
246
247 static svn_error_t *
reverse_dir_opened(void ** new_dir_baton,svn_boolean_t * skip,svn_boolean_t * skip_children,const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const svn_diff_source_t * copyfrom_source,void * parent_dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * result_pool,apr_pool_t * scratch_pool)248 reverse_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
275 static svn_error_t *
reverse_dir_added(const char * relpath,const svn_diff_source_t * copyfrom_source,const svn_diff_source_t * right_source,apr_hash_t * copyfrom_props,apr_hash_t * right_props,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)276 reverse_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
300 static svn_error_t *
reverse_dir_deleted(const char * relpath,const svn_diff_source_t * left_source,apr_hash_t * left_props,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)301 reverse_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
324 static svn_error_t *
reverse_dir_changed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,apr_hash_t * left_props,apr_hash_t * right_props,const apr_array_header_t * prop_changes,void * dir_baton,const struct svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)325 reverse_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
360 static svn_error_t *
reverse_dir_closed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)361 reverse_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
382 static svn_error_t *
reverse_file_opened(void ** new_file_baton,svn_boolean_t * skip,const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const svn_diff_source_t * copyfrom_source,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * result_pool,apr_pool_t * scratch_pool)383 reverse_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
412 static svn_error_t *
reverse_file_added(const char * relpath,const svn_diff_source_t * copyfrom_source,const svn_diff_source_t * right_source,const char * copyfrom_file,const char * right_file,apr_hash_t * copyfrom_props,apr_hash_t * right_props,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)413 reverse_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
439 static svn_error_t *
reverse_file_deleted(const char * relpath,const svn_diff_source_t * left_source,const char * left_file,apr_hash_t * left_props,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)440 reverse_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
466 static svn_error_t *
reverse_file_changed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const char * left_file,const char * right_file,apr_hash_t * left_props,apr_hash_t * right_props,svn_boolean_t file_modified,const apr_array_header_t * prop_changes,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)467 reverse_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
508 static svn_error_t *
reverse_file_closed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)509 reverse_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
531 static svn_error_t *
reverse_node_absent(const char * relpath,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)532 reverse_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
550 const svn_diff_tree_processor_t *
svn_diff__tree_processor_reverse_create(const svn_diff_tree_processor_t * processor,const char * prefix_relpath,apr_pool_t * result_pool)551 svn_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
582 struct filter_tree_baton_t
583 {
584 const svn_diff_tree_processor_t *processor;
585 const char *prefix_relpath;
586 };
587
588 static svn_error_t *
filter_dir_opened(void ** new_dir_baton,svn_boolean_t * skip,svn_boolean_t * skip_children,const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const svn_diff_source_t * copyfrom_source,void * parent_dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * result_pool,apr_pool_t * scratch_pool)589 filter_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
622 static svn_error_t *
filter_dir_added(const char * relpath,const svn_diff_source_t * copyfrom_source,const svn_diff_source_t * right_source,apr_hash_t * copyfrom_props,apr_hash_t * right_props,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)623 filter_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
649 static svn_error_t *
filter_dir_deleted(const char * relpath,const svn_diff_source_t * left_source,apr_hash_t * left_props,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)650 filter_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
672 static svn_error_t *
filter_dir_changed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,apr_hash_t * left_props,apr_hash_t * right_props,const apr_array_header_t * prop_changes,void * dir_baton,const struct svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)673 filter_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
700 static svn_error_t *
filter_dir_closed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)701 filter_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
722 static svn_error_t *
filter_file_opened(void ** new_file_baton,svn_boolean_t * skip,const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const svn_diff_source_t * copyfrom_source,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * result_pool,apr_pool_t * scratch_pool)723 filter_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
757 static svn_error_t *
filter_file_added(const char * relpath,const svn_diff_source_t * copyfrom_source,const svn_diff_source_t * right_source,const char * copyfrom_file,const char * right_file,apr_hash_t * copyfrom_props,apr_hash_t * right_props,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)758 filter_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
787 static svn_error_t *
filter_file_deleted(const char * relpath,const svn_diff_source_t * left_source,const char * left_file,apr_hash_t * left_props,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)788 filter_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
812 static svn_error_t *
filter_file_changed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const char * left_file,const char * right_file,apr_hash_t * left_props,apr_hash_t * right_props,svn_boolean_t file_modified,const apr_array_header_t * prop_changes,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)813 filter_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
846 static svn_error_t *
filter_file_closed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)847 filter_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
869 static svn_error_t *
filter_node_absent(const char * relpath,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)870 filter_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
888 const svn_diff_tree_processor_t *
svn_diff__tree_processor_filter_create(const svn_diff_tree_processor_t * processor,const char * prefix_relpath,apr_pool_t * result_pool)889 svn_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
920 struct copy_as_changed_baton_t
921 {
922 const svn_diff_tree_processor_t *processor;
923 };
924
925 static svn_error_t *
copy_as_changed_dir_opened(void ** new_dir_baton,svn_boolean_t * skip,svn_boolean_t * skip_children,const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const svn_diff_source_t * copyfrom_source,void * parent_dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * result_pool,apr_pool_t * scratch_pool)926 copy_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
958 static svn_error_t *
copy_as_changed_dir_added(const char * relpath,const svn_diff_source_t * copyfrom_source,const svn_diff_source_t * right_source,apr_hash_t * copyfrom_props,apr_hash_t * right_props,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)959 copy_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
1000 static svn_error_t *
copy_as_changed_dir_deleted(const char * relpath,const svn_diff_source_t * left_source,apr_hash_t * left_props,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1001 copy_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
1020 static svn_error_t *
copy_as_changed_dir_changed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,apr_hash_t * left_props,apr_hash_t * right_props,const apr_array_header_t * prop_changes,void * dir_baton,const struct svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1021 copy_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
1045 static svn_error_t *
copy_as_changed_dir_closed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1046 copy_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
1064 static svn_error_t *
copy_as_changed_file_opened(void ** new_file_baton,svn_boolean_t * skip,const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const svn_diff_source_t * copyfrom_source,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * result_pool,apr_pool_t * scratch_pool)1065 copy_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
1099 static svn_error_t *
copy_as_changed_file_added(const char * relpath,const svn_diff_source_t * copyfrom_source,const svn_diff_source_t * right_source,const char * copyfrom_file,const char * right_file,apr_hash_t * copyfrom_props,apr_hash_t * right_props,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1100 copy_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
1159 static svn_error_t *
copy_as_changed_file_deleted(const char * relpath,const svn_diff_source_t * left_source,const char * left_file,apr_hash_t * left_props,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1160 copy_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
1181 static svn_error_t *
copy_as_changed_file_changed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const char * left_file,const char * right_file,apr_hash_t * left_props,apr_hash_t * right_props,svn_boolean_t file_modified,const apr_array_header_t * prop_changes,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1182 copy_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
1212 static svn_error_t *
copy_as_changed_file_closed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1213 copy_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
1232 static svn_error_t *
copy_as_changed_node_absent(const char * relpath,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1233 copy_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
1248 const svn_diff_tree_processor_t *
svn_diff__tree_processor_copy_as_changed_create(const svn_diff_tree_processor_t * processor,apr_pool_t * result_pool)1249 svn_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 */
1279 struct 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 */
1286 struct tee_node_baton_t
1287 {
1288 void *baton1;
1289 void *baton2;
1290 };
1291
1292 static svn_error_t *
tee_dir_opened(void ** new_dir_baton,svn_boolean_t * skip,svn_boolean_t * skip_children,const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const svn_diff_source_t * copyfrom_source,void * parent_dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * result_pool,apr_pool_t * scratch_pool)1293 tee_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
1338 static svn_error_t *
tee_dir_added(const char * relpath,const svn_diff_source_t * copyfrom_source,const svn_diff_source_t * right_source,apr_hash_t * copyfrom_props,apr_hash_t * right_props,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1339 tee_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
1372 static svn_error_t *
tee_dir_deleted(const char * relpath,const svn_diff_source_t * left_source,apr_hash_t * left_props,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1373 tee_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
1400 static svn_error_t *
tee_dir_changed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,apr_hash_t * left_props,apr_hash_t * right_props,const apr_array_header_t * prop_changes,void * dir_baton,const struct svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1401 tee_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
1436 static svn_error_t *
tee_dir_closed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1437 tee_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
1463 static svn_error_t *
tee_file_opened(void ** new_file_baton,svn_boolean_t * skip,const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const svn_diff_source_t * copyfrom_source,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * result_pool,apr_pool_t * scratch_pool)1464 tee_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
1506 static svn_error_t *
tee_file_added(const char * relpath,const svn_diff_source_t * copyfrom_source,const svn_diff_source_t * right_source,const char * copyfrom_file,const char * right_file,apr_hash_t * copyfrom_props,apr_hash_t * right_props,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1507 tee_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
1545 static svn_error_t *
tee_file_deleted(const char * relpath,const svn_diff_source_t * left_source,const char * left_file,apr_hash_t * left_props,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1546 tee_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
1575 static svn_error_t *
tee_file_changed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,const char * left_file,const char * right_file,apr_hash_t * left_props,apr_hash_t * right_props,svn_boolean_t file_modified,const apr_array_header_t * prop_changes,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1576 tee_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
1620 static svn_error_t *
tee_file_closed(const char * relpath,const svn_diff_source_t * left_source,const svn_diff_source_t * right_source,void * file_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1621 tee_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
1648 static svn_error_t *
tee_node_absent(const char * relpath,void * dir_baton,const svn_diff_tree_processor_t * processor,apr_pool_t * scratch_pool)1649 tee_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
1670 const svn_diff_tree_processor_t *
svn_diff__tree_processor_tee_create(const svn_diff_tree_processor_t * processor1,const svn_diff_tree_processor_t * processor2,apr_pool_t * result_pool)1671 svn_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
1697 svn_diff_source_t *
svn_diff__source_create(svn_revnum_t revision,apr_pool_t * result_pool)1698 svn_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