/* svn_wc_upgrade_get_repos_info_t implementation for calling svn_wc_upgrade() from svn_client_upgrade() */ static svn_error_t * fetch_repos_info(const char **repos_root, const char **repos_uuid, void *baton, const char *url, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { struct repos_info_baton *ri = baton; apr_pool_t *subpool; svn_ra_session_t *ra_session; /* The same info is likely to retrieved multiple times (e.g. externals) */ if (ri->last_repos && svn_uri__is_child(ri->last_repos, url, scratch_pool)) { *repos_root = apr_pstrdup(result_pool, ri->last_repos); *repos_uuid = apr_pstrdup(result_pool, ri->last_uuid); return SVN_NO_ERROR; } subpool = svn_pool_create(scratch_pool); SVN_ERR(svn_client_open_ra_session(&ra_session, url, ri->ctx, subpool)); SVN_ERR(svn_ra_get_repos_root2(ra_session, repos_root, result_pool)); SVN_ERR(svn_ra_get_uuid2(ra_session, repos_uuid, result_pool)); /* Store data for further calls */ ri->last_repos = apr_pstrdup(ri->state_pool, *repos_root); ri->last_uuid = apr_pstrdup(ri->state_pool, *repos_uuid); svn_pool_destroy(subpool); return SVN_NO_ERROR; }
svn_error_t * svn_client_get_repos_root(const char **repos_root, const char **repos_uuid, const char *abspath_or_url, svn_client_ctx_t *ctx, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_ra_session_t *ra_session; /* If PATH_OR_URL is a local path we can fetch the repos root locally. */ if (!svn_path_is_url(abspath_or_url)) { SVN_ERR(svn_wc__node_get_repos_info(repos_root, repos_uuid, ctx->wc_ctx, abspath_or_url, result_pool, scratch_pool)); return SVN_NO_ERROR; } /* If PATH_OR_URL was a URL, we use the RA layer to look it up. */ SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, abspath_or_url, NULL, NULL, FALSE, TRUE, ctx, scratch_pool)); if (repos_root) SVN_ERR(svn_ra_get_repos_root2(ra_session, repos_root, result_pool)); if (repos_uuid) SVN_ERR(svn_ra_get_uuid2(ra_session, repos_uuid, result_pool)); return SVN_NO_ERROR; }
svn_error_t * svn_client__pathrev_create_with_session(svn_client__pathrev_t **pathrev_p, svn_ra_session_t *ra_session, svn_revnum_t rev, const char *url, apr_pool_t *result_pool) { svn_client__pathrev_t *pathrev = apr_palloc(result_pool, sizeof(*pathrev)); SVN_ERR_ASSERT(svn_path_is_url(url)); SVN_ERR(svn_ra_get_repos_root2(ra_session, &pathrev->repos_root_url, result_pool)); SVN_ERR(svn_ra_get_uuid2(ra_session, &pathrev->repos_uuid, result_pool)); pathrev->rev = rev; pathrev->url = apr_pstrdup(result_pool, url); *pathrev_p = pathrev; return SVN_NO_ERROR; }
/* Replay revisions START_REVISION thru END_REVISION (inclusive) of * the repository located at URL, using callbacks which generate * Subversion repository dumpstreams describing the changes made in * those revisions. If QUIET is set, don't generate progress * messages. */ static svn_error_t * replay_revisions(svn_ra_session_t *session, svn_ra_session_t *extra_ra_session, const char *url, svn_revnum_t start_revision, svn_revnum_t end_revision, svn_boolean_t quiet, svn_boolean_t incremental, apr_pool_t *pool) { struct replay_baton *replay_baton; const char *uuid; svn_stream_t *stdout_stream; SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool)); replay_baton = apr_pcalloc(pool, sizeof(*replay_baton)); replay_baton->stdout_stream = stdout_stream; replay_baton->extra_ra_session = extra_ra_session; replay_baton->quiet = quiet; /* Write the magic header and UUID */ SVN_ERR(svn_stream_printf(stdout_stream, pool, SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n\n", SVN_REPOS_DUMPFILE_FORMAT_VERSION)); SVN_ERR(svn_ra_get_uuid2(session, &uuid, pool)); SVN_ERR(svn_stream_printf(stdout_stream, pool, SVN_REPOS_DUMPFILE_UUID ": %s\n\n", uuid)); /* Fake revision 0 if necessary */ if (start_revision == 0) { SVN_ERR(dump_revision_header(session, stdout_stream, start_revision, pool)); /* Revision 0 has no tree changes, so we're done. */ if (! quiet) SVN_ERR(svn_cmdline_fprintf(stderr, pool, "* Dumped revision %lu.\n", start_revision)); start_revision++; /* If our first revision is 0, we can treat this as an incremental dump. */ incremental = TRUE; } if (incremental) { SVN_ERR(svn_ra_replay_range(session, start_revision, end_revision, 0, TRUE, replay_revstart, replay_revend, replay_baton, pool)); } else { const svn_ra_reporter3_t *reporter; void *report_baton; const svn_delta_editor_t *dump_editor; void *dump_baton; /* First, we need to dump the start_revision in full. We'll start with a revision record header. */ SVN_ERR(dump_revision_header(session, stdout_stream, start_revision, pool)); /* Then, we'll drive the dump editor with what would look like a full checkout of the repository as it looked in START_REVISION. We do this by manufacturing a basic 'report' to the update reporter, telling it that we have nothing to start with. The delta between nothing and everything-at-REV is, effectively, a full dump of REV. */ SVN_ERR(svn_rdump__get_dump_editor(&dump_editor, &dump_baton, start_revision, stdout_stream, extra_ra_session, check_cancel, NULL, pool)); SVN_ERR(svn_ra_do_update2(session, &reporter, &report_baton, start_revision, "", svn_depth_infinity, FALSE, dump_editor, dump_baton, pool)); SVN_ERR(reporter->set_path(report_baton, "", start_revision, svn_depth_infinity, TRUE, NULL, pool)); SVN_ERR(reporter->finish_report(report_baton, pool)); /* All finished with START_REVISION! */ if (! quiet) SVN_ERR(svn_cmdline_fprintf(stderr, pool, "* Dumped revision %lu.\n", start_revision)); start_revision++; /* Now go pick up additional revisions in the range, if any. */ if (start_revision <= end_revision) SVN_ERR(svn_ra_replay_range(session, start_revision, end_revision, 0, TRUE, replay_revstart, replay_revend, replay_baton, pool)); } SVN_ERR(svn_stream_close(stdout_stream)); return SVN_NO_ERROR; }
svn_error_t * svn_client_info3(const char *abspath_or_url, const svn_opt_revision_t *peg_revision, const svn_opt_revision_t *revision, svn_depth_t depth, svn_boolean_t fetch_excluded, svn_boolean_t fetch_actual_only, const apr_array_header_t *changelists, svn_client_info_receiver2_t receiver, void *receiver_baton, svn_client_ctx_t *ctx, apr_pool_t *pool) { svn_ra_session_t *ra_session, *parent_ra_session; svn_revnum_t rev; const char *url; svn_node_kind_t url_kind; const char *repos_root_URL, *repos_UUID; svn_lock_t *lock; svn_boolean_t related; apr_hash_t *parent_ents; const char *parent_url, *base_name; svn_dirent_t *the_ent; svn_client_info2_t *info; svn_error_t *err; if (depth == svn_depth_unknown) depth = svn_depth_empty; if ((revision == NULL || revision->kind == svn_opt_revision_unspecified) && (peg_revision == NULL || peg_revision->kind == svn_opt_revision_unspecified)) { /* Do all digging in the working copy. */ wc_info_receiver_baton_t b = { receiver, receiver_baton }; return svn_error_trace( svn_wc__get_info(ctx->wc_ctx, abspath_or_url, depth, fetch_excluded, fetch_actual_only, changelists, wc_info_receiver, &b, ctx->cancel_func, ctx->cancel_baton, pool)); } /* Go repository digging instead. */ /* Trace rename history (starting at path_or_url@peg_revision) and return RA session to the possibly-renamed URL as it exists in REVISION. The ra_session returned will be anchored on this "final" URL. */ SVN_ERR(svn_client__ra_session_from_path(&ra_session, &rev, &url, abspath_or_url, NULL, peg_revision, revision, ctx, pool)); SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_URL, pool)); SVN_ERR(svn_ra_get_uuid2(ra_session, &repos_UUID, pool)); svn_uri_split(&parent_url, &base_name, url, pool); /* Get the dirent for the URL itself. */ err = svn_ra_stat(ra_session, "", rev, &the_ent, pool); /* svn_ra_stat() will work against old versions of mod_dav_svn, but not old versions of svnserve. In the case of a pre-1.2 svnserve, catch the specific error it throws:*/ if (err && err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED) { /* Fall back to pre-1.2 strategy for fetching dirent's URL. */ svn_error_clear(err); if (strcmp(url, repos_root_URL) == 0) { /* In this universe, there's simply no way to fetch information about the repository's root directory! If we're recursing, degrade gracefully: rather than throw an error, return no information about the repos root. */ if (depth > svn_depth_empty) goto pre_1_2_recurse; /* Otherwise, we really are stuck. Better tell the user what's going on. */ return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, _("Server does not support retrieving " "information about the repository root")); } SVN_ERR(svn_ra_check_path(ra_session, "", rev, &url_kind, pool)); if (url_kind == svn_node_none) return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, _("URL '%s' non-existent in revision %ld"), url, rev); /* Open a new RA session to the item's parent. */ SVN_ERR(svn_client__open_ra_session_internal(&parent_ra_session, NULL, parent_url, NULL, NULL, FALSE, TRUE, ctx, pool)); /* Get all parent's entries, and find the item's dirent in the hash. */ SVN_ERR(svn_ra_get_dir2(parent_ra_session, &parent_ents, NULL, NULL, "", rev, DIRENT_FIELDS, pool)); the_ent = apr_hash_get(parent_ents, base_name, APR_HASH_KEY_STRING); if (the_ent == NULL) return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, _("URL '%s' non-existent in revision %ld"), url, rev); } else if (err) { return svn_error_trace(err); } if (! the_ent) return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, _("URL '%s' non-existent in revision %ld"), url, rev); /* Check if the URL exists in HEAD and refers to the same resource. In this case, we check the repository for a lock on this URL. ### There is a possible race here, since HEAD might have changed since ### we checked it. A solution to this problem could be to do the below ### check in a loop which only terminates if the HEAD revision is the same ### before and after this check. That could, however, lead to a ### starvation situation instead. */ SVN_ERR(same_resource_in_head(&related, url, rev, ra_session, ctx, pool)); if (related) { err = svn_ra_get_lock(ra_session, &lock, "", pool); /* An old mod_dav_svn will always work; there's nothing wrong with doing a PROPFIND for a property named "DAV:supportedlock". But an old svnserve will error. */ if (err && err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED) { svn_error_clear(err); lock = NULL; } else if (err) return svn_error_trace(err); } else lock = NULL; /* Push the URL's dirent (and lock) at the callback.*/ SVN_ERR(build_info_from_dirent(&info, the_ent, lock, url, rev, repos_UUID, repos_root_URL, pool)); SVN_ERR(receiver(receiver_baton, base_name, info, pool)); /* Possibly recurse, using the original RA session. */ if (depth > svn_depth_empty && (the_ent->kind == svn_node_dir)) { apr_hash_t *locks; pre_1_2_recurse: if (peg_revision->kind == svn_opt_revision_head) { err = svn_ra_get_locks2(ra_session, &locks, "", depth, pool); /* Catch specific errors thrown by old mod_dav_svn or svnserve. */ if (err && (err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED || err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)) { svn_error_clear(err); locks = apr_hash_make(pool); /* use an empty hash */ } else if (err) return svn_error_trace(err); } else locks = apr_hash_make(pool); /* use an empty hash */ SVN_ERR(push_dir_info(ra_session, url, "", rev, repos_UUID, repos_root_URL, receiver, receiver_baton, depth, ctx, locks, pool)); } return SVN_NO_ERROR; }