2 * editor.c : editing trees of versioned resources
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * ====================================================================
24 #include <apr_pools.h>
26 #include "svn_types.h"
27 #include "svn_error.h"
28 #include "svn_pools.h"
29 #include "svn_dirent_uri.h"
31 #include "private/svn_editor.h"
34 /* This enables runtime checks of the editor API constraints. This may
35 introduce additional memory and runtime overhead, and should not be used
38 ### Remove before release?
40 ### Disabled for now. If I call svn_editor_alter_directory(A) then
41 svn_editor_add_file(A/f) the latter fails on SHOULD_ALLOW_ADD.
42 If I modify svn_editor_alter_directory to MARK_ALLOW_ADD(child)
43 then if I call svn_editor_alter_directory(A) followed by
44 svn_editor_alter_directory(A/B/C) the latter fails on
45 VERIFY_PARENT_MAY_EXIST. */
47 #define ENABLE_ORDERING_CHECK
56 /* Standard cancellation function. Called before each callback. */
57 svn_cancel_func_t cancel_func;
60 /* Our callback functions match that of the set-many structure, so
62 svn_editor_cb_many_t funcs;
64 /* This pool is used as the scratch_pool for all callbacks. */
65 apr_pool_t *scratch_pool;
67 #ifdef ENABLE_ORDERING_CHECK
68 svn_boolean_t within_callback;
70 apr_hash_t *pending_incomplete_children;
71 apr_hash_t *completed_nodes;
72 svn_boolean_t finished;
74 apr_pool_t *state_pool;
79 #ifdef ENABLE_ORDERING_CHECK
81 #define START_CALLBACK(editor) \
83 svn_editor_t *editor__tmp_e = (editor); \
84 SVN_ERR_ASSERT(!editor__tmp_e->within_callback); \
85 editor__tmp_e->within_callback = TRUE; \
87 #define END_CALLBACK(editor) ((editor)->within_callback = FALSE)
89 /* Marker to indicate no further changes are allowed on this node. */
90 static const int marker_done = 0;
91 #define MARKER_DONE (&marker_done)
93 /* Marker indicating that add_* may be called for this path, or that it
94 can be the destination of a copy or move. For copy/move, the path
95 will switch to MARKER_ALLOW_ALTER, to enable further tweaks. */
96 static const int marker_allow_add = 0;
97 #define MARKER_ALLOW_ADD (&marker_allow_add)
99 /* Marker indicating that alter_* may be called for this path. */
100 static const int marker_allow_alter = 0;
101 #define MARKER_ALLOW_ALTER (&marker_allow_alter)
103 /* Just like MARKER_DONE, but also indicates that the node was created
104 via add_directory(). This allows us to verify that the CHILDREN param
105 was comprehensive. */
106 static const int marker_added_dir = 0;
107 #define MARKER_ADDED_DIR (&marker_added_dir)
109 #define MARK_FINISHED(editor) ((editor)->finished = TRUE)
110 #define SHOULD_NOT_BE_FINISHED(editor) SVN_ERR_ASSERT(!(editor)->finished)
112 #define CLEAR_INCOMPLETE(editor, relpath) \
113 svn_hash_sets((editor)->pending_incomplete_children, relpath, NULL);
115 #define MARK_RELPATH(editor, relpath, value) \
116 svn_hash_sets((editor)->completed_nodes, \
117 apr_pstrdup((editor)->state_pool, relpath), value)
119 #define MARK_COMPLETED(editor, relpath) \
120 MARK_RELPATH(editor, relpath, MARKER_DONE)
121 #define SHOULD_NOT_BE_COMPLETED(editor, relpath) \
122 SVN_ERR_ASSERT(svn_hash_gets((editor)->completed_nodes, relpath) == NULL)
124 #define MARK_ALLOW_ADD(editor, relpath) \
125 MARK_RELPATH(editor, relpath, MARKER_ALLOW_ADD)
126 #define SHOULD_ALLOW_ADD(editor, relpath) \
127 SVN_ERR_ASSERT(allow_either(editor, relpath, MARKER_ALLOW_ADD, NULL))
129 #define MARK_ALLOW_ALTER(editor, relpath) \
130 MARK_RELPATH(editor, relpath, MARKER_ALLOW_ALTER)
131 #define SHOULD_ALLOW_ALTER(editor, relpath) \
132 SVN_ERR_ASSERT(allow_either(editor, relpath, MARKER_ALLOW_ALTER, NULL))
134 #define MARK_ADDED_DIR(editor, relpath) \
135 MARK_RELPATH(editor, relpath, MARKER_ADDED_DIR)
136 #define CHECK_UNKNOWN_CHILD(editor, relpath) \
137 SVN_ERR_ASSERT(check_unknown_child(editor, relpath))
139 /* When a child is changed in some way, mark the parent directory as needing
140 to be "stable" (no future structural changes). IOW, only allow "alter" on
141 the parent. Prevents parent-add/delete/move after any child operation. */
142 #define MARK_PARENT_STABLE(editor, relpath) \
143 mark_parent_stable(editor, relpath)
145 /* If the parent is MARKER_ALLOW_ADD, then it has been moved-away, and we
146 know it does not exist. All other cases: it might exist. */
147 #define VERIFY_PARENT_MAY_EXIST(editor, relpath) \
148 SVN_ERR_ASSERT(svn_hash_gets((editor)->completed_nodes, \
149 svn_relpath_dirname(relpath, \
150 (editor)->scratch_pool)) \
153 /* If the parent is MARKER_ADDED_DIR, then we should not be deleting
154 children(*). If the parent is MARKER_ALLOW_ADD, then it has been
155 moved-away, so children cannot exist. That leaves MARKER_DONE,
156 MARKER_ALLOW_ALTER, and NULL as possible values. Just assert that
157 we didn't get either of the bad ones.
159 (*) if the child as added via add_*(), then it would have been marked
160 as completed and delete/move-away already test against completed nodes.
161 This test is to beware of trying to delete "children" that are not
162 actually (and can't possibly be) present. */
163 #define CHILD_DELETIONS_ALLOWED(editor, relpath) \
164 SVN_ERR_ASSERT(!allow_either(editor, \
165 svn_relpath_dirname(relpath, \
166 (editor)->scratch_pool), \
167 MARKER_ADDED_DIR, MARKER_ALLOW_ADD))
170 allow_either(const svn_editor_t *editor,
175 void *value = svn_hash_gets(editor->completed_nodes, relpath);
176 return value == marker1 || value == marker2;
180 check_unknown_child(const svn_editor_t *editor,
185 /* If we already know about the new child, then exit early. */
186 if (svn_hash_gets(editor->pending_incomplete_children, relpath) != NULL)
189 parent = svn_relpath_dirname(relpath, editor->scratch_pool);
191 /* Was this parent created via svn_editor_add_directory() ? */
192 if (svn_hash_gets(editor->completed_nodes, parent)
195 /* Whoops. This child should have been listed in that add call,
196 and placed into ->pending_incomplete_children. */
200 /* The parent was not added in this drive. */
205 mark_parent_stable(const svn_editor_t *editor,
208 const char *parent = svn_relpath_dirname(relpath, editor->scratch_pool);
209 const void *marker = svn_hash_gets(editor->completed_nodes, parent);
211 /* If RELPATH has already been marked (to disallow adds, or that it
212 has been fully-completed), then do nothing. */
213 if (marker == MARKER_ALLOW_ALTER
214 || marker == MARKER_DONE
215 || marker == MARKER_ADDED_DIR)
218 /* If the marker is MARKER_ALLOW_ADD, then that means the parent was
219 moved away. There is no way to work on a child. That should have
220 been tested before we got here by VERIFY_PARENT_MAY_EXIST(). */
221 SVN_ERR_ASSERT_NO_RETURN(marker != MARKER_ALLOW_ADD);
223 /* MARKER is NULL. Upgrade it to MARKER_ALLOW_ALTER. */
224 MARK_RELPATH(editor, parent, MARKER_ALLOW_ALTER);
229 /* Be wary with the definition of these macros so that we don't
230 end up with "statement with no effect" warnings. Obviously, this
231 depends upon particular usage, which is easy to verify. */
233 #define START_CALLBACK(editor) /* empty */
234 #define END_CALLBACK(editor) /* empty */
236 #define MARK_FINISHED(editor) /* empty */
237 #define SHOULD_NOT_BE_FINISHED(editor) /* empty */
239 #define CLEAR_INCOMPLETE(editor, relpath) /* empty */
241 #define MARK_COMPLETED(editor, relpath) /* empty */
242 #define SHOULD_NOT_BE_COMPLETED(editor, relpath) /* empty */
244 #define MARK_ALLOW_ADD(editor, relpath) /* empty */
245 #define SHOULD_ALLOW_ADD(editor, relpath) /* empty */
247 #define MARK_ALLOW_ALTER(editor, relpath) /* empty */
248 #define SHOULD_ALLOW_ALTER(editor, relpath) /* empty */
250 #define MARK_ADDED_DIR(editor, relpath) /* empty */
251 #define CHECK_UNKNOWN_CHILD(editor, relpath) /* empty */
253 #define MARK_PARENT_STABLE(editor, relpath) /* empty */
254 #define VERIFY_PARENT_MAY_EXIST(editor, relpath) /* empty */
255 #define CHILD_DELETIONS_ALLOWED(editor, relpath) /* empty */
257 #endif /* ENABLE_ORDERING_CHECK */
261 svn_editor_create(svn_editor_t **editor,
263 svn_cancel_func_t cancel_func,
265 apr_pool_t *result_pool,
266 apr_pool_t *scratch_pool)
268 *editor = apr_pcalloc(result_pool, sizeof(**editor));
270 (*editor)->baton = editor_baton;
271 (*editor)->cancel_func = cancel_func;
272 (*editor)->cancel_baton = cancel_baton;
273 (*editor)->scratch_pool = svn_pool_create(result_pool);
275 #ifdef ENABLE_ORDERING_CHECK
276 (*editor)->pending_incomplete_children = apr_hash_make(result_pool);
277 (*editor)->completed_nodes = apr_hash_make(result_pool);
278 (*editor)->finished = FALSE;
279 (*editor)->state_pool = result_pool;
287 svn_editor_get_baton(const svn_editor_t *editor)
289 return editor->baton;
294 svn_editor_setcb_add_directory(svn_editor_t *editor,
295 svn_editor_cb_add_directory_t callback,
296 apr_pool_t *scratch_pool)
298 editor->funcs.cb_add_directory = callback;
304 svn_editor_setcb_add_file(svn_editor_t *editor,
305 svn_editor_cb_add_file_t callback,
306 apr_pool_t *scratch_pool)
308 editor->funcs.cb_add_file = callback;
314 svn_editor_setcb_add_symlink(svn_editor_t *editor,
315 svn_editor_cb_add_symlink_t callback,
316 apr_pool_t *scratch_pool)
318 editor->funcs.cb_add_symlink = callback;
324 svn_editor_setcb_add_absent(svn_editor_t *editor,
325 svn_editor_cb_add_absent_t callback,
326 apr_pool_t *scratch_pool)
328 editor->funcs.cb_add_absent = callback;
334 svn_editor_setcb_alter_directory(svn_editor_t *editor,
335 svn_editor_cb_alter_directory_t callback,
336 apr_pool_t *scratch_pool)
338 editor->funcs.cb_alter_directory = callback;
344 svn_editor_setcb_alter_file(svn_editor_t *editor,
345 svn_editor_cb_alter_file_t callback,
346 apr_pool_t *scratch_pool)
348 editor->funcs.cb_alter_file = callback;
354 svn_editor_setcb_alter_symlink(svn_editor_t *editor,
355 svn_editor_cb_alter_symlink_t callback,
356 apr_pool_t *scratch_pool)
358 editor->funcs.cb_alter_symlink = callback;
364 svn_editor_setcb_delete(svn_editor_t *editor,
365 svn_editor_cb_delete_t callback,
366 apr_pool_t *scratch_pool)
368 editor->funcs.cb_delete = callback;
374 svn_editor_setcb_copy(svn_editor_t *editor,
375 svn_editor_cb_copy_t callback,
376 apr_pool_t *scratch_pool)
378 editor->funcs.cb_copy = callback;
384 svn_editor_setcb_move(svn_editor_t *editor,
385 svn_editor_cb_move_t callback,
386 apr_pool_t *scratch_pool)
388 editor->funcs.cb_move = callback;
394 svn_editor_setcb_rotate(svn_editor_t *editor,
395 svn_editor_cb_rotate_t callback,
396 apr_pool_t *scratch_pool)
398 editor->funcs.cb_rotate = callback;
404 svn_editor_setcb_complete(svn_editor_t *editor,
405 svn_editor_cb_complete_t callback,
406 apr_pool_t *scratch_pool)
408 editor->funcs.cb_complete = callback;
414 svn_editor_setcb_abort(svn_editor_t *editor,
415 svn_editor_cb_abort_t callback,
416 apr_pool_t *scratch_pool)
418 editor->funcs.cb_abort = callback;
424 svn_editor_setcb_many(svn_editor_t *editor,
425 const svn_editor_cb_many_t *many,
426 apr_pool_t *scratch_pool)
428 #define COPY_CALLBACK(NAME) if (many->NAME) editor->funcs.NAME = many->NAME
430 COPY_CALLBACK(cb_add_directory);
431 COPY_CALLBACK(cb_add_file);
432 COPY_CALLBACK(cb_add_symlink);
433 COPY_CALLBACK(cb_add_absent);
434 COPY_CALLBACK(cb_alter_directory);
435 COPY_CALLBACK(cb_alter_file);
436 COPY_CALLBACK(cb_alter_symlink);
437 COPY_CALLBACK(cb_delete);
438 COPY_CALLBACK(cb_copy);
439 COPY_CALLBACK(cb_move);
440 COPY_CALLBACK(cb_rotate);
441 COPY_CALLBACK(cb_complete);
442 COPY_CALLBACK(cb_abort);
451 check_cancel(svn_editor_t *editor)
453 svn_error_t *err = NULL;
455 if (editor->cancel_func)
457 START_CALLBACK(editor);
458 err = editor->cancel_func(editor->cancel_baton);
459 END_CALLBACK(editor);
462 return svn_error_trace(err);
467 svn_editor_add_directory(svn_editor_t *editor,
469 const apr_array_header_t *children,
471 svn_revnum_t replaces_rev)
473 svn_error_t *err = SVN_NO_ERROR;
475 SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
476 SVN_ERR_ASSERT(children != NULL);
477 SVN_ERR_ASSERT(props != NULL);
478 /* ### validate children are just basenames? */
479 SHOULD_NOT_BE_FINISHED(editor);
480 SHOULD_ALLOW_ADD(editor, relpath);
481 VERIFY_PARENT_MAY_EXIST(editor, relpath);
482 CHECK_UNKNOWN_CHILD(editor, relpath);
484 SVN_ERR(check_cancel(editor));
486 if (editor->funcs.cb_add_directory)
488 START_CALLBACK(editor);
489 err = editor->funcs.cb_add_directory(editor->baton, relpath, children,
491 editor->scratch_pool);
492 END_CALLBACK(editor);
495 MARK_ADDED_DIR(editor, relpath);
496 MARK_PARENT_STABLE(editor, relpath);
497 CLEAR_INCOMPLETE(editor, relpath);
499 #ifdef ENABLE_ORDERING_CHECK
502 for (i = 0; i < children->nelts; i++)
504 const char *child_basename = APR_ARRAY_IDX(children, i, const char *);
505 const char *child = svn_relpath_join(relpath, child_basename,
508 svn_hash_sets(editor->pending_incomplete_children, child, "");
513 svn_pool_clear(editor->scratch_pool);
514 return svn_error_trace(err);
519 svn_editor_add_file(svn_editor_t *editor,
521 const svn_checksum_t *checksum,
522 svn_stream_t *contents,
524 svn_revnum_t replaces_rev)
526 svn_error_t *err = SVN_NO_ERROR;
528 SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
529 SVN_ERR_ASSERT(checksum != NULL
530 && checksum->kind == SVN_EDITOR_CHECKSUM_KIND);
531 SVN_ERR_ASSERT(contents != NULL);
532 SVN_ERR_ASSERT(props != NULL);
533 SHOULD_NOT_BE_FINISHED(editor);
534 SHOULD_ALLOW_ADD(editor, relpath);
535 VERIFY_PARENT_MAY_EXIST(editor, relpath);
536 CHECK_UNKNOWN_CHILD(editor, relpath);
538 SVN_ERR(check_cancel(editor));
540 if (editor->funcs.cb_add_file)
542 START_CALLBACK(editor);
543 err = editor->funcs.cb_add_file(editor->baton, relpath,
544 checksum, contents, props,
545 replaces_rev, editor->scratch_pool);
546 END_CALLBACK(editor);
549 MARK_COMPLETED(editor, relpath);
550 MARK_PARENT_STABLE(editor, relpath);
551 CLEAR_INCOMPLETE(editor, relpath);
553 svn_pool_clear(editor->scratch_pool);
554 return svn_error_trace(err);
559 svn_editor_add_symlink(svn_editor_t *editor,
563 svn_revnum_t replaces_rev)
565 svn_error_t *err = SVN_NO_ERROR;
567 SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
568 SVN_ERR_ASSERT(props != NULL);
569 SHOULD_NOT_BE_FINISHED(editor);
570 SHOULD_ALLOW_ADD(editor, relpath);
571 VERIFY_PARENT_MAY_EXIST(editor, relpath);
572 CHECK_UNKNOWN_CHILD(editor, relpath);
574 SVN_ERR(check_cancel(editor));
576 if (editor->funcs.cb_add_symlink)
578 START_CALLBACK(editor);
579 err = editor->funcs.cb_add_symlink(editor->baton, relpath, target, props,
580 replaces_rev, editor->scratch_pool);
581 END_CALLBACK(editor);
584 MARK_COMPLETED(editor, relpath);
585 MARK_PARENT_STABLE(editor, relpath);
586 CLEAR_INCOMPLETE(editor, relpath);
588 svn_pool_clear(editor->scratch_pool);
589 return svn_error_trace(err);
594 svn_editor_add_absent(svn_editor_t *editor,
596 svn_node_kind_t kind,
597 svn_revnum_t replaces_rev)
599 svn_error_t *err = SVN_NO_ERROR;
601 SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
602 SHOULD_NOT_BE_FINISHED(editor);
603 SHOULD_ALLOW_ADD(editor, relpath);
604 VERIFY_PARENT_MAY_EXIST(editor, relpath);
605 CHECK_UNKNOWN_CHILD(editor, relpath);
607 SVN_ERR(check_cancel(editor));
609 if (editor->funcs.cb_add_absent)
611 START_CALLBACK(editor);
612 err = editor->funcs.cb_add_absent(editor->baton, relpath, kind,
613 replaces_rev, editor->scratch_pool);
614 END_CALLBACK(editor);
617 MARK_COMPLETED(editor, relpath);
618 MARK_PARENT_STABLE(editor, relpath);
619 CLEAR_INCOMPLETE(editor, relpath);
621 svn_pool_clear(editor->scratch_pool);
622 return svn_error_trace(err);
627 svn_editor_alter_directory(svn_editor_t *editor,
629 svn_revnum_t revision,
630 const apr_array_header_t *children,
633 svn_error_t *err = SVN_NO_ERROR;
635 SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
636 SVN_ERR_ASSERT(children != NULL || props != NULL);
637 /* ### validate children are just basenames? */
638 SHOULD_NOT_BE_FINISHED(editor);
639 SHOULD_ALLOW_ALTER(editor, relpath);
640 VERIFY_PARENT_MAY_EXIST(editor, relpath);
642 SVN_ERR(check_cancel(editor));
644 if (editor->funcs.cb_alter_directory)
646 START_CALLBACK(editor);
647 err = editor->funcs.cb_alter_directory(editor->baton,
650 editor->scratch_pool);
651 END_CALLBACK(editor);
654 MARK_COMPLETED(editor, relpath);
655 MARK_PARENT_STABLE(editor, relpath);
657 #ifdef ENABLE_ORDERING_CHECK
658 /* ### this is not entirely correct. we probably need to adjust the
659 ### check_unknown_child() function for this scenario. */
663 for (i = 0; i < children->nelts; i++)
665 const char *child_basename = APR_ARRAY_IDX(children, i, const char *);
666 const char *child = svn_relpath_join(relpath, child_basename,
669 apr_hash_set(editor->pending_incomplete_children, child,
670 APR_HASH_KEY_STRING, "");
671 /* Perhaps MARK_ALLOW_ADD(editor, child); ? */
677 svn_pool_clear(editor->scratch_pool);
678 return svn_error_trace(err);
683 svn_editor_alter_file(svn_editor_t *editor,
685 svn_revnum_t revision,
687 const svn_checksum_t *checksum,
688 svn_stream_t *contents)
690 svn_error_t *err = SVN_NO_ERROR;
692 SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
693 SVN_ERR_ASSERT((checksum != NULL && contents != NULL)
694 || (checksum == NULL && contents == NULL));
695 SVN_ERR_ASSERT(props != NULL || checksum != NULL);
697 SVN_ERR_ASSERT(checksum->kind == SVN_EDITOR_CHECKSUM_KIND);
698 SHOULD_NOT_BE_FINISHED(editor);
699 SHOULD_ALLOW_ALTER(editor, relpath);
700 VERIFY_PARENT_MAY_EXIST(editor, relpath);
702 SVN_ERR(check_cancel(editor));
704 if (editor->funcs.cb_alter_file)
706 START_CALLBACK(editor);
707 err = editor->funcs.cb_alter_file(editor->baton,
708 relpath, revision, props,
710 editor->scratch_pool);
711 END_CALLBACK(editor);
714 MARK_COMPLETED(editor, relpath);
715 MARK_PARENT_STABLE(editor, relpath);
717 svn_pool_clear(editor->scratch_pool);
718 return svn_error_trace(err);
723 svn_editor_alter_symlink(svn_editor_t *editor,
725 svn_revnum_t revision,
729 svn_error_t *err = SVN_NO_ERROR;
731 SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
732 SVN_ERR_ASSERT(props != NULL || target != NULL);
733 SHOULD_NOT_BE_FINISHED(editor);
734 SHOULD_ALLOW_ALTER(editor, relpath);
735 VERIFY_PARENT_MAY_EXIST(editor, relpath);
737 SVN_ERR(check_cancel(editor));
739 if (editor->funcs.cb_alter_symlink)
741 START_CALLBACK(editor);
742 err = editor->funcs.cb_alter_symlink(editor->baton,
743 relpath, revision, props,
745 editor->scratch_pool);
746 END_CALLBACK(editor);
749 MARK_COMPLETED(editor, relpath);
750 MARK_PARENT_STABLE(editor, relpath);
752 svn_pool_clear(editor->scratch_pool);
753 return svn_error_trace(err);
758 svn_editor_delete(svn_editor_t *editor,
760 svn_revnum_t revision)
762 svn_error_t *err = SVN_NO_ERROR;
764 SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
765 SHOULD_NOT_BE_FINISHED(editor);
766 SHOULD_NOT_BE_COMPLETED(editor, relpath);
767 VERIFY_PARENT_MAY_EXIST(editor, relpath);
768 CHILD_DELETIONS_ALLOWED(editor, relpath);
770 SVN_ERR(check_cancel(editor));
772 if (editor->funcs.cb_delete)
774 START_CALLBACK(editor);
775 err = editor->funcs.cb_delete(editor->baton, relpath, revision,
776 editor->scratch_pool);
777 END_CALLBACK(editor);
780 MARK_COMPLETED(editor, relpath);
781 MARK_PARENT_STABLE(editor, relpath);
783 svn_pool_clear(editor->scratch_pool);
784 return svn_error_trace(err);
789 svn_editor_copy(svn_editor_t *editor,
790 const char *src_relpath,
791 svn_revnum_t src_revision,
792 const char *dst_relpath,
793 svn_revnum_t replaces_rev)
795 svn_error_t *err = SVN_NO_ERROR;
797 SVN_ERR_ASSERT(svn_relpath_is_canonical(src_relpath));
798 SVN_ERR_ASSERT(svn_relpath_is_canonical(dst_relpath));
799 SHOULD_NOT_BE_FINISHED(editor);
800 SHOULD_ALLOW_ADD(editor, dst_relpath);
801 VERIFY_PARENT_MAY_EXIST(editor, src_relpath);
802 VERIFY_PARENT_MAY_EXIST(editor, dst_relpath);
804 SVN_ERR(check_cancel(editor));
806 if (editor->funcs.cb_copy)
808 START_CALLBACK(editor);
809 err = editor->funcs.cb_copy(editor->baton, src_relpath, src_revision,
810 dst_relpath, replaces_rev,
811 editor->scratch_pool);
812 END_CALLBACK(editor);
815 MARK_ALLOW_ALTER(editor, dst_relpath);
816 MARK_PARENT_STABLE(editor, dst_relpath);
817 CLEAR_INCOMPLETE(editor, dst_relpath);
819 svn_pool_clear(editor->scratch_pool);
820 return svn_error_trace(err);
825 svn_editor_move(svn_editor_t *editor,
826 const char *src_relpath,
827 svn_revnum_t src_revision,
828 const char *dst_relpath,
829 svn_revnum_t replaces_rev)
831 svn_error_t *err = SVN_NO_ERROR;
833 SVN_ERR_ASSERT(svn_relpath_is_canonical(src_relpath));
834 SVN_ERR_ASSERT(svn_relpath_is_canonical(dst_relpath));
835 SHOULD_NOT_BE_FINISHED(editor);
836 SHOULD_NOT_BE_COMPLETED(editor, src_relpath);
837 SHOULD_ALLOW_ADD(editor, dst_relpath);
838 VERIFY_PARENT_MAY_EXIST(editor, src_relpath);
839 CHILD_DELETIONS_ALLOWED(editor, src_relpath);
840 VERIFY_PARENT_MAY_EXIST(editor, dst_relpath);
842 SVN_ERR(check_cancel(editor));
844 if (editor->funcs.cb_move)
846 START_CALLBACK(editor);
847 err = editor->funcs.cb_move(editor->baton, src_relpath, src_revision,
848 dst_relpath, replaces_rev,
849 editor->scratch_pool);
850 END_CALLBACK(editor);
853 MARK_ALLOW_ADD(editor, src_relpath);
854 MARK_PARENT_STABLE(editor, src_relpath);
855 MARK_ALLOW_ALTER(editor, dst_relpath);
856 MARK_PARENT_STABLE(editor, dst_relpath);
857 CLEAR_INCOMPLETE(editor, dst_relpath);
859 svn_pool_clear(editor->scratch_pool);
860 return svn_error_trace(err);
865 svn_editor_rotate(svn_editor_t *editor,
866 const apr_array_header_t *relpaths,
867 const apr_array_header_t *revisions)
869 svn_error_t *err = SVN_NO_ERROR;
871 SHOULD_NOT_BE_FINISHED(editor);
872 #ifdef ENABLE_ORDERING_CHECK
875 for (i = 0; i < relpaths->nelts; i++)
877 const char *relpath = APR_ARRAY_IDX(relpaths, i, const char *);
879 SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
880 SHOULD_NOT_BE_COMPLETED(editor, relpath);
881 VERIFY_PARENT_MAY_EXIST(editor, relpath);
882 CHILD_DELETIONS_ALLOWED(editor, relpath);
887 SVN_ERR(check_cancel(editor));
889 if (editor->funcs.cb_rotate)
891 START_CALLBACK(editor);
892 err = editor->funcs.cb_rotate(editor->baton, relpaths, revisions,
893 editor->scratch_pool);
894 END_CALLBACK(editor);
897 #ifdef ENABLE_ORDERING_CHECK
900 for (i = 0; i < relpaths->nelts; i++)
902 const char *relpath = APR_ARRAY_IDX(relpaths, i, const char *);
903 MARK_ALLOW_ALTER(editor, relpath);
904 MARK_PARENT_STABLE(editor, relpath);
909 svn_pool_clear(editor->scratch_pool);
910 return svn_error_trace(err);
915 svn_editor_complete(svn_editor_t *editor)
917 svn_error_t *err = SVN_NO_ERROR;
919 SHOULD_NOT_BE_FINISHED(editor);
920 #ifdef ENABLE_ORDERING_CHECK
921 SVN_ERR_ASSERT(apr_hash_count(editor->pending_incomplete_children) == 0);
924 if (editor->funcs.cb_complete)
926 START_CALLBACK(editor);
927 err = editor->funcs.cb_complete(editor->baton, editor->scratch_pool);
928 END_CALLBACK(editor);
931 MARK_FINISHED(editor);
933 svn_pool_clear(editor->scratch_pool);
934 return svn_error_trace(err);
939 svn_editor_abort(svn_editor_t *editor)
941 svn_error_t *err = SVN_NO_ERROR;
943 SHOULD_NOT_BE_FINISHED(editor);
945 if (editor->funcs.cb_abort)
947 START_CALLBACK(editor);
948 err = editor->funcs.cb_abort(editor->baton, editor->scratch_pool);
949 END_CALLBACK(editor);
952 MARK_FINISHED(editor);
954 svn_pool_clear(editor->scratch_pool);
955 return svn_error_trace(err);