/* Create a repository with a filesystem based on OPTS in a subdir NAME, * commit the standard Greek tree as revision 1, and set *REPOS_URL to * the URL we will use to access it. * * ### This always returns a file: URL. We should upgrade this to use the * test suite's specified URL scheme instead. */ static svn_error_t * create_greek_repos(const char **repos_url, const char *name, const svn_test_opts_t *opts, apr_pool_t *pool) { svn_repos_t *repos; svn_revnum_t committed_rev; svn_fs_txn_t *txn; svn_fs_root_t *txn_root; /* Create a filesytem and repository. */ SVN_ERR(svn_test__create_repos(&repos, name, opts, pool)); /* Prepare and commit a txn containing the Greek tree. */ SVN_ERR(svn_fs_begin_txn2(&txn, svn_repos_fs(repos), 0 /* rev */, 0 /* flags */, pool)); SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool)); SVN_ERR(svn_test__create_greek_tree(txn_root, pool)); SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &committed_rev, txn, pool)); SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(committed_rev)); SVN_ERR(svn_uri_get_file_url_from_dirent(repos_url, name, pool)); return SVN_NO_ERROR; }
svn_error_t * svn_repos_get_fs_build_parser4(const svn_repos_parse_fns3_t **callbacks, void **parse_baton, svn_repos_t *repos, svn_revnum_t start_rev, svn_revnum_t end_rev, svn_boolean_t use_history, svn_boolean_t validate_props, enum svn_repos_load_uuid uuid_action, const char *parent_dir, svn_repos_notify_func_t notify_func, void *notify_baton, apr_pool_t *pool) { svn_repos_parse_fns3_t *parser = apr_pcalloc(pool, sizeof(*parser)); struct parse_baton *pb = apr_pcalloc(pool, sizeof(*pb)); if (parent_dir) parent_dir = svn_relpath_canonicalize(parent_dir, pool); SVN_ERR_ASSERT((SVN_IS_VALID_REVNUM(start_rev) && SVN_IS_VALID_REVNUM(end_rev)) || ((! SVN_IS_VALID_REVNUM(start_rev)) && (! SVN_IS_VALID_REVNUM(end_rev)))); if (SVN_IS_VALID_REVNUM(start_rev)) SVN_ERR_ASSERT(start_rev <= end_rev); parser->magic_header_record = magic_header_record; parser->uuid_record = uuid_record; parser->new_revision_record = new_revision_record; parser->new_node_record = new_node_record; parser->set_revision_property = set_revision_property; parser->set_node_property = set_node_property; parser->remove_node_props = remove_node_props; parser->set_fulltext = set_fulltext; parser->close_node = close_node; parser->close_revision = close_revision; parser->delete_node_property = delete_node_property; parser->apply_textdelta = apply_textdelta; pb->repos = repos; pb->fs = svn_repos_fs(repos); pb->use_history = use_history; pb->validate_props = validate_props; pb->notify_func = notify_func; pb->notify_baton = notify_baton; pb->uuid_action = uuid_action; pb->parent_dir = parent_dir; pb->pool = pool; pb->notify_pool = svn_pool_create(pool); pb->rev_map = apr_hash_make(pool); pb->oldest_old_rev = SVN_INVALID_REVNUM; pb->last_rev_mapped = SVN_INVALID_REVNUM; pb->start_rev = start_rev; pb->end_rev = end_rev; *callbacks = parser; *parse_baton = pb; return SVN_NO_ERROR; }
Repository(char const* path) { svn_repos_t *repos; check_svn(svn_repos_open(&repos, path, apr_pool)); fs = svn_repos_fs(repos); svn_revnum_t revnum; check_svn(svn_fs_youngest_rev(&revnum, fs, apr_pool)); check_svn(svn_fs_revision_root(&fs_root, fs, revnum, apr_pool)); }
/* Helper to open a repository and set a warning func (so we don't * SEGFAULT when libsvn_fs's default handler gets run). */ static svn_error_t * open_repos (svn_repos_t **repos, const char *path, apr_pool_t *pool) { SVN_ERR (svn_repos_open (repos, path, pool)); svn_fs_set_warning_func (svn_repos_fs (*repos), warning_func, NULL); return SVN_NO_ERROR; }
void SVNRepos::deltify(File &path, Revision &revStart, Revision &revEnd) { SVN::Pool requestPool; svn_repos_t *repos; svn_fs_t *fs; svn_revnum_t start = SVN_INVALID_REVNUM, end = SVN_INVALID_REVNUM; svn_revnum_t youngest, revision; SVN::Pool revisionPool; if (path.isNull()) { JNIUtil::throwNullPointerException("path"); return; } SVN_JNI_ERR(svn_repos_open3(&repos, path.getInternalStyle(requestPool), NULL, requestPool.getPool(), requestPool.getPool()), ); fs = svn_repos_fs(repos); SVN_JNI_ERR(svn_fs_youngest_rev(&youngest, fs, requestPool.getPool()), ); if (revStart.revision()->kind == svn_opt_revision_number) /* ### We only handle revision numbers right now, not dates. */ start = revStart.revision()->value.number; else if (revStart.revision()->kind == svn_opt_revision_head) start = youngest; else start = SVN_INVALID_REVNUM; if (revEnd.revision()->kind == svn_opt_revision_number) end = revEnd.revision()->value.number; else if (revEnd.revision()->kind == svn_opt_revision_head) end = youngest; else end = SVN_INVALID_REVNUM; /* Fill in implied revisions if necessary. */ if (start == SVN_INVALID_REVNUM) start = youngest; if (end == SVN_INVALID_REVNUM) end = start; if (start > end) { SVN_JNI_ERR(svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("First revision cannot be higher than second")), ); }
/* The core logic. This function iterates the repository REPOS_PATH * and sends all the (DATA and/or PROP) reps in each revision for counting * by process_one_revision(). QUIET is passed to process_one_revision(). */ static svn_error_t *process(const char *repos_path, svn_boolean_t prop, svn_boolean_t data, svn_boolean_t quiet, apr_pool_t *scratch_pool) { apr_hash_t *prop_reps = NULL; apr_hash_t *data_reps = NULL; apr_hash_t *both_reps = NULL; svn_revnum_t rev, youngest; apr_pool_t *iterpool; svn_repos_t *repos; svn_fs_t *fs; if (prop) prop_reps = apr_hash_make(scratch_pool); if (data) data_reps = apr_hash_make(scratch_pool); if (prop && data) both_reps = apr_hash_make(scratch_pool); /* Open the FS. */ SVN_ERR(svn_repos_open2(&repos, repos_path, NULL, scratch_pool)); fs = svn_repos_fs(repos); SVN_ERR(is_fs_fsfs(fs, scratch_pool)); SVN_ERR(svn_fs_youngest_rev(&youngest, fs, scratch_pool)); /* Iterate the revisions. */ iterpool = svn_pool_create(scratch_pool); for (rev = 0; rev <= youngest; rev++) { svn_pool_clear(iterpool); SVN_ERR(cancel_func(NULL)); SVN_ERR(process_one_revision(fs, rev, quiet, prop_reps, data_reps, both_reps, scratch_pool, iterpool)); } svn_pool_destroy(iterpool); /* Print stats. */ SVN_ERR(pretty_print("prop", prop_reps, scratch_pool)); SVN_ERR(pretty_print("data", data_reps, scratch_pool)); SVN_ERR(pretty_print("both", both_reps, scratch_pool)); return SVN_NO_ERROR; }
/* Change revision property NAME to VALUE for REVISION in REPOS. If VALIDATE_PROPS is set, use functions which perform validation of the property value. Otherwise, bypass those checks. */ static svn_error_t * change_rev_prop(svn_repos_t *repos, svn_revnum_t revision, const char *name, const svn_string_t *value, svn_boolean_t validate_props, apr_pool_t *pool) { if (validate_props) return svn_repos_fs_change_rev_prop4(repos, revision, NULL, name, NULL, value, FALSE, FALSE, NULL, NULL, pool); else return svn_fs_change_rev_prop2(svn_repos_fs(repos), revision, name, NULL, value, pool); }
/* This implements `svn_opt_subcommand_t'. */ static svn_error_t * subcommand_index (apr_getopt_t *os, void *baton, apr_pool_t *pool) { struct svnindex_opt_state *opt_state = baton; svn_repos_t *repos; svn_fs_t *fs; svn_stream_t *stderr_stream = NULL; struct recode_write_baton stderr_stream_rwb = { 0 }; svn_revnum_t lower = SVN_INVALID_REVNUM, upper = SVN_INVALID_REVNUM; svn_revnum_t youngest; SVN_ERR (open_repos (&repos, opt_state->repository_path, pool)); fs = svn_repos_fs (repos); SVN_ERR (svn_fs_youngest_rev (&youngest, fs, pool)); /* Find the revision numbers at which to start and end. */ SVN_ERR (get_revnum (&lower, &opt_state->start_revision, youngest, repos, pool)); SVN_ERR (get_revnum (&upper, &opt_state->end_revision, youngest, repos, pool)); if (lower > upper) return svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("First revision cannot be higher than second")); /* Progress feedback goes to stderr, unless they asked to suppress it. */ if (! opt_state->quiet) { stderr_stream = svn_stream_create (&stderr_stream_rwb, pool); stderr_stream_rwb.pool = pool; stderr_stream_rwb.out = stderr; svn_stream_set_write (stderr_stream, recode_write); } SVN_ERR (svnindex__index (repos, stderr_stream, lower, upper, opt_state->verbose, opt_state->db, check_cancel, NULL, pool)); return SVN_NO_ERROR; }
static svn_error_t * svn_ra_local__replay(svn_ra_session_t *session, svn_revnum_t revision, svn_revnum_t low_water_mark, svn_boolean_t send_deltas, const svn_delta_editor_t *editor, void *edit_baton, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; svn_fs_root_t *root; SVN_ERR(svn_fs_revision_root(&root, svn_repos_fs(sess->repos), revision, pool)); return svn_repos_replay2(root, sess->fs_path->data, low_water_mark, send_deltas, editor, edit_baton, NULL, NULL, pool); }
static svn_error_t * svn_ra_local__open(svn_ra_session_t *session, const char *repos_URL, const svn_ra_callbacks2_t *callbacks, void *callback_baton, apr_hash_t *config, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess; const char *fs_path; /* Allocate and stash the session_sess args we have already. */ sess = apr_pcalloc(pool, sizeof(*sess)); sess->callbacks = callbacks; sess->callback_baton = callback_baton; /* Look through the URL, figure out which part points to the repository, and which part is the path *within* the repository. */ SVN_ERR_W(svn_ra_local__split_URL(&(sess->repos), &(sess->repos_url), &fs_path, repos_URL, session->pool), _("Unable to open an ra_local session to URL")); sess->fs_path = svn_stringbuf_create(fs_path, session->pool); /* Cache the filesystem object from the repos here for convenience. */ sess->fs = svn_repos_fs(sess->repos); /* Ignore FS warnings. */ svn_fs_set_warning_func(sess->fs, ignore_warnings, NULL); /* Cache the repository UUID as well */ SVN_ERR(svn_fs_get_uuid(sess->fs, &sess->uuid, session->pool)); /* Be sure username is NULL so we know to look it up / ask for it */ sess->username = NULL; session->priv = sess; return SVN_NO_ERROR; }
void SVNAdmin::deltify(const char *path, Revision &revStart, Revision &revEnd) { Pool requestPool; SVN_JNI_NULL_PTR_EX(path, "path", ); path = svn_path_internal_style(path, requestPool.pool()); svn_repos_t *repos; svn_fs_t *fs; svn_revnum_t start = SVN_INVALID_REVNUM, end = SVN_INVALID_REVNUM; svn_revnum_t youngest, revision; Pool revisionPool; SVN_JNI_ERR(svn_repos_open(&repos, path, requestPool.pool()), ); fs = svn_repos_fs (repos); SVN_JNI_ERR(svn_fs_youngest_rev(&youngest, fs, requestPool.pool()), ); if (revStart.revision()->kind == svn_opt_revision_number) /* ### We only handle revision numbers right now, not dates. */ start = revStart.revision()->value.number; else if (revStart.revision()->kind == svn_opt_revision_head) start = youngest; else start = SVN_INVALID_REVNUM; if (revEnd.revision()->kind == svn_opt_revision_number) end = revEnd.revision()->value.number; else if (revEnd.revision()->kind == svn_opt_revision_head) end = youngest; else end = SVN_INVALID_REVNUM; /* Fill in implied revisions if necessary. */ if (start == SVN_INVALID_REVNUM) start = youngest; if (end == SVN_INVALID_REVNUM) end = start; if (start > end) { SVN_JNI_ERR(svn_error_create (SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("First revision cannot be higher than second")), ); }
/* Build the node-origins index for the repository located at REPOS_PATH. */ static svn_error_t * build_index(const char *repos_path, apr_pool_t *pool) { svn_repos_t *repos; svn_fs_t *fs; svn_revnum_t youngest_rev, i; size_t slotsize; const char *progress_fmt; apr_pool_t *subpool; /* Open the repository. */ SVN_ERR(svn_repos_open3(&repos, repos_path, NULL, pool, pool)); /* Get a filesystem object. */ fs = svn_repos_fs(repos); /* Fetch the youngest revision of the repository. */ SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool)); slotsize = strlen(apr_ltoa(pool, youngest_rev)); progress_fmt = apr_psprintf (pool, "[%%%" APR_SIZE_T_FMT "ld" "/%%%" APR_SIZE_T_FMT "ld] " "Found %%d new lines of history." "\n", slotsize, slotsize); /* Now, iterate over all the revisions, calling index_revision_adds(). */ subpool = svn_pool_create(pool); for (i = 0; i < youngest_rev; i++) { int count; svn_pool_clear(subpool); SVN_ERR(index_revision_adds(&count, fs, i + 1, subpool)); printf(progress_fmt, i + 1, youngest_rev, count); } svn_pool_destroy(subpool); return SVN_NO_ERROR; }
static PyObject *repos_fs(PyObject *self) { RepositoryObject *reposobj = (RepositoryObject *)self; FileSystemObject *ret; svn_fs_t *fs; fs = svn_repos_fs(reposobj->repos); if (fs == NULL) { PyErr_SetString(PyExc_RuntimeError, "Unable to obtain fs handle"); return NULL; } ret = PyObject_New(FileSystemObject, &FileSystem_Type); if (ret == NULL) return NULL; ret->fs = fs; ret->repos = reposobj; Py_INCREF(reposobj); return (PyObject *)ret; }
/* Loads the authz config into *AUTHZ from the file at AUTHZ_FILE in repository at REPOS_PATH from the transaction TXN_NAME. If GROUPS_FILE is set, the resulting *AUTHZ will be constructed from AUTHZ_FILE with global groups taken from GROUPS_FILE. Using POOL for allocations. */ static svn_error_t * get_authz_from_txn(svn_authz_t **authz, const char *repos_path, const char *authz_file, const char *groups_file, const char *txn_name, apr_pool_t *pool) { svn_repos_t *repos; svn_fs_t *fs; svn_fs_txn_t *txn; svn_fs_root_t *root; svn_stream_t *authz_contents; svn_stream_t *groups_contents; svn_error_t *err; /* Open up the repository and find the transaction root */ SVN_ERR(svn_repos_open3(&repos, repos_path, NULL, pool, pool)); fs = svn_repos_fs(repos); SVN_ERR(svn_fs_open_txn(&txn, fs, txn_name, pool)); SVN_ERR(svn_fs_txn_root(&root, txn, pool)); /* Get the authz file contents. */ SVN_ERR(read_file_contents(&authz_contents, authz_file, root, pool)); /* Get the groups file contents if needed. */ if (groups_file) SVN_ERR(read_file_contents(&groups_contents, groups_file, root, pool)); else groups_contents = NULL; err = svn_repos_authz_parse(authz, authz_contents, groups_contents, pool); /* Add the filename to the error stack since the parser doesn't have it. */ if (err != SVN_NO_ERROR) return svn_error_createf(err->apr_err, err, "Error parsing authz file: '%s':", authz_file); return SVN_NO_ERROR; }
/* The main dumper. */ svn_error_t * svn_repos_dump_fs3(svn_repos_t *repos, svn_stream_t *stream, svn_revnum_t start_rev, svn_revnum_t end_rev, svn_boolean_t incremental, svn_boolean_t use_deltas, svn_repos_notify_func_t notify_func, void *notify_baton, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) { const svn_delta_editor_t *dump_editor; void *dump_edit_baton = NULL; svn_revnum_t i; svn_fs_t *fs = svn_repos_fs(repos); apr_pool_t *subpool = svn_pool_create(pool); svn_revnum_t youngest; const char *uuid; int version; svn_boolean_t found_old_reference = FALSE; svn_boolean_t found_old_mergeinfo = FALSE; svn_repos_notify_t *notify; /* Determine the current youngest revision of the filesystem. */ SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool)); /* Use default vals if necessary. */ if (! SVN_IS_VALID_REVNUM(start_rev)) start_rev = 0; if (! SVN_IS_VALID_REVNUM(end_rev)) end_rev = youngest; if (! stream) stream = svn_stream_empty(pool); /* Validate the revisions. */ if (start_rev > end_rev) return svn_error_createf(SVN_ERR_REPOS_BAD_ARGS, NULL, _("Start revision %ld" " is greater than end revision %ld"), start_rev, end_rev); if (end_rev > youngest) return svn_error_createf(SVN_ERR_REPOS_BAD_ARGS, NULL, _("End revision %ld is invalid " "(youngest revision is %ld)"), end_rev, youngest); if ((start_rev == 0) && incremental) incremental = FALSE; /* revision 0 looks the same regardless of whether or not this is an incremental dump, so just simplify things. */ /* Write out the UUID. */ SVN_ERR(svn_fs_get_uuid(fs, &uuid, pool)); /* If we're not using deltas, use the previous version, for compatibility with svn 1.0.x. */ version = SVN_REPOS_DUMPFILE_FORMAT_VERSION; if (!use_deltas) version--; /* Write out "general" metadata for the dumpfile. In this case, a magic header followed by a dumpfile format version. */ SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n\n", version)); SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_UUID ": %s\n\n", uuid)); /* Create a notify object that we can reuse in the loop. */ if (notify_func) notify = svn_repos_notify_create(svn_repos_notify_dump_rev_end, pool); /* Main loop: we're going to dump revision i. */ for (i = start_rev; i <= end_rev; i++) { svn_revnum_t from_rev, to_rev; svn_fs_root_t *to_root; svn_boolean_t use_deltas_for_rev; svn_pool_clear(subpool); /* Check for cancellation. */ if (cancel_func) SVN_ERR(cancel_func(cancel_baton)); /* Special-case the initial revision dump: it needs to contain *all* nodes, because it's the foundation of all future revisions in the dumpfile. */ if ((i == start_rev) && (! incremental)) { /* Special-special-case a dump of revision 0. */ if (i == 0) { /* Just write out the one revision 0 record and move on. The parser might want to use its properties. */ SVN_ERR(write_revision_record(stream, fs, 0, subpool)); to_rev = 0; goto loop_end; } /* Compare START_REV to revision 0, so that everything appears to be added. */ from_rev = 0; to_rev = i; } else { /* In the normal case, we want to compare consecutive revs. */ from_rev = i - 1; to_rev = i; } /* Write the revision record. */ SVN_ERR(write_revision_record(stream, fs, to_rev, subpool)); /* Fetch the editor which dumps nodes to a file. Regardless of what we've been told, don't use deltas for the first rev of a non-incremental dump. */ use_deltas_for_rev = use_deltas && (incremental || i != start_rev); SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton, fs, to_rev, "", stream, notify_func, notify_baton, start_rev, use_deltas_for_rev, FALSE, subpool)); /* Drive the editor in one way or another. */ SVN_ERR(svn_fs_revision_root(&to_root, fs, to_rev, subpool)); /* If this is the first revision of a non-incremental dump, we're in for a full tree dump. Otherwise, we want to simply replay the revision. */ if ((i == start_rev) && (! incremental)) { svn_fs_root_t *from_root; SVN_ERR(svn_fs_revision_root(&from_root, fs, from_rev, subpool)); SVN_ERR(svn_repos_dir_delta2(from_root, "", "", to_root, "", dump_editor, dump_edit_baton, NULL, NULL, FALSE, /* don't send text-deltas */ svn_depth_infinity, FALSE, /* don't send entry props */ FALSE, /* don't ignore ancestry */ subpool)); } else { SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE, dump_editor, dump_edit_baton, NULL, NULL, subpool)); } loop_end: if (notify_func) { notify->revision = to_rev; notify_func(notify_baton, notify, subpool); } if (dump_edit_baton) /* We never get an edit baton for r0. */ { if (((struct edit_baton *)dump_edit_baton)->found_old_reference) found_old_reference = TRUE; if (((struct edit_baton *)dump_edit_baton)->found_old_mergeinfo) found_old_mergeinfo = TRUE; } } if (notify_func) { /* Did we issue any warnings about references to revisions older than the oldest dumped revision? If so, then issue a final generic warning, since the inline warnings already issued might easily be missed. */ notify = svn_repos_notify_create(svn_repos_notify_dump_end, subpool); notify_func(notify_baton, notify, subpool); if (found_old_reference) { notify = svn_repos_notify_create(svn_repos_notify_warning, subpool); notify->warning = svn_repos_notify_warning_found_old_reference; notify->warning_str = _("The range of revisions dumped " "contained references to " "copy sources outside that " "range."); notify_func(notify_baton, notify, subpool); } /* Ditto if we issued any warnings about old revisions referenced in dumped mergeinfo. */ if (found_old_mergeinfo) { notify = svn_repos_notify_create(svn_repos_notify_warning, subpool); notify->warning = svn_repos_notify_warning_found_old_mergeinfo; notify->warning_str = _("The range of revisions dumped " "contained mergeinfo " "which reference revisions outside " "that range."); notify_func(notify_baton, notify, subpool); } } svn_pool_destroy(subpool); return SVN_NO_ERROR; }
svn_error_t * svn_repos_verify_fs2(svn_repos_t *repos, svn_revnum_t start_rev, svn_revnum_t end_rev, svn_repos_notify_func_t notify_func, void *notify_baton, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) { svn_fs_t *fs = svn_repos_fs(repos); svn_revnum_t youngest; svn_revnum_t rev; apr_pool_t *iterpool = svn_pool_create(pool); svn_repos_notify_t *notify; /* Determine the current youngest revision of the filesystem. */ SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool)); /* Use default vals if necessary. */ if (! SVN_IS_VALID_REVNUM(start_rev)) start_rev = 0; if (! SVN_IS_VALID_REVNUM(end_rev)) end_rev = youngest; /* Validate the revisions. */ if (start_rev > end_rev) return svn_error_createf(SVN_ERR_REPOS_BAD_ARGS, NULL, _("Start revision %ld" " is greater than end revision %ld"), start_rev, end_rev); if (end_rev > youngest) return svn_error_createf(SVN_ERR_REPOS_BAD_ARGS, NULL, _("End revision %ld is invalid " "(youngest revision is %ld)"), end_rev, youngest); /* Create a notify object that we can reuse within the loop. */ if (notify_func) notify = svn_repos_notify_create(svn_repos_notify_verify_rev_end, pool); for (rev = start_rev; rev <= end_rev; rev++) { svn_delta_editor_t *dump_editor; void *dump_edit_baton; const svn_delta_editor_t *cancel_editor; void *cancel_edit_baton; svn_fs_root_t *to_root; apr_hash_t *props; svn_pool_clear(iterpool); /* Get cancellable dump editor, but with our close_directory handler. */ SVN_ERR(get_dump_editor((const svn_delta_editor_t **)&dump_editor, &dump_edit_baton, fs, rev, "", svn_stream_empty(pool), notify_func, notify_baton, start_rev, FALSE, TRUE, /* use_deltas, verify */ iterpool)); dump_editor->close_directory = verify_close_directory; SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton, dump_editor, dump_edit_baton, &cancel_editor, &cancel_edit_baton, iterpool)); SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, iterpool)); SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE, cancel_editor, cancel_edit_baton, NULL, NULL, iterpool)); SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, iterpool)); if (notify_func) { notify->revision = rev; notify_func(notify_baton, notify, iterpool); } } /* We're done. */ if (notify_func) { notify = svn_repos_notify_create(svn_repos_notify_verify_end, iterpool); notify_func(notify_baton, notify, iterpool); } svn_pool_destroy(iterpool); return SVN_NO_ERROR; }
svn_error_t * svn_repos_get_commit_editor5(const svn_delta_editor_t **editor, void **edit_baton, svn_repos_t *repos, svn_fs_txn_t *txn, const char *repos_url, const char *base_path, apr_hash_t *revprop_table, svn_commit_callback2_t callback, void *callback_baton, svn_repos_authz_callback_t authz_callback, void *authz_baton, apr_pool_t *pool) { svn_delta_editor_t *e; apr_pool_t *subpool = svn_pool_create(pool); struct edit_baton *eb; /* Do a global authz access lookup. Users with no write access whatsoever to the repository don't get a commit editor. */ if (authz_callback) { svn_boolean_t allowed; SVN_ERR(authz_callback(svn_authz_write, &allowed, NULL, NULL, authz_baton, pool)); if (!allowed) return svn_error_create(SVN_ERR_AUTHZ_UNWRITABLE, NULL, "Not authorized to open a commit editor."); } /* Allocate the structures. */ e = svn_delta_default_editor(pool); eb = apr_pcalloc(subpool, sizeof(*eb)); /* Set up the editor. */ e->open_root = open_root; e->delete_entry = delete_entry; e->add_directory = add_directory; e->open_directory = open_directory; e->change_dir_prop = change_dir_prop; e->add_file = add_file; e->open_file = open_file; e->close_file = close_file; e->apply_textdelta = apply_textdelta; e->change_file_prop = change_file_prop; e->close_edit = close_edit; e->abort_edit = abort_edit; /* Set up the edit baton. */ eb->pool = subpool; eb->revprop_table = svn_prop_hash_dup(revprop_table, subpool); eb->commit_callback = callback; eb->commit_callback_baton = callback_baton; eb->authz_callback = authz_callback; eb->authz_baton = authz_baton; eb->base_path = svn_fspath__canonicalize(base_path, subpool); eb->repos = repos; eb->repos_url = repos_url; eb->repos_name = svn_dirent_basename(svn_repos_path(repos, subpool), subpool); eb->fs = svn_repos_fs(repos); eb->txn = txn; eb->txn_owner = txn == NULL; *edit_baton = eb; *editor = e; return SVN_NO_ERROR; }
static svn_error_t * close_edit(void *edit_baton, apr_pool_t *pool) { struct edit_baton *eb = edit_baton; svn_revnum_t new_revision = SVN_INVALID_REVNUM; svn_error_t *err; const char *conflict; const char *post_commit_err = NULL; /* If no transaction has been created (ie. if open_root wasn't called before close_edit), abort the operation here with an error. */ if (! eb->txn) return svn_error_create(SVN_ERR_REPOS_BAD_ARGS, NULL, "No valid transaction supplied to close_edit"); /* Commit. */ err = svn_repos_fs_commit_txn(&conflict, eb->repos, &new_revision, eb->txn, pool); if (SVN_IS_VALID_REVNUM(new_revision)) { if (err) { /* If the error was in post-commit, then the commit itself succeeded. In which case, save the post-commit warning (to be reported back to the client, who will probably display it as a warning) and clear the error. */ post_commit_err = svn_repos__post_commit_error_str(err, pool); svn_error_clear(err); err = SVN_NO_ERROR; } } else { /* ### todo: we should check whether it really was a conflict, and return the conflict info if so? */ /* If the commit failed, it's *probably* due to a conflict -- that is, the txn being out-of-date. The filesystem gives us the ability to continue diddling the transaction and try again; but let's face it: that's not how the cvs or svn works from a user interface standpoint. Thus we don't make use of this fs feature (for now, at least.) So, in a nutshell: svn commits are an all-or-nothing deal. Each commit creates a new fs txn which either succeeds or is aborted completely. No second chances; the user simply needs to update and commit again :) */ eb->txn_aborted = TRUE; return svn_error_trace( svn_error_compose_create(err, svn_fs_abort_txn(eb->txn, pool))); } /* Pass new revision information to the caller's callback. */ { svn_string_t *date, *author; svn_commit_info_t *commit_info; /* Even if there was a post-commit hook failure, it's more serious if one of the calls here fails, so we explicitly check for errors here, while saving the possible post-commit error for later. */ err = svn_fs_revision_prop(&date, svn_repos_fs(eb->repos), new_revision, SVN_PROP_REVISION_DATE, pool); if (! err) { err = svn_fs_revision_prop(&author, svn_repos_fs(eb->repos), new_revision, SVN_PROP_REVISION_AUTHOR, pool); } if ((! err) && eb->commit_callback) { commit_info = svn_create_commit_info(pool); /* fill up the svn_commit_info structure */ commit_info->revision = new_revision; commit_info->date = date ? date->data : NULL; commit_info->author = author ? author->data : NULL; commit_info->post_commit_err = post_commit_err; err = (*eb->commit_callback)(commit_info, eb->commit_callback_baton, pool); } } return svn_error_trace(err); }
/* Retrieve the file at DIRENT (contained in a repo) then parse it as a config * file placing the result into CFG_P allocated in POOL. * * If DIRENT cannot be parsed as a config file then an error is returned. The * contents of CFG_P is then undefined. If MUST_EXIST is TRUE, a missing * authz file is also an error. The CASE_SENSITIVE controls the lookup * behavior for section and option names alike. * * SCRATCH_POOL will be used for temporary allocations. */ static svn_error_t * authz_retrieve_config_repo(svn_config_t **cfg_p, const char *dirent, svn_boolean_t must_exist, svn_boolean_t case_sensitive, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_error_t *err; svn_repos_t *repos; const char *repos_root_dirent; const char *fs_path; svn_fs_t *fs; svn_fs_root_t *root; svn_revnum_t youngest_rev; svn_node_kind_t node_kind; svn_stream_t *contents; /* Search for a repository in the full path. */ repos_root_dirent = svn_repos_find_root_path(dirent, scratch_pool); if (!repos_root_dirent) return svn_error_createf(SVN_ERR_RA_LOCAL_REPOS_NOT_FOUND, NULL, "Unable to find repository at '%s'", dirent); /* Attempt to open a repository at repos_root_dirent. */ SVN_ERR(svn_repos_open3(&repos, repos_root_dirent, NULL, scratch_pool, scratch_pool)); fs_path = &dirent[strlen(repos_root_dirent)]; /* Root path is always a directory so no reason to go any further */ if (*fs_path == '\0') return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, "'/' is not a file in repo '%s'", repos_root_dirent); /* We skip some things that are non-important for how we're going to use * this repo connection. We do not set any capabilities since none of * the current ones are important for what we're doing. We also do not * setup the environment that repos hooks would run under since we won't * be triggering any. */ /* Get the filesystem. */ fs = svn_repos_fs(repos); /* Find HEAD and the revision root */ SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, scratch_pool)); SVN_ERR(svn_fs_revision_root(&root, fs, youngest_rev, scratch_pool)); SVN_ERR(svn_fs_check_path(&node_kind, root, fs_path, scratch_pool)); if (node_kind == svn_node_none) { if (!must_exist) { SVN_ERR(svn_config_create2(cfg_p, case_sensitive, case_sensitive, result_pool)); return SVN_NO_ERROR; } else { return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, "'%s' path not found in repo '%s'", fs_path, repos_root_dirent); } } else if (node_kind != svn_node_file) { return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, "'%s' is not a file in repo '%s'", fs_path, repos_root_dirent); } SVN_ERR(svn_fs_file_contents(&contents, root, fs_path, scratch_pool)); err = svn_config_parse(cfg_p, contents, case_sensitive, case_sensitive, result_pool); /* Add the URL to the error stack since the parser doesn't have it. */ if (err != SVN_NO_ERROR) return svn_error_createf(err->apr_err, err, "Error while parsing config file: '%s' in repo '%s':", fs_path, repos_root_dirent); return SVN_NO_ERROR; }