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