Modified: subversion/branches/swig-py3/subversion/libsvn_client/wc_editor.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_client/wc_editor.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_client/wc_editor.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_client/wc_editor.c Mon Jul 8 15:19:03 2019 @@ -1,5 +1,5 @@ /* - * copy_foreign.c: copy from other repository support. + * wc_editor.c: editing the local modifications in the WC. * * ==================================================================== * Licensed to the Apache Software Foundation (ASF) under one @@ -48,20 +48,34 @@ /* WC Modifications Editor. * + * This editor applies incoming modifications onto the current working state + * of the working copy, to produce a new working state. + * + * Currently, it assumes the working state matches what the edit driver + * expects to find, and may throw an error if not. + * + * For simplicity, we apply incoming edits as they arrive, rather than + * queueing them up to apply in a batch. + * * TODO: * - tests * - use for all existing scenarios ('svn add', 'svn propset', etc.) - * - copy-from (half done: in dir_add only, untested) - * - text-delta * - Instead of 'root_dir_add' option, probably the driver should anchor * at the parent dir. * - Instead of 'ignore_mergeinfo' option, implement that as a wrapper. + * - Option to quietly accept changes that seem to be already applied + * in the versioned state and/or on disk. + * Consider 'svn add' which assumes items to be added are found on disk. + * - Notification. */ +/* Everything we need to know about the edit session. + */ struct edit_baton_t { - apr_pool_t *pool; const char *anchor_abspath; + svn_boolean_t manage_wc_write_lock; + const char *lock_root_abspath; /* the path locked, when locked */ /* True => 'open_root' method will act as 'add_directory' */ svn_boolean_t root_dir_add; @@ -76,22 +90,20 @@ struct edit_baton_t void *notify_baton; }; +/* Everything we need to know about a directory that's open for edits. + */ struct dir_baton_t { apr_pool_t *pool; - struct dir_baton_t *pb; struct edit_baton_t *eb; const char *local_abspath; - - svn_boolean_t created; /* already under version control in the WC */ - apr_hash_t *properties; - - int users; }; -/* */ +/* Join PATH onto ANCHOR_ABSPATH. + * Throw an error if the result is outside ANCHOR_ABSPATH. + */ static svn_error_t * get_path(const char **local_abspath_p, const char *anchor_abspath, @@ -112,6 +124,72 @@ get_path(const char **local_abspath_p, return SVN_NO_ERROR; } +/* Create a directory on disk and add it to version control, + * with no properties. + */ +static svn_error_t * +mkdir(const char *abspath, + struct edit_baton_t *eb, + apr_pool_t *scratch_pool) +{ + SVN_ERR(svn_io_make_dir_recursively(abspath, scratch_pool)); + SVN_ERR(svn_wc_add_from_disk3(eb->wc_ctx, abspath, + NULL /*properties*/, + TRUE /* skip checks */, + eb->notify_func, eb->notify_baton, + scratch_pool)); + return SVN_NO_ERROR; +} + +/* Prepare to open or add a directory: initialize a new dir baton. + * + * If PATH is "" and PB is null, it represents the root directory of + * the edit; otherwise PATH is not "" and PB is not null. + */ +static svn_error_t * +dir_open_or_add(struct dir_baton_t **child_dir_baton, + const char *path, + struct dir_baton_t *pb, + struct edit_baton_t *eb, + apr_pool_t *dir_pool) +{ + struct dir_baton_t *db = apr_pcalloc(dir_pool, sizeof(*db)); + + db->pool = dir_pool; + db->eb = eb; + + SVN_ERR(get_path(&db->local_abspath, + eb->anchor_abspath, path, dir_pool)); + + *child_dir_baton = db; + return SVN_NO_ERROR; +} + +/* */ +static svn_error_t * +release_write_lock(struct edit_baton_t *eb, + apr_pool_t *scratch_pool) +{ + if (eb->lock_root_abspath) + { + SVN_ERR(svn_wc__release_write_lock( + eb->ctx->wc_ctx, eb->lock_root_abspath, scratch_pool)); + eb->lock_root_abspath = NULL; + } + return SVN_NO_ERROR; +} + +/* */ +static apr_status_t +pool_cleanup_handler(void *root_baton) +{ + struct dir_baton_t *db = root_baton; + struct edit_baton_t *eb = db->eb; + + svn_error_clear(release_write_lock(eb, db->pool)); + return APR_SUCCESS; +} + /* svn_delta_editor_t function */ static svn_error_t * edit_open(void *edit_baton, @@ -120,28 +198,38 @@ edit_open(void *edit_baton, void **root_baton) { struct edit_baton_t *eb = edit_baton; - apr_pool_t *dir_pool = svn_pool_create(eb->pool); - struct dir_baton_t *db = apr_pcalloc(dir_pool, sizeof(*db)); + struct dir_baton_t *db; - db->pool = dir_pool; - db->eb = eb; - db->users = 1; - db->local_abspath = eb->anchor_abspath; + SVN_ERR(dir_open_or_add(&db, "", NULL, eb, result_pool)); + + /* Acquire a WC write lock */ + if (eb->manage_wc_write_lock) + { + apr_pool_cleanup_register(db->pool, db, + pool_cleanup_handler, + apr_pool_cleanup_null); + SVN_ERR(svn_wc__acquire_write_lock(&eb->lock_root_abspath, + eb->ctx->wc_ctx, + eb->anchor_abspath, + FALSE /*lock_anchor*/, + db->pool, db->pool)); + } - db->created = !(eb->root_dir_add); if (eb->root_dir_add) - SVN_ERR(svn_io_make_dir_recursively(eb->anchor_abspath, dir_pool)); + { + SVN_ERR(mkdir(db->local_abspath, eb, result_pool)); + } *root_baton = db; - return SVN_NO_ERROR; } /* svn_delta_editor_t function */ static svn_error_t * -edit_close(void *edit_baton, - apr_pool_t *scratch_pool) +edit_close_or_abort(void *edit_baton, + apr_pool_t *scratch_pool) { + SVN_ERR(release_write_lock(edit_baton, scratch_pool)); return SVN_NO_ERROR; } @@ -167,31 +255,6 @@ delete_entry(const char *path, return SVN_NO_ERROR; } -/* */ -static svn_error_t * -dir_open_or_add(const char *path, - void *parent_baton, - struct dir_baton_t **child_baton) -{ - struct dir_baton_t *pb = parent_baton; - struct edit_baton_t *eb = pb->eb; - apr_pool_t *dir_pool = svn_pool_create(pb->pool); - struct dir_baton_t *db = apr_pcalloc(dir_pool, sizeof(*db)); - - pb->users++; - - db->pb = pb; - db->eb = pb->eb; - db->pool = dir_pool; - db->users = 1; - - SVN_ERR(get_path(&db->local_abspath, - eb->anchor_abspath, path, db->pool)); - - *child_baton = db; - return SVN_NO_ERROR; -} - /* An svn_delta_editor_t function. */ static svn_error_t * dir_open(const char *path, @@ -200,10 +263,11 @@ dir_open(const char *path, apr_pool_t *result_pool, void **child_baton) { + struct dir_baton_t *pb = parent_baton; + struct edit_baton_t *eb = pb->eb; struct dir_baton_t *db; - SVN_ERR(dir_open_or_add(path, parent_baton, &db)); - db->created = TRUE; + SVN_ERR(dir_open_or_add(&db, path, pb, eb, result_pool)); *child_baton = db; return SVN_NO_ERROR; @@ -217,9 +281,13 @@ dir_add(const char *path, apr_pool_t *result_pool, void **child_baton) { + struct dir_baton_t *pb = parent_baton; + struct edit_baton_t *eb = pb->eb; struct dir_baton_t *db; + /* ### Our caller should be providing a scratch pool */ + apr_pool_t *scratch_pool = svn_pool_create(result_pool); - SVN_ERR(dir_open_or_add(path, parent_baton, &db)); + SVN_ERR(dir_open_or_add(&db, path, pb, eb, result_pool)); if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision)) { @@ -229,15 +297,16 @@ dir_add(const char *path, copyfrom_revision, db->local_abspath, db->eb->ra_session, - db->eb->ctx, db->pool)); - db->created = TRUE; + db->eb->ctx, + scratch_pool)); } else { - SVN_ERR(svn_io_make_dir_recursively(db->local_abspath, db->pool)); + SVN_ERR(mkdir(db->local_abspath, eb, result_pool)); } *child_baton = db; + svn_pool_destroy(scratch_pool); return SVN_NO_ERROR; } @@ -249,78 +318,19 @@ dir_change_prop(void *dir_baton, { struct dir_baton_t *db = dir_baton; struct edit_baton_t *eb = db->eb; - svn_prop_kind_t prop_kind; - - prop_kind = svn_property_kind2(name); - if (prop_kind != svn_prop_regular_kind + if (svn_property_kind2(name) != svn_prop_regular_kind || (eb->ignore_mergeinfo_changes && ! strcmp(name, SVN_PROP_MERGEINFO))) { /* We can't handle DAV, ENTRY and merge specific props here */ return SVN_NO_ERROR; } - if (! db->created) - { - /* Store properties to be added later in svn_wc_add_from_disk3() */ - if (! db->properties) - db->properties = apr_hash_make(db->pool); - - if (value != NULL) - svn_hash_sets(db->properties, apr_pstrdup(db->pool, name), - svn_string_dup(value, db->pool)); - } - else - { - SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, db->local_abspath, name, value, - svn_depth_empty, FALSE, NULL, - NULL, NULL, /* Cancellation */ - NULL, NULL, /* Notification */ - scratch_pool)); - } - - return SVN_NO_ERROR; -} - -/* Releases the directory baton if there are no more users */ -static svn_error_t * -maybe_done(struct dir_baton_t *db) -{ - db->users--; - - if (db->users == 0) - { - struct dir_baton_t *pb = db->pb; - - svn_pool_clear(db->pool); - - if (pb) - SVN_ERR(maybe_done(pb)); - } - - return SVN_NO_ERROR; -} - -static svn_error_t * -ensure_added(struct dir_baton_t *db, - apr_pool_t *scratch_pool) -{ - if (db->created) - return SVN_NO_ERROR; - - if (db->pb) - SVN_ERR(ensure_added(db->pb, scratch_pool)); - - db->created = TRUE; - - /* Add the directory with all the already collected properties */ - SVN_ERR(svn_wc_add_from_disk3(db->eb->wc_ctx, - db->local_abspath, - db->properties, - TRUE /* skip checks */, - db->eb->notify_func, - db->eb->notify_baton, - scratch_pool)); + SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, db->local_abspath, name, value, + svn_depth_empty, FALSE, NULL, + NULL, NULL, /* Cancellation */ + NULL, NULL, /* Notification */ + scratch_pool)); return SVN_NO_ERROR; } @@ -329,50 +339,57 @@ static svn_error_t * dir_close(void *dir_baton, apr_pool_t *scratch_pool) { - struct dir_baton_t *db = dir_baton; - /*struct edit_baton_t *eb = db->eb;*/ - - SVN_ERR(ensure_added(db, scratch_pool)); - - SVN_ERR(maybe_done(db)); - return SVN_NO_ERROR; } +/* Everything we need to know about a file that's open for edits. + */ struct file_baton_t { apr_pool_t *pool; - struct dir_baton_t *pb; struct edit_baton_t *eb; const char *local_abspath; - svn_boolean_t created; /* already under version control in the WC */ - apr_hash_t *properties; - - svn_boolean_t writing; - unsigned char digest[APR_MD5_DIGESTSIZE]; + /* fields for the transfer of text changes */ + const char *writing_file; + unsigned char digest[APR_MD5_DIGESTSIZE]; /* MD5 digest of new fulltext */ + svn_stream_t *wc_file_read_stream, *tmp_file_write_stream; const char *tmp_path; }; +/* Create a new file on disk and add it to version control. + * + * The file is empty and has no properties. + */ +static svn_error_t * +mkfile(const char *abspath, + struct edit_baton_t *eb, + apr_pool_t *scratch_pool) +{ + SVN_ERR(svn_io_file_create_empty(abspath, scratch_pool)); + SVN_ERR(svn_wc_add_from_disk3(eb->wc_ctx, abspath, + NULL /*properties*/, + TRUE /* skip checks */, + eb->notify_func, eb->notify_baton, + scratch_pool)); + return SVN_NO_ERROR; +} + /* */ static svn_error_t * file_open_or_add(const char *path, void *parent_baton, - struct file_baton_t **file_baton) + struct file_baton_t **file_baton, + apr_pool_t *file_pool) { struct dir_baton_t *pb = parent_baton; struct edit_baton_t *eb = pb->eb; - apr_pool_t *file_pool = svn_pool_create(pb->pool); struct file_baton_t *fb = apr_pcalloc(file_pool, sizeof(*fb)); - pb->users++; - fb->pool = file_pool; fb->eb = eb; - fb->pb = pb; - SVN_ERR(get_path(&fb->local_abspath, eb->anchor_abspath, path, fb->pool)); @@ -389,8 +406,7 @@ file_open(const char *path, { struct file_baton_t *fb; - SVN_ERR(file_open_or_add(path, parent_baton, &fb)); - fb->created = TRUE; + SVN_ERR(file_open_or_add(path, parent_baton, &fb, result_pool)); *file_baton = fb; return SVN_NO_ERROR; @@ -406,7 +422,7 @@ file_add(const char *path, { struct file_baton_t *fb; - SVN_ERR(file_open_or_add(path, parent_baton, &fb)); + SVN_ERR(file_open_or_add(path, parent_baton, &fb, result_pool)); if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision)) { @@ -417,7 +433,10 @@ file_add(const char *path, fb->local_abspath, fb->eb->ra_session, fb->eb->ctx, fb->pool)); - fb->created = TRUE; + } + else + { + SVN_ERR(mkfile(fb->local_abspath, fb->eb, result_pool)); } *file_baton = fb; @@ -432,35 +451,19 @@ file_change_prop(void *file_baton, { struct file_baton_t *fb = file_baton; struct edit_baton_t *eb = fb->eb; - svn_prop_kind_t prop_kind; - prop_kind = svn_property_kind2(name); - - if (prop_kind != svn_prop_regular_kind + if (svn_property_kind2(name) != svn_prop_regular_kind || (eb->ignore_mergeinfo_changes && ! strcmp(name, SVN_PROP_MERGEINFO))) { /* We can't handle DAV, ENTRY and merge specific props here */ return SVN_NO_ERROR; } - if (! fb->created) - { - /* Store properties to be added later in svn_wc_add_from_disk3() */ - if (! fb->properties) - fb->properties = apr_hash_make(fb->pool); - - if (value != NULL) - svn_hash_sets(fb->properties, apr_pstrdup(fb->pool, name), - svn_string_dup(value, fb->pool)); - } - else - { - SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, fb->local_abspath, name, value, - svn_depth_empty, FALSE, NULL, - NULL, NULL, /* Cancellation */ - NULL, NULL, /* Notification */ - scratch_pool)); - } + SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, fb->local_abspath, name, value, + svn_depth_empty, FALSE, NULL, + NULL, NULL, /* Cancellation */ + NULL, NULL, /* Notification */ + scratch_pool)); return SVN_NO_ERROR; } @@ -473,16 +476,27 @@ file_textdelta(void *file_baton, void **handler_baton) { struct file_baton_t *fb = file_baton; - svn_stream_t *target; + const char *target_dir = svn_dirent_dirname(fb->local_abspath, fb->pool); + svn_error_t *err; + + SVN_ERR_ASSERT(! fb->writing_file); - SVN_ERR_ASSERT(! fb->writing); + err = svn_stream_open_readonly(&fb->wc_file_read_stream, fb->local_abspath, + fb->pool, fb->pool); + if (err && APR_STATUS_IS_ENOENT(err->apr_err)) + { + svn_error_clear(err); + fb->wc_file_read_stream = svn_stream_empty(fb->pool); + } + else + SVN_ERR(err); - SVN_ERR(svn_stream_open_writable(&target, fb->local_abspath, fb->pool, - fb->pool)); + SVN_ERR(svn_stream_open_unique(&fb->tmp_file_write_stream, &fb->writing_file, + target_dir, svn_io_file_del_none, + fb->pool, fb->pool)); - fb->writing = TRUE; - svn_txdelta_apply(svn_stream_empty(fb->pool) /* source */, - target, + svn_txdelta_apply(fb->wc_file_read_stream, + fb->tmp_file_write_stream, fb->digest, fb->local_abspath, fb->pool, @@ -493,35 +507,19 @@ file_textdelta(void *file_baton, } static svn_error_t * -ensure_added_file(struct file_baton_t *fb, - apr_pool_t *scratch_pool) -{ - struct edit_baton_t *eb = fb->eb; - - if (fb->created) - return SVN_NO_ERROR; - - if (fb->pb) - SVN_ERR(ensure_added(fb->pb, scratch_pool)); - - fb->created = TRUE; - - /* Add the file with all the already collected properties */ - SVN_ERR(svn_wc_add_from_disk3(eb->wc_ctx, fb->local_abspath, fb->properties, - TRUE /* skip checks */, - eb->notify_func, eb->notify_baton, - fb->pool)); - - return SVN_NO_ERROR; -} - -static svn_error_t * file_close(void *file_baton, const char *text_checksum, apr_pool_t *scratch_pool) { struct file_baton_t *fb = file_baton; - struct dir_baton_t *pb = fb->pb; + + /* If we have text changes, write them to disk */ + if (fb->writing_file) + { + SVN_ERR(svn_stream_close(fb->wc_file_read_stream)); + SVN_ERR(svn_io_file_rename2(fb->writing_file, fb->local_abspath, + FALSE /*flush*/, scratch_pool)); + } if (text_checksum) { @@ -543,11 +541,6 @@ file_close(void *file_baton, fb->pool))); } - SVN_ERR(ensure_added_file(fb, fb->pool)); - - svn_pool_destroy(fb->pool); - SVN_ERR(maybe_done(pb)); - return SVN_NO_ERROR; } @@ -557,6 +550,7 @@ svn_client__wc_editor_internal(const svn const char *dst_abspath, svn_boolean_t root_dir_add, svn_boolean_t ignore_mergeinfo_changes, + svn_boolean_t manage_wc_write_lock, svn_wc_notify_func2_t notify_func, void *notify_baton, svn_ra_session_t *ra_session, @@ -566,8 +560,9 @@ svn_client__wc_editor_internal(const svn svn_delta_editor_t *editor = svn_delta_default_editor(result_pool); struct edit_baton_t *eb = apr_pcalloc(result_pool, sizeof(*eb)); - eb->pool = result_pool; eb->anchor_abspath = apr_pstrdup(result_pool, dst_abspath); + eb->manage_wc_write_lock = manage_wc_write_lock; + eb->lock_root_abspath = NULL; eb->root_dir_add = root_dir_add; eb->ignore_mergeinfo_changes = ignore_mergeinfo_changes; @@ -578,7 +573,8 @@ svn_client__wc_editor_internal(const svn eb->notify_baton = notify_baton; editor->open_root = edit_open; - editor->close_edit = edit_close; + editor->close_edit = edit_close_or_abort; + editor->abort_edit = edit_close_or_abort; editor->delete_entry = delete_entry; @@ -612,8 +608,48 @@ svn_client__wc_editor(const svn_delta_ed dst_abspath, FALSE /*root_dir_add*/, FALSE /*ignore_mergeinfo_changes*/, + TRUE /*manage_wc_write_lock*/, notify_func, notify_baton, ra_session, ctx, result_pool)); return SVN_NO_ERROR; } + +svn_error_t * +svn_client__wc_copy_mods(const char *src_wc_abspath, + const char *dst_wc_abspath, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + svn_client__pathrev_t *base; + const char *dst_wc_url; + svn_ra_session_t *ra_session; + const svn_delta_editor_t *editor; + void *edit_baton; + apr_array_header_t *src_targets = apr_array_make(scratch_pool, 1, + sizeof(char *)); + + /* We'll need an RA session to obtain the base of any copies */ + SVN_ERR(svn_client__wc_node_get_base(&base, + src_wc_abspath, ctx->wc_ctx, + scratch_pool, scratch_pool)); + dst_wc_url = base->url; + SVN_ERR(svn_client_open_ra_session2(&ra_session, + dst_wc_url, dst_wc_abspath, + ctx, scratch_pool, scratch_pool)); + SVN_ERR(svn_client__wc_editor(&editor, &edit_baton, + dst_wc_abspath, + NULL, NULL, /*notification*/ + ra_session, ctx, scratch_pool)); + + APR_ARRAY_PUSH(src_targets, const char *) = src_wc_abspath; + SVN_ERR(svn_client__wc_replay(src_wc_abspath, + src_targets, svn_depth_infinity, NULL, + editor, edit_baton, + notify_func, notify_baton, + ctx, scratch_pool)); + + return SVN_NO_ERROR; +}
Modified: subversion/branches/swig-py3/subversion/libsvn_delta/branch_compat.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_delta/branch_compat.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_delta/branch_compat.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_delta/branch_compat.c Mon Jul 8 15:19:03 2019 @@ -875,6 +875,8 @@ drive_ev1_props(const char *repos_relpat */ static svn_error_t * apply_change(void **dir_baton, + const svn_delta_editor_t *editor, + void *edit_baton, void *parent_baton, void *callback_baton, const char *ev1_relpath, @@ -905,7 +907,7 @@ apply_change(void **dir_baton, /* Only property edits are allowed on the root. */ SVN_ERR_ASSERT(change->action == RESTRUCTURE_NONE); SVN_ERR(drive_ev1_props(ev1_relpath, change, base_props, - eb->deditor, *dir_baton, scratch_pool)); + editor, *dir_baton, scratch_pool)); /* No further action possible for the root. */ return SVN_NO_ERROR; @@ -913,8 +915,8 @@ apply_change(void **dir_baton, if (change->action == RESTRUCTURE_DELETE) { - SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting_rev, - parent_baton, scratch_pool)); + SVN_ERR(editor->delete_entry(ev1_relpath, change->deleting_rev, + parent_baton, scratch_pool)); /* No futher action possible for this node. */ return SVN_NO_ERROR; @@ -927,11 +929,11 @@ apply_change(void **dir_baton, if (change->action == RESTRUCTURE_ADD_ABSENT) { if (change->kind == svn_node_dir) - SVN_ERR(eb->deditor->absent_directory(ev1_relpath, parent_baton, - scratch_pool)); - else if (change->kind == svn_node_file) - SVN_ERR(eb->deditor->absent_file(ev1_relpath, parent_baton, + SVN_ERR(editor->absent_directory(ev1_relpath, parent_baton, scratch_pool)); + else if (change->kind == svn_node_file) + SVN_ERR(editor->absent_file(ev1_relpath, parent_baton, + scratch_pool)); else SVN_ERR_MALFUNCTION(); @@ -948,8 +950,8 @@ apply_change(void **dir_baton, /* Do we have an old node to delete first? If so, delete it. */ if (change->deleting) - SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting_rev, - parent_baton, scratch_pool)); + SVN_ERR(editor->delete_entry(ev1_relpath, change->deleting_rev, + parent_baton, scratch_pool)); /* If it's a copy, determine the copy source location. */ if (change->copyfrom_path) @@ -974,13 +976,13 @@ apply_change(void **dir_baton, } if (change->kind == svn_node_dir) - SVN_ERR(eb->deditor->add_directory(ev1_relpath, parent_baton, - copyfrom_url, copyfrom_rev, - result_pool, dir_baton)); - else if (change->kind == svn_node_file) - SVN_ERR(eb->deditor->add_file(ev1_relpath, parent_baton, + SVN_ERR(editor->add_directory(ev1_relpath, parent_baton, copyfrom_url, copyfrom_rev, - result_pool, &file_baton)); + result_pool, dir_baton)); + else if (change->kind == svn_node_file) + SVN_ERR(editor->add_file(ev1_relpath, parent_baton, + copyfrom_url, copyfrom_rev, + result_pool, &file_baton)); else SVN_ERR_MALFUNCTION(); } @@ -993,13 +995,13 @@ apply_change(void **dir_baton, when we fetch the base properties.) */ if (change->kind == svn_node_dir) - SVN_ERR(eb->deditor->open_directory(ev1_relpath, parent_baton, - change->changing_rev, - result_pool, dir_baton)); - else if (change->kind == svn_node_file) - SVN_ERR(eb->deditor->open_file(ev1_relpath, parent_baton, + SVN_ERR(editor->open_directory(ev1_relpath, parent_baton, change->changing_rev, - result_pool, &file_baton)); + result_pool, dir_baton)); + else if (change->kind == svn_node_file) + SVN_ERR(editor->open_file(ev1_relpath, parent_baton, + change->changing_rev, + result_pool, &file_baton)); else SVN_ERR_MALFUNCTION(); } @@ -1007,10 +1009,10 @@ apply_change(void **dir_baton, /* Apply any properties in CHANGE to the node. */ if (change->kind == svn_node_dir) SVN_ERR(drive_ev1_props(ev1_relpath, change, base_props, - eb->deditor, *dir_baton, scratch_pool)); + editor, *dir_baton, scratch_pool)); else SVN_ERR(drive_ev1_props(ev1_relpath, change, base_props, - eb->deditor, file_baton, scratch_pool)); + editor, file_baton, scratch_pool)); /* Send the text content delta, if new text content is provided. */ if (change->contents_text) @@ -1023,7 +1025,7 @@ apply_change(void **dir_baton, scratch_pool); /* ### would be nice to have a BASE_CHECKSUM, but hey: this is the ### shim code... */ - SVN_ERR(eb->deditor->apply_textdelta(file_baton, NULL, scratch_pool, + SVN_ERR(editor->apply_textdelta(file_baton, NULL, scratch_pool, &handler, &handler_baton)); /* ### it would be nice to send a true txdelta here, but whatever. */ SVN_ERR(svn_txdelta_send_stream(read_stream, handler, handler_baton, @@ -1033,7 +1035,7 @@ apply_change(void **dir_baton, if (file_baton) { - SVN_ERR(eb->deditor->close_file(file_baton, NULL, scratch_pool)); + SVN_ERR(editor->close_file(file_baton, NULL, scratch_pool)); } return SVN_NO_ERROR; @@ -1740,7 +1742,7 @@ drive_changes(svn_branch__txn_priv_t *eb /* Apply the appropriate Ev1 change to each Ev1-relative path. */ paths = get_unsorted_paths(eb->changes, scratch_pool); - SVN_ERR(svn_delta_path_driver2(eb->deditor, eb->dedit_baton, + SVN_ERR(svn_delta_path_driver3(eb->deditor, eb->dedit_baton, paths, TRUE /*sort*/, apply_change, (void *)eb, scratch_pool)); Modified: subversion/branches/swig-py3/subversion/libsvn_delta/compat.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_delta/compat.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_delta/compat.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_delta/compat.c Mon Jul 8 15:19:03 2019 @@ -1577,6 +1577,8 @@ drive_ev1_props(const struct editor_bato /* Conforms to svn_delta_path_driver_cb_func_t */ static svn_error_t * apply_change(void **dir_baton, + const svn_delta_editor_t *deditor, + void *dedit_baton, void *parent_baton, void *callback_baton, const char *ev1_relpath, @@ -1614,8 +1616,8 @@ apply_change(void **dir_baton, if (change->action == RESTRUCTURE_DELETE) { - SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting, - parent_baton, scratch_pool)); + SVN_ERR(deditor->delete_entry(ev1_relpath, change->deleting, + parent_baton, scratch_pool)); /* No futher action possible for this node. */ return SVN_NO_ERROR; @@ -1627,11 +1629,11 @@ apply_change(void **dir_baton, if (change->action == RESTRUCTURE_ADD_ABSENT) { if (change->kind == svn_node_dir) - SVN_ERR(eb->deditor->absent_directory(ev1_relpath, parent_baton, - scratch_pool)); + SVN_ERR(deditor->absent_directory(ev1_relpath, parent_baton, + scratch_pool)); else - SVN_ERR(eb->deditor->absent_file(ev1_relpath, parent_baton, - scratch_pool)); + SVN_ERR(deditor->absent_file(ev1_relpath, parent_baton, + scratch_pool)); /* No further action possible for this node. */ return SVN_NO_ERROR; @@ -1645,8 +1647,8 @@ apply_change(void **dir_baton, /* Do we have an old node to delete first? */ if (SVN_IS_VALID_REVNUM(change->deleting)) - SVN_ERR(eb->deditor->delete_entry(ev1_relpath, change->deleting, - parent_baton, scratch_pool)); + SVN_ERR(deditor->delete_entry(ev1_relpath, change->deleting, + parent_baton, scratch_pool)); /* Are we copying the node from somewhere? */ if (change->copyfrom_path) @@ -1669,24 +1671,24 @@ apply_change(void **dir_baton, } if (change->kind == svn_node_dir) - SVN_ERR(eb->deditor->add_directory(ev1_relpath, parent_baton, - copyfrom_url, copyfrom_rev, - result_pool, dir_baton)); + SVN_ERR(deditor->add_directory(ev1_relpath, parent_baton, + copyfrom_url, copyfrom_rev, + result_pool, dir_baton)); else - SVN_ERR(eb->deditor->add_file(ev1_relpath, parent_baton, - copyfrom_url, copyfrom_rev, - result_pool, &file_baton)); + SVN_ERR(deditor->add_file(ev1_relpath, parent_baton, + copyfrom_url, copyfrom_rev, + result_pool, &file_baton)); } else { if (change->kind == svn_node_dir) - SVN_ERR(eb->deditor->open_directory(ev1_relpath, parent_baton, - change->changing, - result_pool, dir_baton)); + SVN_ERR(deditor->open_directory(ev1_relpath, parent_baton, + change->changing, + result_pool, dir_baton)); else - SVN_ERR(eb->deditor->open_file(ev1_relpath, parent_baton, - change->changing, - result_pool, &file_baton)); + SVN_ERR(deditor->open_file(ev1_relpath, parent_baton, + change->changing, + result_pool, &file_baton)); } /* Apply any properties in CHANGE to the node. */ @@ -1703,8 +1705,8 @@ apply_change(void **dir_baton, /* ### would be nice to have a BASE_CHECKSUM, but hey: this is the ### shim code... */ - SVN_ERR(eb->deditor->apply_textdelta(file_baton, NULL, scratch_pool, - &handler, &handler_baton)); + SVN_ERR(deditor->apply_textdelta(file_baton, NULL, scratch_pool, + &handler, &handler_baton)); SVN_ERR(svn_stream_open_readonly(&contents, change->contents_abspath, scratch_pool, scratch_pool)); /* ### it would be nice to send a true txdelta here, but whatever. */ @@ -1718,7 +1720,7 @@ apply_change(void **dir_baton, const char *digest = svn_checksum_to_cstring(change->checksum, scratch_pool); - SVN_ERR(eb->deditor->close_file(file_baton, digest, scratch_pool)); + SVN_ERR(deditor->close_file(file_baton, digest, scratch_pool)); } return SVN_NO_ERROR; @@ -1747,7 +1749,7 @@ drive_changes(const struct editor_baton /* Get a sorted list of Ev1-relative paths. */ paths = get_sorted_paths(eb->changes, eb->base_relpath, scratch_pool); - SVN_ERR(svn_delta_path_driver2(eb->deditor, eb->dedit_baton, paths, + SVN_ERR(svn_delta_path_driver3(eb->deditor, eb->dedit_baton, paths, FALSE, apply_change, (void *)eb, scratch_pool)); Modified: subversion/branches/swig-py3/subversion/libsvn_delta/deprecated.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_delta/deprecated.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_delta/deprecated.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_delta/deprecated.c Mon Jul 8 15:19:03 2019 @@ -30,6 +30,79 @@ #include "svn_sorts.h" +struct path_driver_2_to_3_baton_t +{ + svn_delta_path_driver_cb_func_t callback_func; + void *callback_baton; + svn_boolean_t slash_prefix; +}; + +/* Convert from a newer to older callback + */ +static svn_error_t * +path_driver_2_to_3_func(void **dir_baton, + const svn_delta_editor_t *editor, + void *edit_baton, + void *parent_baton, + void *callback_baton, + const char *path, + apr_pool_t *pool) +{ + struct path_driver_2_to_3_baton_t *b = callback_baton; + + if (b->slash_prefix) + path = apr_pstrcat(pool, "/", path, SVN_VA_NULL); + + /* Just drop the 'editor' parameters */ + SVN_ERR(b->callback_func(dir_baton, parent_baton, + b->callback_baton, + path, pool)); + return SVN_NO_ERROR; +} + +svn_error_t * +svn_delta_path_driver2(const svn_delta_editor_t *editor, + void *edit_baton, + const apr_array_header_t *paths, + svn_boolean_t sort_paths, + svn_delta_path_driver_cb_func_t callback_func, + void *callback_baton, + apr_pool_t *pool) +{ + struct path_driver_2_to_3_baton_t b; + int i; + + b.callback_func = callback_func; + b.callback_baton = callback_baton; + b.slash_prefix = FALSE; + + /* Remove any '/' prefix from incoming paths. Arrange to add a '/' + prefix to all paths for the callback, if any incoming path had one. */ + for (i = 0; i < paths->nelts; i++) + { + const char *path = APR_ARRAY_IDX(paths, i, const char *); + + if (path[0] == '/') + { + /* Re-allocate the array and note that we found a '/' prefix. */ + if (!b.slash_prefix) + { + paths = apr_array_copy(pool, paths); + b.slash_prefix = TRUE; + } + + /* Modify each array element that had a '/' prefix */ + APR_ARRAY_IDX(paths, i, const char *) = path + 1; + } + } + + SVN_ERR(svn_delta_path_driver3(editor, edit_baton, + paths, sort_paths, + path_driver_2_to_3_func, &b, + pool)); + return SVN_NO_ERROR; +} + svn_error_t * svn_delta_path_driver(const svn_delta_editor_t *editor, void *edit_baton, Modified: subversion/branches/swig-py3/subversion/libsvn_delta/path_driver.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_delta/path_driver.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_delta/path_driver.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_delta/path_driver.c Mon Jul 8 15:19:03 2019 @@ -31,7 +31,6 @@ #include "svn_dirent_uri.h" #include "svn_path.h" #include "svn_sorts.h" -#include "private/svn_fspath.h" #include "private/svn_sorts_private.h" @@ -45,6 +44,22 @@ typedef struct dir_stack_t } dir_stack_t; +/* Push onto dir_stack a new item allocated in POOL and containing + * DIR_BATON and POOL. + */ +static void +push_dir_stack_item(apr_array_header_t *db_stack, + void *dir_baton, + apr_pool_t *pool) +{ + dir_stack_t *item = apr_pcalloc(pool, sizeof(*item)); + + item->dir_baton = dir_baton; + item->pool = pool; + APR_ARRAY_PUSH(db_stack, dir_stack_t *) = item; +} + + /* Call EDITOR's open_directory() function with the PATH argument, then * add the resulting dir baton to the dir baton stack. */ @@ -72,10 +87,7 @@ open_dir(apr_array_header_t *db_stack, &db)); /* Now add the dir baton to the stack. */ - item = apr_pcalloc(subpool, sizeof(*item)); - item->dir_baton = db; - item->pool = subpool; - APR_ARRAY_PUSH(db_stack, dir_stack_t *) = item; + push_dir_stack_item(db_stack, db, subpool); return SVN_NO_ERROR; } @@ -131,168 +143,215 @@ count_components(const char *path) /*** Public interfaces ***/ svn_error_t * -svn_delta_path_driver2(const svn_delta_editor_t *editor, +svn_delta_path_driver3(const svn_delta_editor_t *editor, void *edit_baton, - const apr_array_header_t *paths, + const apr_array_header_t *relpaths, svn_boolean_t sort_paths, - svn_delta_path_driver_cb_func_t callback_func, + svn_delta_path_driver_cb_func2_t callback_func, void *callback_baton, apr_pool_t *pool) { - apr_array_header_t *db_stack = apr_array_make(pool, 4, sizeof(void *)); - const char *last_path = NULL; - int i = 0; - void *parent_db = NULL, *db = NULL; - const char *path; + svn_delta_path_driver_state_t *state; + int i; apr_pool_t *subpool, *iterpool; - dir_stack_t *item; /* Do nothing if there are no paths. */ - if (! paths->nelts) + if (! relpaths->nelts) return SVN_NO_ERROR; subpool = svn_pool_create(pool); iterpool = svn_pool_create(pool); /* sort paths if necessary */ - if (sort_paths && paths->nelts > 1) + if (sort_paths && relpaths->nelts > 1) { - apr_array_header_t *sorted = apr_array_copy(subpool, paths); + apr_array_header_t *sorted = apr_array_copy(subpool, relpaths); svn_sort__array(sorted, svn_sort_compare_paths); - paths = sorted; + relpaths = sorted; } - item = apr_pcalloc(subpool, sizeof(*item)); - - /* If the root of the edit is also a target path, we want to call - the callback function to let the user open the root directory and - do what needs to be done. Otherwise, we'll do the open_root() - ourselves. */ - path = APR_ARRAY_IDX(paths, 0, const char *); - if (svn_path_is_empty(path)) - { - SVN_ERR(callback_func(&db, NULL, callback_baton, path, subpool)); - last_path = path; - i++; - } - else - { - SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM, subpool, &db)); - } - item->pool = subpool; - item->dir_baton = db; - APR_ARRAY_PUSH(db_stack, void *) = item; + SVN_ERR(svn_delta_path_driver_start(&state, + editor, edit_baton, + callback_func, callback_baton, + pool)); /* Now, loop over the commit items, traversing the URL tree and driving the editor. */ - for (; i < paths->nelts; i++) + for (i = 0; i < relpaths->nelts; i++) { - const char *pdir; - const char *common = ""; - size_t common_len; + const char *relpath; /* Clear the iteration pool. */ svn_pool_clear(iterpool); /* Get the next path. */ - path = APR_ARRAY_IDX(paths, i, const char *); + relpath = APR_ARRAY_IDX(relpaths, i, const char *); - /*** Step A - Find the common ancestor of the last path and the - current one. For the first iteration, this is just the - empty string. ***/ - if (i > 0) - common = (last_path[0] == '/') - ? svn_fspath__get_longest_ancestor(last_path, path, iterpool) - : svn_relpath_get_longest_ancestor(last_path, path, iterpool); - common_len = strlen(common); - - /*** Step B - Close any directories between the last path and - the new common ancestor, if any need to be closed. - Sometimes there is nothing to do here (like, for the first - iteration, or when the last path was an ancestor of the - current one). ***/ - if ((i > 0) && (strlen(last_path) > common_len)) - { - const char *rel = last_path + (common_len ? (common_len + 1) : 0); - int count = count_components(rel); - while (count--) - { - SVN_ERR(pop_stack(db_stack, editor)); - } - } + SVN_ERR(svn_delta_path_driver_step(state, relpath, iterpool)); + } - /*** Step C - Open any directories between the common ancestor - and the parent of the current path. ***/ - if (*path == '/') - pdir = svn_fspath__dirname(path, iterpool); - else - pdir = svn_relpath_dirname(path, iterpool); + /* Destroy the iteration subpool. */ + svn_pool_destroy(iterpool); - if (strlen(pdir) > common_len) - { - const char *piece = pdir + common_len + 1; + SVN_ERR(svn_delta_path_driver_finish(state, pool)); - while (1) - { - const char *rel = pdir; - - /* Find the first separator. */ - piece = strchr(piece, '/'); - - /* Calculate REL as the portion of PDIR up to (but not - including) the location to which PIECE is pointing. */ - if (piece) - rel = apr_pstrmemdup(iterpool, pdir, piece - pdir); - - /* Open the subdirectory. */ - SVN_ERR(open_dir(db_stack, editor, rel, pool)); - - /* If we found a '/', advance our PIECE pointer to - character just after that '/'. Otherwise, we're - done. */ - if (piece) - piece++; - else - break; - } - } + return SVN_NO_ERROR; +} - /*** Step D - Tell our caller to handle the current path. ***/ - item = APR_ARRAY_IDX(db_stack, db_stack->nelts - 1, void *); - parent_db = item->dir_baton; - subpool = svn_pool_create(pool); - SVN_ERR(callback_func(&db, parent_db, callback_baton, path, subpool)); - if (db) +struct svn_delta_path_driver_state_t +{ + const svn_delta_editor_t *editor; + void *edit_baton; + svn_delta_path_driver_cb_func2_t callback_func; + void *callback_baton; + apr_array_header_t *db_stack; + const char *last_path; + apr_pool_t *pool; /* at least the lifetime of the entire drive */ +}; + +svn_error_t * +svn_delta_path_driver_start(svn_delta_path_driver_state_t **state_p, + const svn_delta_editor_t *editor, + void *edit_baton, + svn_delta_path_driver_cb_func2_t callback_func, + void *callback_baton, + apr_pool_t *pool) +{ + svn_delta_path_driver_state_t *state = apr_pcalloc(pool, sizeof(*state)); + + state->editor = editor; + state->edit_baton = edit_baton; + state->callback_func = callback_func; + state->callback_baton = callback_baton; + state->db_stack = apr_array_make(pool, 4, sizeof(void *)); + state->last_path = NULL; + state->pool = pool; + + *state_p = state; + return SVN_NO_ERROR; +} + +svn_error_t * +svn_delta_path_driver_step(svn_delta_path_driver_state_t *state, + const char *relpath, + apr_pool_t *scratch_pool) +{ + const char *pdir; + const char *common = ""; + size_t common_len; + apr_pool_t *subpool; + dir_stack_t *item; + void *parent_db, *db; + + SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath)); + + /* If the first target path is not the root of the edit, we must first + call open_root() ourselves. (If the first target path is the root of + the edit, then we expect the user's callback to do so.) */ + if (!state->last_path && !svn_path_is_empty(relpath)) + { + subpool = svn_pool_create(state->pool); + SVN_ERR(state->editor->open_root(state->edit_baton, SVN_INVALID_REVNUM, + subpool, &db)); + push_dir_stack_item(state->db_stack, db, subpool); + } + + /*** Step A - Find the common ancestor of the last path and the + current one. For the first iteration, this is just the + empty string. ***/ + if (state->last_path) + common = svn_relpath_get_longest_ancestor(state->last_path, relpath, + scratch_pool); + common_len = strlen(common); + + /*** Step B - Close any directories between the last path and + the new common ancestor, if any need to be closed. + Sometimes there is nothing to do here (like, for the first + iteration, or when the last path was an ancestor of the + current one). ***/ + if ((state->last_path) && (strlen(state->last_path) > common_len)) + { + const char *rel = state->last_path + (common_len ? (common_len + 1) : 0); + int count = count_components(rel); + while (count--) { - item = apr_pcalloc(subpool, sizeof(*item)); - item->dir_baton = db; - item->pool = subpool; - APR_ARRAY_PUSH(db_stack, void *) = item; + SVN_ERR(pop_stack(state->db_stack, state->editor)); } - else + } + + /*** Step C - Open any directories between the common ancestor + and the parent of the current path. ***/ + pdir = svn_relpath_dirname(relpath, scratch_pool); + + if (strlen(pdir) > common_len) + { + const char *piece = pdir + common_len + 1; + + while (1) { - svn_pool_destroy(subpool); + const char *rel = pdir; + + /* Find the first separator. */ + piece = strchr(piece, '/'); + + /* Calculate REL as the portion of PDIR up to (but not + including) the location to which PIECE is pointing. */ + if (piece) + rel = apr_pstrmemdup(scratch_pool, pdir, piece - pdir); + + /* Open the subdirectory. */ + SVN_ERR(open_dir(state->db_stack, state->editor, rel, state->pool)); + + /* If we found a '/', advance our PIECE pointer to + character just after that '/'. Otherwise, we're + done. */ + if (piece) + piece++; + else + break; } + } - /*** Step E - Save our state for the next iteration. If our - caller opened or added PATH as a directory, that becomes - our LAST_PATH. Otherwise, we use PATH's parent - directory. ***/ - - /* NOTE: The variable LAST_PATH needs to outlive the loop. */ - if (db) - last_path = path; /* lives in a pool outside our control. */ - else - last_path = apr_pstrdup(pool, pdir); /* duping into POOL. */ + /*** Step D - Tell our caller to handle the current path. ***/ + if (state->db_stack->nelts) + { + item = APR_ARRAY_IDX(state->db_stack, state->db_stack->nelts - 1, void *); + parent_db = item->dir_baton; + } + else + parent_db = NULL; + db = NULL; /* predictable behaviour for callbacks that don't set it */ + subpool = svn_pool_create(state->pool); + SVN_ERR(state->callback_func(&db, + state->editor, state->edit_baton, parent_db, + state->callback_baton, + relpath, subpool)); + if (db) + { + push_dir_stack_item(state->db_stack, db, subpool); + } + else + { + svn_pool_destroy(subpool); } - /* Destroy the iteration subpool. */ - svn_pool_destroy(iterpool); + /*** Step E - Save our state for the next iteration. If our + caller opened or added PATH as a directory, that becomes + our LAST_PATH. Otherwise, we use PATH's parent + directory. ***/ + state->last_path = apr_pstrdup(state->pool, db ? relpath : pdir); + + return SVN_NO_ERROR; +} +svn_error_t * +svn_delta_path_driver_finish(svn_delta_path_driver_state_t *state, + apr_pool_t *scratch_pool) +{ /* Close down any remaining open directory batons. */ - while (db_stack->nelts) + while (state->db_stack->nelts) { - SVN_ERR(pop_stack(db_stack, editor)); + SVN_ERR(pop_stack(state->db_stack, state->editor)); } return SVN_NO_ERROR; Modified: subversion/branches/swig-py3/subversion/libsvn_fs/fs-loader.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_fs/fs-loader.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_fs/fs-loader.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_fs/fs-loader.c Mon Jul 8 15:19:03 2019 @@ -2221,3 +2221,42 @@ svn_fs_info_dup(const void *info_void, return apr_pmemdup(result_pool, info, sizeof(*info)); } +svn_error_t * +svn_fs_ioctl(svn_fs_t *fs, + svn_fs_ioctl_code_t ctlcode, + void *input, + void **output_p, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + void *output; + + if (fs) + { + if (!fs->vtable->ioctl) + return svn_error_create(SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE, NULL, NULL); + + SVN_ERR(fs->vtable->ioctl(fs, ctlcode, input, &output, + cancel_func, cancel_baton, + result_pool, scratch_pool)); + } + else + { + fs_library_vtable_t *vtable; + + SVN_ERR(get_library_vtable(&vtable, ctlcode.fs_type, scratch_pool)); + + if (!vtable->ioctl) + return svn_error_create(SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE, NULL, NULL); + + SVN_ERR(vtable->ioctl(ctlcode, input, &output, + cancel_func, cancel_baton, + result_pool, scratch_pool)); + } + + if (output_p) + *output_p = output; + return SVN_NO_ERROR; +} Modified: subversion/branches/swig-py3/subversion/libsvn_fs/fs-loader.h URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_fs/fs-loader.h?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_fs/fs-loader.h (original) +++ subversion/branches/swig-py3/subversion/libsvn_fs/fs-loader.h Mon Jul 8 15:19:03 2019 @@ -159,6 +159,13 @@ typedef struct fs_library_vtable_t /* For svn_fs_info_fsfs_dup(). */ void *(*info_fsap_dup)(const void *fsap_info, apr_pool_t *result_pool); + + svn_error_t *(*ioctl)(svn_fs_ioctl_code_t ctlcode, + void *input, void **output_p, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); } fs_library_vtable_t; /* This is the type of symbol an FS module defines to fetch the @@ -266,6 +273,12 @@ typedef struct fs_vtable_t svn_error_t *(*bdb_set_errcall)(svn_fs_t *fs, void (*handler)(const char *errpfx, char *msg)); + svn_error_t *(*ioctl)(svn_fs_t *fs, svn_fs_ioctl_code_t ctlcode, + void *input, void **output_p, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); } fs_vtable_t; Modified: subversion/branches/swig-py3/subversion/libsvn_fs_base/fs.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_fs_base/fs.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_fs_base/fs.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_fs_base/fs.c Mon Jul 8 15:19:03 2019 @@ -574,6 +574,7 @@ static fs_vtable_t fs_vtable = { base_bdb_verify_root, base_bdb_freeze, base_bdb_set_errcall, + NULL /* ioctl */ }; /* Where the format number is stored. */ @@ -1515,7 +1516,8 @@ static fs_library_vtable_t library_vtabl base_bdb_logfiles, svn_fs_base__id_parse, base_set_svn_fs_open, - NULL /* info_fsap_dup */ + NULL /* info_fsap_dup */, + NULL /* ioctl */ }; svn_error_t * Modified: subversion/branches/swig-py3/subversion/libsvn_fs_fs/dump-index.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_fs_fs/dump-index.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_fs_fs/dump-index.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_fs_fs/dump-index.c Mon Jul 8 15:19:03 2019 @@ -21,8 +21,8 @@ */ #include "svn_pools.h" -#include "private/svn_fs_fs_private.h" +#include "fs_fs.h" #include "index.h" #include "rev_file.h" #include "util.h" Modified: subversion/branches/swig-py3/subversion/libsvn_fs_fs/fs.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_fs_fs/fs.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_fs_fs/fs.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_fs_fs/fs.c Mon Jul 8 15:19:03 2019 @@ -47,6 +47,7 @@ #include "verify.h" #include "svn_private_config.h" #include "private/svn_fs_util.h" +#include "private/svn_fs_fs_private.h" #include "../libsvn_fs/fs-loader.h" @@ -254,6 +255,67 @@ fs_set_uuid(svn_fs_t *fs, } +static svn_error_t * +fs_ioctl(svn_fs_t *fs, svn_fs_ioctl_code_t ctlcode, + void *input_void, void **output_p, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + if (strcmp(ctlcode.fs_type, SVN_FS_TYPE_FSFS) == 0) + { + if (ctlcode.code == SVN_FS_FS__IOCTL_GET_STATS.code) + { + svn_fs_fs__ioctl_get_stats_input_t *input = input_void; + svn_fs_fs__ioctl_get_stats_output_t *output; + + output = apr_pcalloc(result_pool, sizeof(*output)); + SVN_ERR(svn_fs_fs__get_stats(&output->stats, fs, + input->progress_func, + input->progress_baton, + cancel_func, cancel_baton, + result_pool, scratch_pool)); + *output_p = output; + } + else if (ctlcode.code == SVN_FS_FS__IOCTL_DUMP_INDEX.code) + { + svn_fs_fs__ioctl_dump_index_input_t *input = input_void; + + SVN_ERR(svn_fs_fs__dump_index(fs, input->revision, + input->callback_func, + input->callback_baton, + cancel_func, cancel_baton, + scratch_pool)); + *output_p = NULL; + } + else if (ctlcode.code == SVN_FS_FS__IOCTL_LOAD_INDEX.code) + { + svn_fs_fs__ioctl_load_index_input_t *input = input_void; + + SVN_ERR(svn_fs_fs__load_index(fs, input->revision, input->entries, + scratch_pool)); + *output_p = NULL; + } + else if (ctlcode.code == SVN_FS_FS__IOCTL_REVISION_SIZE.code) + { + svn_fs_fs__ioctl_revision_size_input_t *input = input_void; + svn_fs_fs__ioctl_revision_size_output_t *output + = apr_pcalloc(result_pool, sizeof(*output)); + + SVN_ERR(svn_fs_fs__revision_size(&output->rev_size, + fs, input->revision, + scratch_pool)); + *output_p = output; + } + else + return svn_error_create(SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE, NULL, NULL); + } + else + return svn_error_create(SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE, NULL, NULL); + + return SVN_NO_ERROR; +} /* The vtable associated with a specific open filesystem. */ static fs_vtable_t fs_vtable = { @@ -279,7 +341,8 @@ static fs_vtable_t fs_vtable = { fs_info, svn_fs_fs__verify_root, fs_freeze, - fs_set_errcall + fs_set_errcall, + fs_ioctl }; @@ -602,7 +665,8 @@ static fs_library_vtable_t library_vtabl fs_logfiles, NULL /* parse_id */, fs_set_svn_fs_open, - fs_info_dup + fs_info_dup, + NULL /* ioctl */ }; svn_error_t * Modified: subversion/branches/swig-py3/subversion/libsvn_fs_fs/fs_fs.h URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_fs_fs/fs_fs.h?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_fs_fs/fs_fs.h (original) +++ subversion/branches/swig-py3/subversion/libsvn_fs_fs/fs_fs.h Mon Jul 8 15:19:03 2019 @@ -304,4 +304,56 @@ svn_fs_fs__initialize_txn_caches(svn_fs_ void svn_fs_fs__reset_txn_caches(svn_fs_t *fs); +/* Scan all contents of the repository FS and return statistics in *STATS, + * allocated in RESULT_POOL. Report progress through PROGRESS_FUNC with + * PROGRESS_BATON, if PROGRESS_FUNC is not NULL. + * Use SCRATCH_POOL for temporary allocations. + */ +svn_error_t * +svn_fs_fs__get_stats(svn_fs_fs__stats_t **stats, + svn_fs_t *fs, + svn_fs_progress_notify_func_t progress_func, + void *progress_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Read the P2L index for the rev / pack file containing REVISION in FS. + * For each index entry, invoke CALLBACK_FUNC with CALLBACK_BATON. + * If not NULL, call CANCEL_FUNC with CANCEL_BATON from time to time. + * Use SCRATCH_POOL for temporary allocations. + */ +svn_error_t * +svn_fs_fs__dump_index(svn_fs_t *fs, + svn_revnum_t revision, + svn_fs_fs__dump_index_func_t callback_func, + void *callback_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool); + + +/* Rewrite the respective index information of the rev / pack file in FS + * containing REVISION and use the svn_fs_fs__p2l_entry_t * array ENTRIES + * as the new index contents. Allocate temporaries from SCRATCH_POOL. + * + * Note that this becomes a no-op if ENTRIES is empty. You may use a zero- + * sized empty entry instead. + */ +svn_error_t * +svn_fs_fs__load_index(svn_fs_t *fs, + svn_revnum_t revision, + apr_array_header_t *entries, + apr_pool_t *scratch_pool); + +/* Set *REV_SIZE to the total size of objects belonging to revision REVISION + * in FS. The size includes revision properties and excludes indexes. + */ +svn_error_t * +svn_fs_fs__revision_size(apr_off_t *rev_size, + svn_fs_t *fs, + svn_revnum_t revision, + apr_pool_t *scratch_pool); + #endif Modified: subversion/branches/swig-py3/subversion/libsvn_fs_fs/load-index.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_fs_fs/load-index.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_fs_fs/load-index.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_fs_fs/load-index.c Mon Jul 8 15:19:03 2019 @@ -22,9 +22,9 @@ #include "svn_pools.h" -#include "private/svn_fs_fs_private.h" #include "private/svn_sorts_private.h" +#include "fs_fs.h" #include "index.h" #include "util.h" #include "transaction.h" Modified: subversion/branches/swig-py3/subversion/libsvn_fs_fs/revprops.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_fs_fs/revprops.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_fs_fs/revprops.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_fs_fs/revprops.c Mon Jul 8 15:19:03 2019 @@ -672,6 +672,64 @@ read_pack_revprop(packed_revprops_t **re return SVN_NO_ERROR; } +svn_error_t * +svn_fs_fs__get_revision_props_size(apr_off_t *props_size_p, + svn_fs_t *fs, + svn_revnum_t rev, + apr_pool_t *scratch_pool) +{ + fs_fs_data_t *ffd = fs->fsap_data; + + /* should they be available at all? */ + SVN_ERR(svn_fs_fs__ensure_revision_exists(rev, fs, scratch_pool)); + + /* if REV had not been packed when we began, try reading it from the + * non-packed shard. If that fails, we will fall through to packed + * shard reads. */ + if (!svn_fs_fs__is_packed_revprop(fs, rev)) + { + const char *path = svn_fs_fs__path_revprops(fs, rev, scratch_pool); + svn_error_t *err; + apr_file_t *file; + svn_filesize_t file_size; + + err = svn_io_file_open(&file, path, APR_FOPEN_READ, APR_OS_DEFAULT, + scratch_pool); + if (!err) + err = svn_io_file_size_get(&file_size, file, scratch_pool); + if (!err) + { + *props_size_p = (apr_off_t)file_size; + return SVN_NO_ERROR; + } + else if (!APR_STATUS_IS_ENOENT(err->apr_err) + || ffd->format < SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT) + { + return svn_error_trace(err); + } + + /* fall through: maybe the revision got packed while we were looking */ + svn_error_clear(err); + } + + /* Try reading packed revprops. If that fails, REV is most + * likely invalid (or its revprops highly contested). */ + { + packed_revprops_t *revprops; + + /* ### This is inefficient -- reading all the revprops in a pack. We + should just read the index. */ + SVN_ERR(read_pack_revprop(&revprops, fs, rev, + TRUE /*read_all*/, FALSE /*populate_cache*/, + scratch_pool)); + *props_size_p = (apr_off_t)APR_ARRAY_IDX(revprops->sizes, + rev - revprops->start_revision, + apr_size_t); + } + + return SVN_NO_ERROR; +} + /* Read the revprops for revision REV in FS and return them in *PROPERTIES_P. * * Allocations will be done in POOL. Modified: subversion/branches/swig-py3/subversion/libsvn_fs_fs/revprops.h URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_fs_fs/revprops.h?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_fs_fs/revprops.h (original) +++ subversion/branches/swig-py3/subversion/libsvn_fs_fs/revprops.h Mon Jul 8 15:19:03 2019 @@ -62,6 +62,15 @@ svn_fs_fs__upgrade_cleanup_pack_revprops void svn_fs_fs__reset_revprop_cache(svn_fs_t *fs); +/* Set *PROPS_SIZE_P to the size in bytes on disk of the revprops for + * revision REV in FS. The size excludes indexes. + */ +svn_error_t * +svn_fs_fs__get_revision_props_size(apr_off_t *props_size_p, + svn_fs_t *fs, + svn_revnum_t rev, + apr_pool_t *scratch_pool); + /* Read the revprops for revision REV in FS and return them in *PROPERTIES_P. * If REFRESH is set, clear the revprop cache before accessing the data. * Modified: subversion/branches/swig-py3/subversion/libsvn_fs_fs/stats.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_fs_fs/stats.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_fs_fs/stats.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_fs_fs/stats.c Mon Jul 8 15:19:03 2019 @@ -28,7 +28,6 @@ #include "private/svn_cache.h" #include "private/svn_sorts_private.h" #include "private/svn_string_private.h" -#include "private/svn_fs_fs_private.h" #include "index.h" #include "pack.h" @@ -37,6 +36,7 @@ #include "fs_fs.h" #include "cached_data.h" #include "low_level.h" +#include "revprops.h" #include "../libsvn_fs/fs-loader.h" @@ -1397,3 +1397,96 @@ svn_fs_fs__get_stats(svn_fs_fs__stats_t return SVN_NO_ERROR; } + +/* Baton for rev_size_index_entry_cb. */ +struct rev_size_baton_t { + svn_revnum_t revision; + apr_off_t rev_size; +}; + +/* Implements svn_fs_fs__dump_index_func_t, summing object sizes for + * revision BATON->revision into BATON->rev_size. + */ +static svn_error_t * +rev_size_index_entry_cb(const svn_fs_fs__p2l_entry_t *entry, + void *baton, + apr_pool_t *scratch_pool) +{ + struct rev_size_baton_t *b = baton; + + if (entry->item.revision == b->revision) + b->rev_size += entry->size; + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_fs__revision_size(apr_off_t *rev_size, + svn_fs_t *fs, + svn_revnum_t revision, + apr_pool_t *scratch_pool) +{ + /* Get the size of the revision (excluding rev-props) */ + if (svn_fs_fs__use_log_addressing(fs)) + { + /* This works for a packed or a non-packed revision. + We could provide an optimized case for a non-packed revision + using svn_fs_fs__p2l_get_max_offset(). */ + struct rev_size_baton_t b = { 0, 0 }; + + b.revision = revision; + SVN_ERR(svn_fs_fs__dump_index(fs, revision, + rev_size_index_entry_cb, &b, + NULL, NULL, scratch_pool)); + *rev_size = b.rev_size; + } + else + { + svn_fs_fs__revision_file_t *rev_file; + svn_revnum_t min_unpacked_rev; + + SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, fs, revision, + scratch_pool, scratch_pool)); + SVN_ERR(svn_fs_fs__min_unpacked_rev(&min_unpacked_rev, fs, + scratch_pool)); + if (revision < min_unpacked_rev) + { + int shard_size = svn_fs_fs__shard_size(fs); + apr_off_t start_offset, end_offset; + + SVN_ERR(svn_fs_fs__get_packed_offset(&start_offset, fs, revision, + scratch_pool)); + if (((revision + 1) % shard_size) == 0) + { + svn_filesize_t file_size; + + SVN_ERR(svn_io_file_size_get(&file_size, rev_file->file, scratch_pool)); + end_offset = (apr_off_t)file_size; + } + else + { + SVN_ERR(svn_fs_fs__get_packed_offset(&end_offset, fs, + revision + 1, scratch_pool)); + } + *rev_size = (end_offset - start_offset); + } + else + { + svn_filesize_t file_size; + + SVN_ERR(svn_io_file_size_get(&file_size, rev_file->file, scratch_pool)); + *rev_size = (apr_off_t)file_size; + } + + SVN_ERR(svn_fs_fs__close_revision_file(rev_file)); + } + + /* Add the size of the rev-props */ + { + apr_off_t size; + + SVN_ERR(svn_fs_fs__get_revision_props_size(&size, fs, revision, scratch_pool)); + *rev_size += size; + } + + return SVN_NO_ERROR; +} Propchange: subversion/branches/swig-py3/subversion/libsvn_fs_x/ ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Mon Jul 8 15:19:03 2019 @@ -96,4 +96,4 @@ /subversion/branches/verify-keep-going/subversion/libsvn_fs_x:1439280-1492639,1546002-1546110 /subversion/branches/wc-collate-path/subversion/libsvn_fs_x:1402685-1480384 /subversion/trunk/subversion/libsvn_fs_fs:1415133-1596500,1596567,1597414,1597989,1598273,1599140,1600872,1601633,1603485-1603487,1603499,1603605,1604128,1604188,1604413-1604414,1604416-1604417,1604421,1604442,1604700,1604717,1604720,1604726,1604755,1604794,1604802,1604824,1604836,1604844,1604902-1604903,1604911,1604925,1604933,1604947,1605059-1605060,1605064-1605065,1605068,1605071-1605073,1605075,1605123,1605188-1605189,1605191,1605197,1605444,1605633,1606132,1606142,1606144,1606514,1606526,1606528,1606551,1606554,1606564,1606598-1606599,1606656,1606658,1606662,1606744,1606840,1607085,1607572,1612407,1612810,1613339,1613872,1614611,1615348,1615351-1615352,1615356,1616338-1616339,1616613,1617586,1617688,1618138,1618151,1618153,1618226,1618641,1618653,1618662,1619068,1619358,1619413,1619769,1619774,1620602,1620909,1620912,1620928,1620930,1621275,1621635,1622931,1622937,1622942,1622946,1622959-1622960,1622963,1622987,1623007,1623368,1623373,1623377,1623379,1623381,1623398,1623402,162 4011,1624265,1624512,1626246,1626871,1626873,1626886,1627497-1627498,1627502,1627947-1627949,1627966,1628083,1628093,1628158-1628159,1628161,1628392-1628393,1628415,1628427,1628676,1628738,1628762,1628764,1629854-1629855,1629857,1629865,1629873,1629875,1629879,1630067,1630070,1631049-1631051,1631075,1631115,1631171,1631180,1631185-1631186,1631196-1631197,1631239-1631240,1631548,1631550,1631563,1631567,1631588,1631598,1632646,1632776,1632849,1632851-1632853,1632856-1632857,1632868,1632908,1632926,1633232,1633617-1633618,1634872,1634875,1634879-1634880,1634920,1636478,1636483,1636629,1636644,1637184,1637186,1637330,1637358,1637363,1637393,1639319,1639322,1639335,1639348,1639352,1639355,1639358,1639414,1639419,1639426,1639430,1639436,1639440,1639549,1640061-1640062,1640197,1640915,1640966,1641013,1643139,1643233,1645567,1646021,1646712,1646716,1647537,1647540-1647541,1647820,1647905,1648230,1648238,1648241-1648243,1648253,1648272,1648532,1648537-1648539,1648542,1648591,1648612,1649590, 1651567,1652068,1652076,1652441,1652451,1653608,1654932,1654934,1654937,1655635,1655649,1655651,1655664,1656176,1657525,1657972,1657978,1658482,1659212,1659217,1659314,1659509,1662668,1665318,1665854,1665894,1667090,1667101,1667538,1669743,1669746,1669749,1669945,1670139,1670953,1673170,1673197,1673202,1673204,1673445,1673454,1673685,1673689,1673875,1674165,1674341,1674400,1674404,1674631,1674669,1674673,1675396,1676667,1677431,1678149,1678151,1678718,1678725,1679169,1679907,1679920-1679924,1679926,1680347,1680460,1680464,1680476,1680819,1681949,1681966,1681974,1681994,1682008,1682076,1682086,1682093,1682259,1682265,1682739,1682864,1683311,1683330,1683378,1683544,1683553,1684047,1686232,1686542,1686546,1686554,1686557,1687061,1687064,1687070-1687071,1687074,1687078-1687079,1688270,1688425,1692650,1693886,1694489,1694848,1696171,1696185,1696627-1696628,1696630,1696758,1697372,1697381,1697387,1697393,1697403,1697405,1701017,1701053,1702600,1702922,1703069,1703142,1703237,1703240,17052 66,1705638,1705643,1705646,1705724,1705730,1705739,1706612,1706615,1706617,1706619,1706675-1706676,1706679,1706979-1706980,1707308,1707971-1707973,1707986,1707988-1707989,1708004,1709388,1709799,1710017,1710359,1710368,1710370,1711507,1711582,1711672,1712927,1715793,1715947,1716047,1716067,1716784,1716973-1716974,1717332,1717334,1717864,1719269,1719336,1719413,1719730,1720015,1721285,1723715,1723720,1723834,1723839,1725179-1725180,1726004,1726099,1726116,1726897,1726995,1727006-1727007,1727028,1727040,1727707,1727822,1730491,1735916,1736357,1736359,1737355-1737356,1740721-1740722,1741096,1741200,1741206,1741214,1741224,1742540,1745055,1745107,1745852,1746006,1746012,1746026,1756258-1756266,1756364,1756377,1759117,1759122-1759126,1759135,1759404-1759405,1759686,1764340,1764481,1764676,1766352,1780810,1781655,1781694,1785053,1785737-1785738,1785741,1785754,1785904,1786445-1786446,1786515 -/subversion/trunk/subversion/libsvn_fs_x:1414756-1509914,1813660-1847674 +/subversion/trunk/subversion/libsvn_fs_x:1414756-1509914,1813660-1862712 Modified: subversion/branches/swig-py3/subversion/libsvn_fs_x/fs.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_fs_x/fs.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_fs_x/fs.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_fs_x/fs.c Mon Jul 8 15:19:03 2019 @@ -310,7 +310,8 @@ static fs_vtable_t fs_vtable = { x_info, svn_fs_x__verify_root, x_freeze, - x_set_errcall + x_set_errcall, + NULL /* ioctl */ }; @@ -641,7 +642,8 @@ static fs_library_vtable_t library_vtabl x_logfiles, NULL /* parse_id */, x_set_svn_fs_open, - x_info_dup + x_info_dup, + NULL /* ioctl */ }; svn_error_t * Modified: subversion/branches/swig-py3/subversion/libsvn_ra_svn/client.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_ra_svn/client.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_ra_svn/client.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_ra_svn/client.c Mon Jul 8 15:19:03 2019 @@ -3105,6 +3105,7 @@ ra_svn_get_deleted_rev(svn_ra_session_t { svn_ra_svn__session_baton_t *sess_baton = session->priv; svn_ra_svn_conn_t *conn = sess_baton->conn; + svn_error_t *err; path = reparent_path(session, path, pool); @@ -3116,8 +3117,20 @@ ra_svn_get_deleted_rev(svn_ra_session_t SVN_ERR(handle_unsupported_cmd(handle_auth_request(sess_baton, pool), N_("'get-deleted-rev' not implemented"))); - return svn_error_trace(svn_ra_svn__read_cmd_response(conn, pool, "r", - revision_deleted)); + err = svn_error_trace(svn_ra_svn__read_cmd_response(conn, pool, "r", + revision_deleted)); + /* The protocol does not allow for a reply of SVN_INVALID_REVNUM directly. + Instead, a new enough server returns SVN_ERR_ENTRY_MISSING_REVISION to + indicate the answer to the query is SVN_INVALID_REVNUM. (An older server + closes the connection and returns SVN_ERR_RA_SVN_CONNECTION_CLOSED.) */ + if (err && err->apr_err == SVN_ERR_ENTRY_MISSING_REVISION) + { + *revision_deleted = SVN_INVALID_REVNUM; + svn_error_clear(err); + } + else + SVN_ERR(err); + return SVN_NO_ERROR; } static svn_error_t * Modified: subversion/branches/swig-py3/subversion/libsvn_repos/authz.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_repos/authz.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_repos/authz.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_repos/authz.c Mon Jul 8 15:19:03 2019 @@ -1548,6 +1548,8 @@ authz_read(authz_full_t **authz_p, const char *groups_path, svn_boolean_t must_exist, svn_repos_t *repos_hint, + svn_repos_authz_warning_func_t warning_func, + void *warning_baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { @@ -1587,7 +1589,8 @@ authz_read(authz_full_t **authz_p, /* Parse the configuration(s) and construct the full authz model * from it. */ err = svn_authz__parse(authz_p, rules_stream, groups_stream, - item_pool, scratch_pool); + warning_func, warning_baton, + item_pool, scratch_pool); if (err != SVN_NO_ERROR) { /* That pool would otherwise never get destroyed. */ @@ -1611,11 +1614,11 @@ authz_read(authz_full_t **authz_p, { /* Parse the configuration(s) and construct the full authz model from * it. */ - err = svn_error_quick_wrapf(svn_authz__parse(authz_p, rules_stream, - groups_stream, - result_pool, scratch_pool), - "Error while parsing authz file: '%s':", - path); + err = svn_error_quick_wrapf( + svn_authz__parse(authz_p, rules_stream, groups_stream, + warning_func, warning_baton, + result_pool, scratch_pool), + "Error while parsing authz file: '%s':", path); } svn_repos__destroy_config_access(config_access); @@ -1628,11 +1631,13 @@ authz_read(authz_full_t **authz_p, /*** Public functions. ***/ svn_error_t * -svn_repos_authz_read3(svn_authz_t **authz_p, +svn_repos_authz_read4(svn_authz_t **authz_p, const char *path, const char *groups_path, svn_boolean_t must_exist, svn_repos_t *repos_hint, + svn_repos_authz_warning_func_t warning_func, + void *warning_baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { @@ -1640,7 +1645,8 @@ svn_repos_authz_read3(svn_authz_t **auth authz->pool = result_pool; SVN_ERR(authz_read(&authz->full, &authz->authz_id, path, groups_path, - must_exist, repos_hint, result_pool, scratch_pool)); + must_exist, repos_hint, warning_func, warning_baton, + result_pool, scratch_pool)); *authz_p = authz; return SVN_NO_ERROR; @@ -1648,18 +1654,21 @@ svn_repos_authz_read3(svn_authz_t **auth svn_error_t * -svn_repos_authz_parse(svn_authz_t **authz_p, svn_stream_t *stream, - svn_stream_t *groups_stream, apr_pool_t *pool) +svn_repos_authz_parse2(svn_authz_t **authz_p, + svn_stream_t *stream, + svn_stream_t *groups_stream, + svn_repos_authz_warning_func_t warning_func, + void *warning_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { - apr_pool_t *scratch_pool = svn_pool_create(pool); - svn_authz_t *authz = apr_pcalloc(pool, sizeof(*authz)); - authz->pool = pool; + svn_authz_t *authz = apr_pcalloc(result_pool, sizeof(*authz)); + authz->pool = result_pool; /* Parse the configuration and construct the full authz model from it. */ - SVN_ERR(svn_authz__parse(&authz->full, stream, groups_stream, pool, - scratch_pool)); - - svn_pool_destroy(scratch_pool); + SVN_ERR(svn_authz__parse(&authz->full, stream, groups_stream, + warning_func, warning_baton, + result_pool, scratch_pool)); *authz_p = authz; return SVN_NO_ERROR; Modified: subversion/branches/swig-py3/subversion/libsvn_repos/authz.h URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_repos/authz.h?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_repos/authz.h (original) +++ subversion/branches/swig-py3/subversion/libsvn_repos/authz.h Mon Jul 8 15:19:03 2019 @@ -312,6 +312,8 @@ svn_error_t * svn_authz__parse(authz_full_t **authz, svn_stream_t *rules, svn_stream_t *groups, + svn_repos_authz_warning_func_t warning_func, + void *warning_baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool); Modified: subversion/branches/swig-py3/subversion/libsvn_repos/authz_parse.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_repos/authz_parse.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_repos/authz_parse.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_repos/authz_parse.c Mon Jul 8 15:19:03 2019 @@ -127,6 +127,10 @@ typedef struct ctor_baton_t svn_membuf_t rule_path_buffer; svn_stringbuf_t *rule_string_buffer; + /* The warning callback and its baton. */ + svn_repos_authz_warning_func_t warning_func; + void *warning_baton; + /* The parser's scratch pool. This may not be the same pool as passed to the constructor callbacks, that is supposed to be an iteration pool maintained by the generic parser. @@ -203,7 +207,9 @@ insert_default_acl(ctor_baton_t *cb) /* Initialize a constuctor baton. */ static ctor_baton_t * -create_ctor_baton(apr_pool_t *result_pool, +create_ctor_baton(svn_repos_authz_warning_func_t warning_func, + void *warning_baton, + apr_pool_t *result_pool, apr_pool_t *scratch_pool) { apr_pool_t *const parser_pool = svn_pool_create(scratch_pool); @@ -234,6 +240,9 @@ create_ctor_baton(apr_pool_t *result_poo svn_membuf__create(&cb->rule_path_buffer, 0, parser_pool); cb->rule_string_buffer = svn_stringbuf_create_empty(parser_pool); + cb->warning_func = warning_func; + cb->warning_baton = warning_baton; + cb->parser_pool = parser_pool; insert_default_acl(cb); @@ -242,6 +251,25 @@ create_ctor_baton(apr_pool_t *result_poo } +/* Emit a warning. Clears ERROR */ +static void +emit_parser_warning(const ctor_baton_t *cb, + svn_error_t *error, + apr_pool_t *scratch_pool) +{ + if (cb->warning_func) + cb->warning_func(cb->warning_baton, error, scratch_pool); + svn_error_clear(error); +} + +/* Avoid creating an error struct if there is no warning function. */ +#define SVN_AUTHZ_PARSE_WARN(cb, err, pool) \ + do { \ + if ((cb) && (cb)->warning_func) \ + emit_parser_warning((cb), (err), (pool)); \ + } while(0) + + /* Create and store per-user global rights. The USER string must be interned or statically initialized. */ static void @@ -1011,7 +1039,8 @@ close_section(void *baton, svn_stringbuf /* Add a user to GROUP. - GROUP is never internalized, but USER always is. */ + GROUP is never internalized, but USER always is. + Adding a NULL user will create an empty group, if it doesn't exist. */ static void add_to_group(ctor_baton_t *cb, const char *group, const char *user) { @@ -1022,7 +1051,8 @@ add_to_group(ctor_baton_t *cb, const cha members = svn_hash__make(cb->authz->pool); svn_hash_sets(cb->expanded_groups, group, members); } - svn_hash_sets(members, user, interned_empty_string); + if (user) + svn_hash_sets(members, user, interned_empty_string); } @@ -1038,8 +1068,15 @@ expand_group_callback(void *baton, ctor_baton_t *const cb = baton; const char *const group = key; apr_array_header_t *members = value; - int i; + + if (0 == members->nelts) + { + /* Create the group with no members. */ + add_to_group(cb, group, NULL); + return SVN_NO_ERROR; + } + for (i = 0; i < members->nelts; ++i) { const char *member = APR_ARRAY_IDX(members, i, const char*); @@ -1169,10 +1206,24 @@ array_insert_ace(void *baton, SVN_ERR_ASSERT(ace->members == NULL); ace->members = svn_hash_gets(iab->cb->expanded_groups, ace->name); if (!ace->members) - return svn_error_createf( - SVN_ERR_AUTHZ_INVALID_CONFIG, NULL, - _("Access entry refers to undefined group '%s'"), - ace->name); + { + return svn_error_createf( + SVN_ERR_AUTHZ_INVALID_CONFIG, NULL, + _("Access entry refers to undefined group '%s'"), + ace->name); + } + else if (0 == apr_hash_count(ace->members)) + { + /* An ACE for an empty group has no effect, so ignore it. */ + SVN_AUTHZ_PARSE_WARN( + iab->cb, + svn_error_createf( + SVN_ERR_AUTHZ_INVALID_CONFIG, NULL, + _("Ignoring access entry for empty group '%s'"), + ace->name), + scratch_pool); + return SVN_NO_ERROR; + } } APR_ARRAY_PUSH(iab->ace_array, authz_ace_t) = *ace; @@ -1318,10 +1369,13 @@ svn_error_t * svn_authz__parse(authz_full_t **authz, svn_stream_t *rules, svn_stream_t *groups, + svn_repos_authz_warning_func_t warning_func, + void *warning_baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - ctor_baton_t *const cb = create_ctor_baton(result_pool, scratch_pool); + ctor_baton_t *const cb = create_ctor_baton(warning_func, warning_baton, + result_pool, scratch_pool); /* * Pass 1: Parse the authz file.
