1 /*
2 * debug_editor.c : An editor that writes the operations it does to stderr.
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 "svn_io.h"
25
26 #include "private/svn_delta_private.h"
27
28 struct edit_baton
29 {
30 const svn_delta_editor_t *wrapped_editor;
31 void *wrapped_edit_baton;
32
33 int indent_level;
34
35 svn_stream_t *out;
36 const char *prefix;
37 };
38
39 struct dir_baton
40 {
41 void *edit_baton;
42 void *wrapped_dir_baton;
43 };
44
45 struct file_baton
46 {
47 void *edit_baton;
48 void *wrapped_file_baton;
49 };
50
51 static svn_error_t *
write_indent(struct edit_baton * eb,apr_pool_t * pool)52 write_indent(struct edit_baton *eb, apr_pool_t *pool)
53 {
54 int i;
55
56 SVN_ERR(svn_stream_puts(eb->out, eb->prefix));
57 for (i = 0; i < eb->indent_level; ++i)
58 SVN_ERR(svn_stream_puts(eb->out, " "));
59
60 return SVN_NO_ERROR;
61 }
62
63 static svn_error_t *
set_target_revision(void * edit_baton,svn_revnum_t target_revision,apr_pool_t * pool)64 set_target_revision(void *edit_baton,
65 svn_revnum_t target_revision,
66 apr_pool_t *pool)
67 {
68 struct edit_baton *eb = edit_baton;
69
70 SVN_ERR(write_indent(eb, pool));
71 SVN_ERR(svn_stream_printf(eb->out, pool, "set_target_revision : %ld\n",
72 target_revision));
73
74 if (eb->wrapped_editor)
75 SVN_ERR(eb->wrapped_editor->set_target_revision(eb->wrapped_edit_baton,
76 target_revision,
77 pool));
78 return SVN_NO_ERROR;
79 }
80
81 static svn_error_t *
open_root(void * edit_baton,svn_revnum_t base_revision,apr_pool_t * pool,void ** root_baton)82 open_root(void *edit_baton,
83 svn_revnum_t base_revision,
84 apr_pool_t *pool,
85 void **root_baton)
86 {
87 struct edit_baton *eb = edit_baton;
88 struct dir_baton *dir_baton = apr_palloc(pool, sizeof(*dir_baton));
89
90 SVN_ERR(write_indent(eb, pool));
91 SVN_ERR(svn_stream_printf(eb->out, pool, "open_root : %ld\n",
92 base_revision));
93 eb->indent_level++;
94
95 if (eb->wrapped_editor)
96 SVN_ERR(eb->wrapped_editor->open_root(eb->wrapped_edit_baton,
97 base_revision,
98 pool,
99 &dir_baton->wrapped_dir_baton));
100
101 dir_baton->edit_baton = edit_baton;
102
103 *root_baton = dir_baton;
104
105 return SVN_NO_ERROR;
106 }
107
108 static svn_error_t *
delete_entry(const char * path,svn_revnum_t base_revision,void * parent_baton,apr_pool_t * pool)109 delete_entry(const char *path,
110 svn_revnum_t base_revision,
111 void *parent_baton,
112 apr_pool_t *pool)
113 {
114 struct dir_baton *pb = parent_baton;
115 struct edit_baton *eb = pb->edit_baton;
116
117 SVN_ERR(write_indent(eb, pool));
118 SVN_ERR(svn_stream_printf(eb->out, pool, "delete_entry : %s:%ld\n",
119 path, base_revision));
120
121 if (eb->wrapped_editor)
122 SVN_ERR(eb->wrapped_editor->delete_entry(path,
123 base_revision,
124 pb->wrapped_dir_baton,
125 pool));
126 return SVN_NO_ERROR;
127 }
128
129 static svn_error_t *
add_directory(const char * path,void * parent_baton,const char * copyfrom_path,svn_revnum_t copyfrom_revision,apr_pool_t * pool,void ** child_baton)130 add_directory(const char *path,
131 void *parent_baton,
132 const char *copyfrom_path,
133 svn_revnum_t copyfrom_revision,
134 apr_pool_t *pool,
135 void **child_baton)
136 {
137 struct dir_baton *pb = parent_baton;
138 struct edit_baton *eb = pb->edit_baton;
139 struct dir_baton *b = apr_palloc(pool, sizeof(*b));
140
141 SVN_ERR(write_indent(eb, pool));
142 SVN_ERR(svn_stream_printf(eb->out, pool,
143 "add_directory : '%s' [from '%s':%ld]\n",
144 path, copyfrom_path, copyfrom_revision));
145 eb->indent_level++;
146
147 if (eb->wrapped_editor)
148 SVN_ERR(eb->wrapped_editor->add_directory(path,
149 pb->wrapped_dir_baton,
150 copyfrom_path,
151 copyfrom_revision,
152 pool,
153 &b->wrapped_dir_baton));
154
155 b->edit_baton = eb;
156 *child_baton = b;
157
158 return SVN_NO_ERROR;
159 }
160
161 static svn_error_t *
open_directory(const char * path,void * parent_baton,svn_revnum_t base_revision,apr_pool_t * pool,void ** child_baton)162 open_directory(const char *path,
163 void *parent_baton,
164 svn_revnum_t base_revision,
165 apr_pool_t *pool,
166 void **child_baton)
167 {
168 struct dir_baton *pb = parent_baton;
169 struct edit_baton *eb = pb->edit_baton;
170 struct dir_baton *db = apr_palloc(pool, sizeof(*db));
171
172 SVN_ERR(write_indent(eb, pool));
173 SVN_ERR(svn_stream_printf(eb->out, pool, "open_directory : '%s':%ld\n",
174 path, base_revision));
175 eb->indent_level++;
176
177 if (eb->wrapped_editor)
178 SVN_ERR(eb->wrapped_editor->open_directory(path,
179 pb->wrapped_dir_baton,
180 base_revision,
181 pool,
182 &db->wrapped_dir_baton));
183
184 db->edit_baton = eb;
185 *child_baton = db;
186
187 return SVN_NO_ERROR;
188 }
189
190 static svn_error_t *
add_file(const char * path,void * parent_baton,const char * copyfrom_path,svn_revnum_t copyfrom_revision,apr_pool_t * pool,void ** file_baton)191 add_file(const char *path,
192 void *parent_baton,
193 const char *copyfrom_path,
194 svn_revnum_t copyfrom_revision,
195 apr_pool_t *pool,
196 void **file_baton)
197 {
198 struct dir_baton *pb = parent_baton;
199 struct edit_baton *eb = pb->edit_baton;
200 struct file_baton *fb = apr_palloc(pool, sizeof(*fb));
201
202 SVN_ERR(write_indent(eb, pool));
203 SVN_ERR(svn_stream_printf(eb->out, pool,
204 "add_file : '%s' [from '%s':%ld]\n",
205 path, copyfrom_path, copyfrom_revision));
206
207 eb->indent_level++;
208
209 if (eb->wrapped_editor)
210 SVN_ERR(eb->wrapped_editor->add_file(path,
211 pb->wrapped_dir_baton,
212 copyfrom_path,
213 copyfrom_revision,
214 pool,
215 &fb->wrapped_file_baton));
216
217 fb->edit_baton = eb;
218 *file_baton = fb;
219
220 return SVN_NO_ERROR;
221 }
222
223 static svn_error_t *
open_file(const char * path,void * parent_baton,svn_revnum_t base_revision,apr_pool_t * pool,void ** file_baton)224 open_file(const char *path,
225 void *parent_baton,
226 svn_revnum_t base_revision,
227 apr_pool_t *pool,
228 void **file_baton)
229 {
230 struct dir_baton *pb = parent_baton;
231 struct edit_baton *eb = pb->edit_baton;
232 struct file_baton *fb = apr_palloc(pool, sizeof(*fb));
233
234 SVN_ERR(write_indent(eb, pool));
235 SVN_ERR(svn_stream_printf(eb->out, pool, "open_file : '%s':%ld\n",
236 path, base_revision));
237
238 eb->indent_level++;
239
240 if (eb->wrapped_editor)
241 SVN_ERR(eb->wrapped_editor->open_file(path,
242 pb->wrapped_dir_baton,
243 base_revision,
244 pool,
245 &fb->wrapped_file_baton));
246
247 fb->edit_baton = eb;
248 *file_baton = fb;
249
250 return SVN_NO_ERROR;
251 }
252
253 static svn_error_t *
apply_textdelta(void * file_baton,const char * base_checksum,apr_pool_t * pool,svn_txdelta_window_handler_t * handler,void ** handler_baton)254 apply_textdelta(void *file_baton,
255 const char *base_checksum,
256 apr_pool_t *pool,
257 svn_txdelta_window_handler_t *handler,
258 void **handler_baton)
259 {
260 struct file_baton *fb = file_baton;
261 struct edit_baton *eb = fb->edit_baton;
262
263 SVN_ERR(write_indent(eb, pool));
264 SVN_ERR(svn_stream_printf(eb->out, pool, "apply_textdelta : %s\n",
265 base_checksum));
266
267 if (eb->wrapped_editor)
268 SVN_ERR(eb->wrapped_editor->apply_textdelta(fb->wrapped_file_baton,
269 base_checksum,
270 pool,
271 handler,
272 handler_baton));
273
274 return SVN_NO_ERROR;
275 }
276
277 static svn_error_t *
apply_textdelta_stream(const struct svn_delta_editor_t * editor,void * file_baton,const char * base_checksum,svn_txdelta_stream_open_func_t open_func,void * open_baton,apr_pool_t * scratch_pool)278 apply_textdelta_stream(const struct svn_delta_editor_t *editor,
279 void *file_baton,
280 const char *base_checksum,
281 svn_txdelta_stream_open_func_t open_func,
282 void *open_baton,
283 apr_pool_t *scratch_pool)
284 {
285 struct file_baton *fb = file_baton;
286 struct edit_baton *eb = fb->edit_baton;
287
288 SVN_ERR(write_indent(eb, scratch_pool));
289 SVN_ERR(svn_stream_printf(eb->out, scratch_pool,
290 "apply_textdelta_stream : %s\n",
291 base_checksum));
292
293 if (eb->wrapped_editor)
294 SVN_ERR(eb->wrapped_editor->apply_textdelta_stream(eb->wrapped_editor,
295 fb->wrapped_file_baton,
296 base_checksum,
297 open_func, open_baton,
298 scratch_pool));
299
300 return SVN_NO_ERROR;
301 }
302
303 static svn_error_t *
close_file(void * file_baton,const char * text_checksum,apr_pool_t * pool)304 close_file(void *file_baton,
305 const char *text_checksum,
306 apr_pool_t *pool)
307 {
308 struct file_baton *fb = file_baton;
309 struct edit_baton *eb = fb->edit_baton;
310
311 eb->indent_level--;
312
313 SVN_ERR(write_indent(eb, pool));
314 SVN_ERR(svn_stream_printf(eb->out, pool, "close_file : %s\n",
315 text_checksum));
316
317 if (eb->wrapped_editor)
318 SVN_ERR(eb->wrapped_editor->close_file(fb->wrapped_file_baton,
319 text_checksum, pool));
320
321 return SVN_NO_ERROR;
322 }
323
324 static svn_error_t *
absent_file(const char * path,void * file_baton,apr_pool_t * pool)325 absent_file(const char *path,
326 void *file_baton,
327 apr_pool_t *pool)
328 {
329 struct file_baton *fb = file_baton;
330 struct edit_baton *eb = fb->edit_baton;
331
332 SVN_ERR(write_indent(eb, pool));
333 SVN_ERR(svn_stream_printf(eb->out, pool, "absent_file : %s\n", path));
334
335 if (eb->wrapped_editor)
336 SVN_ERR(eb->wrapped_editor->absent_file(path, fb->wrapped_file_baton,
337 pool));
338
339 return SVN_NO_ERROR;
340 }
341
342 static svn_error_t *
close_directory(void * dir_baton,apr_pool_t * pool)343 close_directory(void *dir_baton,
344 apr_pool_t *pool)
345 {
346 struct dir_baton *db = dir_baton;
347 struct edit_baton *eb = db->edit_baton;
348
349 eb->indent_level--;
350 SVN_ERR(write_indent(eb, pool));
351 SVN_ERR(svn_stream_printf(eb->out, pool, "close_directory\n"));
352
353 if (eb->wrapped_editor)
354 SVN_ERR(eb->wrapped_editor->close_directory(db->wrapped_dir_baton,
355 pool));
356
357 return SVN_NO_ERROR;
358 }
359
360 static svn_error_t *
absent_directory(const char * path,void * dir_baton,apr_pool_t * pool)361 absent_directory(const char *path,
362 void *dir_baton,
363 apr_pool_t *pool)
364 {
365 struct dir_baton *db = dir_baton;
366 struct edit_baton *eb = db->edit_baton;
367
368 SVN_ERR(write_indent(eb, pool));
369 SVN_ERR(svn_stream_printf(eb->out, pool, "absent_directory : %s\n",
370 path));
371
372 if (eb->wrapped_editor)
373 SVN_ERR(eb->wrapped_editor->absent_directory(path, db->wrapped_dir_baton,
374 pool));
375
376 return SVN_NO_ERROR;
377 }
378
379 static svn_error_t *
change_file_prop(void * file_baton,const char * name,const svn_string_t * value,apr_pool_t * pool)380 change_file_prop(void *file_baton,
381 const char *name,
382 const svn_string_t *value,
383 apr_pool_t *pool)
384 {
385 struct file_baton *fb = file_baton;
386 struct edit_baton *eb = fb->edit_baton;
387
388 SVN_ERR(write_indent(eb, pool));
389 SVN_ERR(svn_stream_printf(eb->out, pool, "change_file_prop : %s -> %s\n",
390 name, value ? value->data : "<deleted>"));
391
392 if (eb->wrapped_editor)
393 SVN_ERR(eb->wrapped_editor->change_file_prop(fb->wrapped_file_baton,
394 name,
395 value,
396 pool));
397
398 return SVN_NO_ERROR;
399 }
400
401 static svn_error_t *
change_dir_prop(void * dir_baton,const char * name,const svn_string_t * value,apr_pool_t * pool)402 change_dir_prop(void *dir_baton,
403 const char *name,
404 const svn_string_t *value,
405 apr_pool_t *pool)
406 {
407 struct dir_baton *db = dir_baton;
408 struct edit_baton *eb = db->edit_baton;
409
410 SVN_ERR(write_indent(eb, pool));
411 SVN_ERR(svn_stream_printf(eb->out, pool, "change_dir_prop : %s -> %s\n",
412 name, value ? value->data : "<deleted>"));
413
414 if (eb->wrapped_editor)
415 SVN_ERR(eb->wrapped_editor->change_dir_prop(db->wrapped_dir_baton,
416 name,
417 value,
418 pool));
419
420 return SVN_NO_ERROR;
421 }
422
423 static svn_error_t *
close_edit(void * edit_baton,apr_pool_t * pool)424 close_edit(void *edit_baton,
425 apr_pool_t *pool)
426 {
427 struct edit_baton *eb = edit_baton;
428
429 SVN_ERR(write_indent(eb, pool));
430 SVN_ERR(svn_stream_printf(eb->out, pool, "close_edit\n"));
431
432 if (eb->wrapped_editor)
433 SVN_ERR(eb->wrapped_editor->close_edit(eb->wrapped_edit_baton, pool));
434
435 return SVN_NO_ERROR;
436 }
437
438 static svn_error_t *
abort_edit(void * edit_baton,apr_pool_t * pool)439 abort_edit(void *edit_baton,
440 apr_pool_t *pool)
441 {
442 struct edit_baton *eb = edit_baton;
443
444 SVN_ERR(write_indent(eb, pool));
445 SVN_ERR(svn_stream_printf(eb->out, pool, "abort_edit\n"));
446
447 if (eb->wrapped_editor)
448 SVN_ERR(eb->wrapped_editor->abort_edit(eb->wrapped_edit_baton, pool));
449
450 return SVN_NO_ERROR;
451 }
452
453 svn_error_t *
svn_delta__get_debug_editor(const svn_delta_editor_t ** editor,void ** edit_baton,const svn_delta_editor_t * wrapped_editor,void * wrapped_edit_baton,const char * prefix,apr_pool_t * pool)454 svn_delta__get_debug_editor(const svn_delta_editor_t **editor,
455 void **edit_baton,
456 const svn_delta_editor_t *wrapped_editor,
457 void *wrapped_edit_baton,
458 const char *prefix,
459 apr_pool_t *pool)
460 {
461 svn_delta_editor_t *tree_editor = svn_delta_default_editor(pool);
462 struct edit_baton *eb = apr_palloc(pool, sizeof(*eb));
463 apr_file_t *errfp;
464 svn_stream_t *out;
465
466 apr_status_t apr_err = apr_file_open_stdout(&errfp, pool);
467 if (apr_err)
468 return svn_error_wrap_apr(apr_err, "Problem opening stderr");
469
470 out = svn_stream_from_aprfile2(errfp, TRUE, pool);
471
472 tree_editor->set_target_revision = set_target_revision;
473 tree_editor->open_root = open_root;
474 tree_editor->delete_entry = delete_entry;
475 tree_editor->add_directory = add_directory;
476 tree_editor->open_directory = open_directory;
477 tree_editor->change_dir_prop = change_dir_prop;
478 tree_editor->close_directory = close_directory;
479 tree_editor->absent_directory = absent_directory;
480 tree_editor->add_file = add_file;
481 tree_editor->open_file = open_file;
482 tree_editor->apply_textdelta = apply_textdelta;
483 tree_editor->apply_textdelta_stream = apply_textdelta_stream;
484 tree_editor->change_file_prop = change_file_prop;
485 tree_editor->close_file = close_file;
486 tree_editor->absent_file = absent_file;
487 tree_editor->close_edit = close_edit;
488 tree_editor->abort_edit = abort_edit;
489
490 eb->wrapped_editor = wrapped_editor;
491 eb->wrapped_edit_baton = wrapped_edit_baton;
492 eb->out = out;
493 eb->indent_level = 0;
494 /* This is DBG_FLAG from ../libsvn_subr/debug.c */
495 eb->prefix = apr_pstrcat(pool, "DBG: ", prefix, SVN_VA_NULL);
496
497 *editor = tree_editor;
498 *edit_baton = eb;
499
500 return SVN_NO_ERROR;
501 }
502