You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by fu...@apache.org on 2019/07/08 15:19:05 UTC
svn commit: r1862754 [6/9] - in /subversion/branches/swig-py3: ./
build/ac-macros/ build/generator/ doc/ doc/programmer/ notes/
notes/shelving/ subversion/bindings/cxx/ subversion/bindings/cxxhl/
subversion/bindings/javahl/native/ subversion/bindings/j...
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.