Julian Foad wrote: > [...] There are > currently two implementations of a "dump" editor and neither is > immediately usable. The one in "svnadmin dump" is not written as a clean > editor, and instead calls directly into the FS layer to fetch its data. > The one in "svnrdump" is clean but does not support all the features of > the other such as non-delta mode and verify mode.
For connecting to the WC and to shelving, it is not a problem that the "svnrdump" dump editor lacks support for those features. It's a problem that the implementation is located in the "svnrdump" executable rather than in a library, but that is easy to overcome. > => We need to unify these two implementations, to have a clean re- > usable dump editor. So moving the "svnrdump" implementation into the library can be the first step (done: r1838835), and unifying can be the second step. The attached patch 'unifying-dump-editors-1.patch' goes some way towards that. > The delta edit driver in "svnadmin load" also does not seem to be shared > with the one in "svnrdump load". > > => We need to unify these two implementations, to have a re-usable > load edit-driver. > > To be clear, re-using the dump/load functionality is not a direct > requirement for shelving; rather, it is an existing functionality that > supports input and output of shelvable changes. By providing an input > and output mechanism that can be attached to various APIs (repository, > WC, and shelves) it is useful for testing that the APIs all work > consistently. Only by implementing more than one edit driver for each editor (and vice versa) can we prove that the components are cleanly separated by an API and thus re-usable. Then there is the need for a test framework that can generate all different combinations of changes and test each of the subsystems with all of those changes. These improvements are not just to benefit shelving. In the longer term, if we are to make a major improvement like supporting moves/renames properly, in my opinion we need to do it starting from a baseline where we consistently and cleanly use APIs that encode the current semantics of versioned changes, and then migrate those. -- - Julian
Towards unifying the two repository dump editor implementations. ('Dump editor' here means a dump-stream writer driven through the svn_delta_editor_t API.) The older dump editor in 'dump.c' supports 'svnadmin dump' and 'svnadmin verify'. The newer dump editor in 'dump_editor.c' supports 'svnrdump dump'. The latter can only produce delta-mode dumps. This patch extracts some of the ancillary functionality (some kinds of verification) out of the original dump editor into a separate wrapper, and applies this verification wrapper to either the original dump editor or the newer one. This brings us closer to being able to use the newer dump editor as a drop-in replacement for the old one. ### So far, only 2 of the 3 checks performed in dump mode are moved to the new checking wrapper: fspath and copyfrom, but not mergeinfo. * subversion/libsvn_repos/dump.c (check_mergeinfo_revisions, verify_fspath, check_for_old_copy_reference): New, extracted from dump_node(). (edit_baton, dump_node, get_dump_editor): Remove the three checks that are moved to the wrapper, and their related parameters. (rc_*, get_ref_checking_editor): New: a reference-checking wrapper editor implementing those three checks. (get_dump_only_editor): New function. Wraps the basic editor with the new reference-checking wrapper editor. ### For now, calls the newer dump editor in 'deltas' mode, else the older one; thus in deltas mode the mergeinfo revs check is missing. (svn_repos_dump_fs4): Call get_dump_only_editor() instead of get_gump_editor(). (get_verify_editor): New function, wrapping get_dump_editor(). (verify_one_revision): Call get_verify_editor() instead of get_gump_editor(). --This line, and those below, will be ignored-- Index: subversion/libsvn_repos/dump.c =================================================================== --- subversion/libsvn_repos/dump.c (revision 1838836) +++ subversion/libsvn_repos/dump.c (working copy) @@ -651,16 +651,12 @@ struct edit_baton /* True if checking UCS normalization during a verify. */ svn_boolean_t check_normalization; /* The first revision dumped in this dumpstream. */ svn_revnum_t oldest_dumped_rev; - /* If not NULL, set to true if any references to revisions older than - OLDEST_DUMPED_REV were found in the dumpstream. */ - svn_boolean_t *found_old_reference; - /* If not NULL, set to true if any mergeinfo was dumped which contains revisions older than OLDEST_DUMPED_REV. */ svn_boolean_t *found_old_mergeinfo; /* Structure allows us to verify the paths currently being dumped. If NULL, validity checks are being skipped. */ @@ -874,12 +870,43 @@ verify_mergeinfo_revisions(svn_boolean_t *found_old_mergeinfo = TRUE; } return SVN_NO_ERROR; } +/* */ +static svn_error_t * +check_mergeinfo_revisions(svn_boolean_t *found_old_mergeinfo, + svn_repos_notify_func_t notify_func, + void *notify_baton, + svn_revnum_t oldest_dumped_rev, + apr_hash_t *prophash, + apr_pool_t *pool) +{ + /* If this is a partial dump, then issue a warning if we dump mergeinfo + properties that refer to revisions older than the first revision + dumped. */ + if (notify_func && oldest_dumped_rev > 1) + { + svn_string_t *mergeinfo_str = svn_hash_gets(prophash, + SVN_PROP_MERGEINFO); + if (mergeinfo_str) + { + /* An error in verifying the mergeinfo must not prevent dumping + the data. Ignore any such error. */ + svn_error_clear(verify_mergeinfo_revisions( + found_old_mergeinfo, + mergeinfo_str->data, oldest_dumped_rev, + notify_func, notify_baton, + pool)); + } + } + + return SVN_NO_ERROR; +} + /* Unique string pointers used by verify_mergeinfo_normalization() and check_name_collision() */ static const char normalized_unique[] = "normalized_unique"; static const char normalized_collision[] = "normalized_collision"; @@ -1069,12 +1096,63 @@ dump_node_delete(svn_stream_t *stream, headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete"); SVN_ERR(svn_repos__dump_headers(stream, headers, pool)); return SVN_NO_ERROR; } +/* */ +static svn_error_t * +verify_fspath(const char *path, + svn_repos_notify_func_t notify_func, + void *notify_baton, + apr_pool_t *pool) +{ + svn_error_t *err = svn_fs__path_valid(path, pool); + + if (err) + { + if (notify_func) + { + char errbuf[512]; /* ### svn_strerror() magic number */ + + notify_warning(pool, notify_func, notify_baton, + svn_repos_notify_warning_invalid_fspath, + _("E%06d: While validating fspath '%s': %s"), + err->apr_err, path, + svn_err_best_message(err, errbuf, sizeof (errbuf))); + } + } + return svn_error_trace(err); +} + +/* */ +static svn_error_t * +check_for_old_copy_reference(svn_boolean_t *found_old_reference, + svn_repos_notify_func_t notify_func, + void *notify_baton, + svn_revnum_t oldest_dumped_rev, + svn_revnum_t copyfrom_rev, + apr_pool_t *pool) +{ + if (copyfrom_rev < oldest_dumped_rev + && notify_func) + { + notify_warning(pool, notify_func, notify_baton, + svn_repos_notify_warning_found_old_reference, + _("Referencing data in revision %ld," + " which is older than the oldest" + " dumped revision (r%ld). Loading this dump" + " into an empty repository" + " will fail."), + copyfrom_rev, oldest_dumped_rev); + if (found_old_reference) + *found_old_reference = TRUE; + } + return SVN_NO_ERROR; +} + /* This helper is the main "meat" of the editor -- it does all the work of writing a node record. Write out a node record for PATH of type KIND under EB->FS_ROOT. ACTION describes what is happening to the node (see enum svn_node_action). Write record to writable EB->STREAM. @@ -1103,35 +1181,18 @@ dump_node(struct edit_baton *eb, apr_file_t *delta_file = NULL; svn_repos__dumpfile_headers_t *headers = svn_repos__dumpfile_headers_create(pool); svn_filesize_t textlen; /* Maybe validate the path. */ - if (eb->verify || eb->notify_func) + if (eb->verify) { - svn_error_t *err = svn_fs__path_valid(path, pool); - - if (err) - { - if (eb->notify_func) - { - char errbuf[512]; /* ### svn_strerror() magic number */ - - notify_warning(pool, eb->notify_func, eb->notify_baton, - svn_repos_notify_warning_invalid_fspath, - _("E%06d: While validating fspath '%s': %s"), - err->apr_err, path, - svn_err_best_message(err, errbuf, sizeof(errbuf))); - } - - /* Return the error in addition to notifying about it. */ - if (eb->verify) - return svn_error_trace(err); - else - svn_error_clear(err); - } + /* Return the error in addition to notifying about it. */ + SVN_ERR(verify_fspath(path, + eb->notify_func, eb->notify_baton, + pool)); } /* Write out metadata headers for this file node. */ svn_repos__dumpfile_header_push( headers, SVN_REPOS_DUMPFILE_NODE_PATH, path); if (kind == svn_node_file) @@ -1268,27 +1329,12 @@ dump_node(struct edit_baton *eb, "'%s' in r%ld"), path, eb->current_rev)); tracker_path_copy(eb->path_tracker, path, compare_path, compare_rev); } - if (!eb->verify && cmp_rev < eb->oldest_dumped_rev - && eb->notify_func) - { - notify_warning(pool, eb->notify_func, eb->notify_baton, - svn_repos_notify_warning_found_old_reference, - _("Referencing data in revision %ld," - " which is older than the oldest" - " dumped revision (r%ld). Loading this dump" - " into an empty repository" - " will fail."), - cmp_rev, eb->oldest_dumped_rev); - if (eb->found_old_reference) - *eb->found_old_reference = TRUE; - } - svn_repos__dumpfile_header_pushf( headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV, "%ld", cmp_rev); svn_repos__dumpfile_header_push( headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH, cmp_path); SVN_ERR(svn_fs_revision_root(&compare_root, @@ -1349,29 +1395,18 @@ dump_node(struct edit_baton *eb, { apr_hash_t *prophash, *oldhash = NULL; svn_stream_t *propstream; SVN_ERR(svn_fs_node_proplist(&prophash, eb->fs_root, path, pool)); - /* If this is a partial dump, then issue a warning if we dump mergeinfo - properties that refer to revisions older than the first revision - dumped. */ - if (!eb->verify && eb->notify_func && eb->oldest_dumped_rev > 1) + if (!eb->verify) { - svn_string_t *mergeinfo_str = svn_hash_gets(prophash, - SVN_PROP_MERGEINFO); - if (mergeinfo_str) - { - /* An error in verifying the mergeinfo must not prevent dumping - the data. Ignore any such error. */ - svn_error_clear(verify_mergeinfo_revisions( - eb->found_old_mergeinfo, - mergeinfo_str->data, eb->oldest_dumped_rev, - eb->notify_func, eb->notify_baton, - pool)); - } + SVN_ERR(check_mergeinfo_revisions(eb->found_old_mergeinfo, + eb->notify_func, eb->notify_baton, + eb->oldest_dumped_rev, + prophash, pool)); } /* If we're checking UCS normalization, also parse any changed mergeinfo and warn about denormalized paths and name collisions there. */ if (eb->verify && eb->check_normalization && eb->notify_func) @@ -1842,13 +1877,12 @@ static svn_error_t * get_dump_editor(const svn_delta_editor_t **editor, void **edit_baton, svn_fs_t *fs, svn_revnum_t to_rev, const char *root_path, svn_stream_t *stream, - svn_boolean_t *found_old_reference, svn_boolean_t *found_old_mergeinfo, svn_error_t *(*custom_close_directory)(void *dir_baton, apr_pool_t *scratch_pool), svn_repos_notify_func_t notify_func, void *notify_baton, svn_revnum_t oldest_dumped_rev, @@ -1874,13 +1908,12 @@ get_dump_editor(const svn_delta_editor_t SVN_ERR(svn_fs_revision_root(&(eb->fs_root), fs, to_rev, pool)); eb->fs = fs; eb->current_rev = to_rev; eb->use_deltas = use_deltas; eb->verify = verify; eb->check_normalization = check_normalization; - eb->found_old_reference = found_old_reference; eb->found_old_mergeinfo = found_old_mergeinfo; /* In non-verification mode, we will allow anything to be dumped because it might be an incremental dump with possible manual intervention. Also, this might be the last resort when it comes to data recovery. @@ -1912,12 +1945,465 @@ get_dump_editor(const svn_delta_editor_t SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton, NULL, NULL, shim_callbacks, pool, pool)); return SVN_NO_ERROR; } +/* ========================================================== */ +/* A filtering editor that reports: + - invalid fspaths, + - old references in copyfrom, + - old references in mergeinfo. + + ### TODO: move the mergeinfo revisions check to here. + */ + +struct rc_edit_baton +{ + const svn_delta_editor_t *wrapped_editor; + void *wrapped_edit_baton; + + /* If not NULL, set to true if any references to revisions older than + OLDEST_DUMPED_REV were found in the dumpstream. */ + svn_boolean_t *found_old_reference; + + svn_boolean_t *found_old_mergeinfo; + svn_repos_notify_func_t notify_func; + void *notify_baton; + svn_revnum_t oldest_dumped_rev; +}; + +struct rc_dir_baton +{ + struct rc_edit_baton *edit_baton; + void *wrapped_dir_baton; +}; + +struct rc_file_baton +{ + struct rc_edit_baton *edit_baton; + void *wrapped_file_baton; +}; + +static svn_error_t * +rc_set_target_revision(void *edit_baton, + svn_revnum_t target_revision, + apr_pool_t *pool) +{ + struct rc_edit_baton *eb = edit_baton; + + return eb->wrapped_editor->set_target_revision(eb->wrapped_edit_baton, + target_revision, + pool); +} + +static svn_error_t * +rc_open_root(void *edit_baton, + svn_revnum_t base_revision, + apr_pool_t *pool, + void **root_baton) +{ + struct rc_edit_baton *eb = edit_baton; + struct rc_dir_baton *dir_baton = apr_palloc(pool, sizeof(*dir_baton)); + + SVN_ERR(eb->wrapped_editor->open_root(eb->wrapped_edit_baton, + base_revision, + pool, + &dir_baton->wrapped_dir_baton)); + + dir_baton->edit_baton = edit_baton; + + *root_baton = dir_baton; + + return SVN_NO_ERROR; +} + +static svn_error_t * +rc_delete_entry(const char *path, + svn_revnum_t base_revision, + void *parent_baton, + apr_pool_t *pool) +{ + struct rc_dir_baton *pb = parent_baton; + struct rc_edit_baton *eb = pb->edit_baton; + + if (eb->notify_func) + { + svn_error_clear(verify_fspath(path, eb->notify_func, eb->notify_baton, + pool)); + } + + return eb->wrapped_editor->delete_entry(path, + base_revision, + pb->wrapped_dir_baton, + pool); +} + +static svn_error_t * +rc_add_directory(const char *path, + void *parent_baton, + const char *copyfrom_path, + svn_revnum_t copyfrom_rev, + apr_pool_t *pool, + void **child_baton) +{ + struct rc_dir_baton *pb = parent_baton; + struct rc_edit_baton *eb = pb->edit_baton; + struct rc_dir_baton *b = apr_palloc(pool, sizeof(*b)); + svn_boolean_t is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev); + + if (eb->notify_func) + { + svn_error_clear(verify_fspath(path, eb->notify_func, eb->notify_baton, + pool)); + } + + if (is_copy) + { + SVN_ERR(check_for_old_copy_reference(eb->found_old_reference, + eb->notify_func, eb->notify_baton, + eb->oldest_dumped_rev, + copyfrom_rev, pool)); + } + + SVN_ERR(eb->wrapped_editor->add_directory(path, + pb->wrapped_dir_baton, + copyfrom_path, + copyfrom_rev, + pool, + &b->wrapped_dir_baton)); + + b->edit_baton = eb; + *child_baton = b; + + return SVN_NO_ERROR; +} + +static svn_error_t * +rc_open_directory(const char *path, + void *parent_baton, + svn_revnum_t base_revision, + apr_pool_t *pool, + void **child_baton) +{ + struct rc_dir_baton *pb = parent_baton; + struct rc_edit_baton *eb = pb->edit_baton; + struct rc_dir_baton *db = apr_palloc(pool, sizeof(*db)); + + if (eb->notify_func) + { + svn_error_clear(verify_fspath(path, eb->notify_func, eb->notify_baton, + pool)); + } + + SVN_ERR(eb->wrapped_editor->open_directory(path, + pb->wrapped_dir_baton, + base_revision, + pool, + &db->wrapped_dir_baton)); + + db->edit_baton = eb; + *child_baton = db; + + return SVN_NO_ERROR; +} + +static svn_error_t * +rc_add_file(const char *path, + void *parent_baton, + const char *copyfrom_path, + svn_revnum_t copyfrom_rev, + apr_pool_t *pool, + void **file_baton) +{ + struct rc_dir_baton *pb = parent_baton; + struct rc_edit_baton *eb = pb->edit_baton; + struct rc_file_baton *fb = apr_palloc(pool, sizeof(*fb)); + svn_boolean_t is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev); + + if (eb->notify_func) + { + svn_error_clear(verify_fspath(path, eb->notify_func, eb->notify_baton, + pool)); + } + + if (is_copy) + { + SVN_ERR(check_for_old_copy_reference(eb->found_old_reference, + eb->notify_func, eb->notify_baton, + eb->oldest_dumped_rev, + copyfrom_rev, pool)); + } + + SVN_ERR(eb->wrapped_editor->add_file(path, + pb->wrapped_dir_baton, + copyfrom_path, + copyfrom_rev, + pool, + &fb->wrapped_file_baton)); + + fb->edit_baton = eb; + *file_baton = fb; + + return SVN_NO_ERROR; +} + +static svn_error_t * +rc_open_file(const char *path, + void *parent_baton, + svn_revnum_t base_revision, + apr_pool_t *pool, + void **file_baton) +{ + struct rc_dir_baton *pb = parent_baton; + struct rc_edit_baton *eb = pb->edit_baton; + struct rc_file_baton *fb = apr_palloc(pool, sizeof(*fb)); + + if (eb->notify_func) + { + svn_error_clear(verify_fspath(path, eb->notify_func, eb->notify_baton, + pool)); + } + + SVN_ERR(eb->wrapped_editor->open_file(path, + pb->wrapped_dir_baton, + base_revision, + pool, + &fb->wrapped_file_baton)); + + fb->edit_baton = eb; + *file_baton = fb; + + return SVN_NO_ERROR; +} + +static svn_error_t * +rc_apply_textdelta(void *file_baton, + const char *base_checksum, + apr_pool_t *pool, + svn_txdelta_window_handler_t *handler, + void **handler_baton) +{ + struct rc_file_baton *fb = file_baton; + struct rc_edit_baton *eb = fb->edit_baton; + + return eb->wrapped_editor->apply_textdelta(fb->wrapped_file_baton, + base_checksum, + pool, + handler, + handler_baton); +} + +static svn_error_t * +rc_apply_textdelta_stream(const 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) +{ + struct rc_file_baton *fb = file_baton; + struct rc_edit_baton *eb = fb->edit_baton; + + return eb->wrapped_editor->apply_textdelta_stream(eb->wrapped_editor, + fb->wrapped_file_baton, + base_checksum, + open_func, open_baton, + scratch_pool); +} + +static svn_error_t * +rc_close_file(void *file_baton, + const char *text_checksum, + apr_pool_t *pool) +{ + struct rc_file_baton *fb = file_baton; + struct rc_edit_baton *eb = fb->edit_baton; + + return eb->wrapped_editor->close_file(fb->wrapped_file_baton, + text_checksum, pool); +} + +static svn_error_t * +rc_absent_file(const char *path, + void *file_baton, + apr_pool_t *pool) +{ + struct rc_file_baton *fb = file_baton; + struct rc_edit_baton *eb = fb->edit_baton; + + return eb->wrapped_editor->absent_file(path, fb->wrapped_file_baton, + pool); +} + +static svn_error_t * +rc_close_directory(void *dir_baton, + apr_pool_t *pool) +{ + struct rc_dir_baton *db = dir_baton; + struct rc_edit_baton *eb = db->edit_baton; + + return eb->wrapped_editor->close_directory(db->wrapped_dir_baton, pool); +} + +static svn_error_t * +rc_absent_directory(const char *path, + void *dir_baton, + apr_pool_t *pool) +{ + struct rc_dir_baton *db = dir_baton; + struct rc_edit_baton *eb = db->edit_baton; + + return eb->wrapped_editor->absent_directory(path, db->wrapped_dir_baton, + pool); +} + +static svn_error_t * +rc_change_file_prop(void *file_baton, + const char *name, + const svn_string_t *value, + apr_pool_t *pool) +{ + struct rc_file_baton *fb = file_baton; + struct rc_edit_baton *eb = fb->edit_baton; + + return eb->wrapped_editor->change_file_prop(fb->wrapped_file_baton, + name, value, pool); +} + +static svn_error_t * +rc_change_dir_prop(void *dir_baton, + const char *name, + const svn_string_t *value, + apr_pool_t *pool) +{ + struct rc_dir_baton *db = dir_baton; + struct rc_edit_baton *eb = db->edit_baton; + + return eb->wrapped_editor->change_dir_prop(db->wrapped_dir_baton, + name, + value, + pool); +} + +static svn_error_t * +rc_close_edit(void *edit_baton, + apr_pool_t *pool) +{ + struct rc_edit_baton *eb = edit_baton; + + return eb->wrapped_editor->close_edit(eb->wrapped_edit_baton, pool); +} + +static svn_error_t * +rc_abort_edit(void *edit_baton, + apr_pool_t *pool) +{ + struct rc_edit_baton *eb = edit_baton; + + return eb->wrapped_editor->abort_edit(eb->wrapped_edit_baton, pool); +} + +/* Check for references older than oldest_dumped_rev. + Notify warnings and set *found_old_reference / *found_old_mergeinfo. + */ +static svn_error_t * +get_ref_checking_editor(const svn_delta_editor_t **editor_p, + void **edit_baton, + const svn_delta_editor_t *wrapped_editor, + void *wrapped_edit_baton, + svn_boolean_t *found_old_reference, + svn_boolean_t *found_old_mergeinfo, + svn_repos_notify_func_t notify_func, + void *notify_baton, + svn_revnum_t oldest_dumped_rev, + apr_pool_t *pool) +{ + svn_delta_editor_t *editor = svn_delta_default_editor(pool); + struct rc_edit_baton *eb = apr_palloc(pool, sizeof (*eb)); + + editor->set_target_revision = rc_set_target_revision; + editor->open_root = rc_open_root; + editor->delete_entry = rc_delete_entry; + editor->add_directory = rc_add_directory; + editor->open_directory = rc_open_directory; + editor->change_dir_prop = rc_change_dir_prop; + editor->close_directory = rc_close_directory; + editor->absent_directory = rc_absent_directory; + editor->add_file = rc_add_file; + editor->open_file = rc_open_file; + editor->apply_textdelta = rc_apply_textdelta; + editor->apply_textdelta_stream = rc_apply_textdelta_stream; + editor->change_file_prop = rc_change_file_prop; + editor->close_file = rc_close_file; + editor->absent_file = rc_absent_file; + editor->close_edit = rc_close_edit; + editor->abort_edit = rc_abort_edit; + + eb->wrapped_editor = wrapped_editor; + eb->wrapped_edit_baton = wrapped_edit_baton; + eb->found_old_reference = found_old_reference; + eb->found_old_mergeinfo = found_old_mergeinfo; + eb->notify_func = notify_func; + eb->notify_baton = notify_baton; + eb->oldest_dumped_rev = oldest_dumped_rev; + + *editor_p = editor; + *edit_baton = eb; + + return SVN_NO_ERROR; +} + +/* Get a dump editor (for dump, not for verify). */ +static svn_error_t * +get_dump_only_editor(const svn_delta_editor_t **editor, + void **edit_baton, + svn_fs_t *fs, + svn_revnum_t to_rev, + const char *root_relpath, + svn_stream_t *stream, + svn_boolean_t *found_old_reference, + svn_boolean_t *found_old_mergeinfo, + svn_repos_notify_func_t notify_func, + void *notify_baton, + svn_revnum_t oldest_dumped_rev, + svn_boolean_t use_deltas, + apr_pool_t *pool) +{ + if (use_deltas) + { + /* For this editor implementation, FS and TO_REV are not required. */ + SVN_ERR(svn_repos__get_dump_editor(editor, edit_baton, + stream, root_relpath, pool)); + } + else + { + SVN_ERR(get_dump_editor(editor, edit_baton, + fs, to_rev, root_relpath, + stream, + /*###*/found_old_mergeinfo, + NULL /*custom_close_directory*/, + /*###*/notify_func, notify_baton, + /*###*/oldest_dumped_rev, + use_deltas, + FALSE /*verify*/, FALSE /*check_normalization*/, + pool)); + } + + /* Check for invalid fspaths and for copyfrom or mergeinfo references to + revisions older than oldest_dumped_rev. When found, send a warning + notification and set *found_old_reference / *found_old_mergeinfo. */ + SVN_ERR(get_ref_checking_editor(editor, edit_baton, + *editor, *edit_baton, + found_old_reference, found_old_mergeinfo, + notify_func, notify_baton, + oldest_dumped_rev, + pool)); + return SVN_NO_ERROR; +} + /*----------------------------------------------------------------------*/ /** The main dumping routine, svn_repos_dump_fs. **/ /* Helper for svn_repos_dump_fs. @@ -2096,17 +2582,17 @@ svn_repos_dump_fs4(svn_repos_t *repos, goto loop_end; /* Fetch the editor which dumps nodes to a file. Regardless of what we've been told, don't use deltas for the first rev of a non-incremental dump. */ use_deltas_for_rev = use_deltas && (incremental || rev != start_rev); - SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton, fs, rev, + SVN_ERR(get_dump_only_editor(&dump_editor, &dump_edit_baton, fs, rev, "", stream, &found_old_reference, - &found_old_mergeinfo, NULL, + &found_old_mergeinfo, notify_func, notify_baton, - start_rev, use_deltas_for_rev, FALSE, FALSE, + start_rev, use_deltas_for_rev, iterpool)); /* Drive the editor in one way or another. */ SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, iterpool)); /* If this is the first revision of a non-incremental dump, @@ -2313,12 +2799,38 @@ verify_close_directory(void *dir_baton, &check_baton, pool)); } return close_directory(dir_baton, pool); } +/* Get a verify editor... */ +static svn_error_t * +get_verify_editor(const svn_delta_editor_t **editor, + void **edit_baton, + svn_fs_t *fs, + svn_revnum_t rev, + const char *root_relpath, + svn_repos_notify_func_t notify_func, + void *notify_baton, + svn_revnum_t oldest_dumped_rev, + svn_boolean_t check_normalization, + apr_pool_t *pool) +{ + SVN_ERR(get_dump_editor(editor, edit_baton, + fs, rev, root_relpath, + svn_stream_empty(pool), + NULL, + verify_close_directory, + notify_func, notify_baton, + oldest_dumped_rev, + FALSE /*use_deltas*/, TRUE /*verify*/, + check_normalization, + pool)); + return SVN_NO_ERROR; +} + /* Verify revision REV in file system FS. */ static svn_error_t * verify_one_revision(svn_fs_t *fs, svn_revnum_t rev, svn_repos_notify_func_t notify_func, void *notify_baton, @@ -2333,22 +2845,18 @@ verify_one_revision(svn_fs_t *fs, svn_fs_root_t *to_root; apr_hash_t *props; const svn_delta_editor_t *cancel_editor; void *cancel_edit_baton; /* Get cancellable dump editor, but with our close_directory handler.*/ - SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton, - fs, rev, "", - svn_stream_empty(scratch_pool), - NULL, NULL, - verify_close_directory, - notify_func, notify_baton, - start_rev, - FALSE, TRUE, /* use_deltas, verify */ - check_normalization, - scratch_pool)); + SVN_ERR(get_verify_editor(&dump_editor, &dump_edit_baton, + fs, rev, "", + notify_func, notify_baton, + start_rev, + check_normalization, + scratch_pool)); SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton, dump_editor, dump_edit_baton, &cancel_editor, &cancel_edit_baton, scratch_pool)); SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, scratch_pool));