/* Implements svn_ra_reporter3_t->finish_report. */ static svn_error_t * reporter_finish_report(void *report_baton, apr_pool_t *pool) { report_baton_t *rb = report_baton; svn_ra_session_t *ras; apr_hash_t *locks; const char *repos_root; apr_pool_t *subpool = svn_pool_create(pool); svn_error_t *err = SVN_NO_ERROR; /* Open an RA session to our common ancestor and grab the locks under it. */ SVN_ERR(svn_client__open_ra_session_internal(&ras, rb->ancestor, NULL, NULL, NULL, FALSE, TRUE, rb->ctx, subpool)); /* The locks need to live throughout the edit. Note that if the server doesn't support lock discovery, we'll just not do locky stuff. */ err = svn_ra_get_locks(ras, &locks, "", rb->pool); if (err && ((err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED) || (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE))) { svn_error_clear(err); err = SVN_NO_ERROR; locks = apr_hash_make(rb->pool); } SVN_ERR(err); SVN_ERR(svn_ra_get_repos_root2(ras, &repos_root, rb->pool)); /* Close the RA session. */ svn_pool_destroy(subpool); SVN_ERR(svn_wc_status_set_repos_locks(rb->set_locks_baton, locks, repos_root, rb->pool)); return rb->wrapped_reporter->finish_report(rb->wrapped_report_baton, pool); }
svn_error_t * svn_client_info2(const char *path_or_url, const svn_opt_revision_t *peg_revision, const svn_opt_revision_t *revision, svn_info_receiver_t receiver, void *receiver_baton, svn_depth_t depth, const apr_array_header_t *changelists, 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_info_t *info; svn_error_t *err; 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. */ apr_hash_t *changelist_hash = NULL; if (changelists && changelists->nelts) SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelists, pool)); return crawl_entries(path_or_url, receiver, receiver_baton, depth, changelist_hash, ctx, 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, path_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_path_split(url, &parent_url, &base_name, pool); base_name = svn_path_uri_decode(base_name, 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, parent_url, NULL, 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 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 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_locks(ra_session, &locks, "", 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 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; }
int main (int argc, const char **argv) { apr_pool_t *pool; svn_error_t *err; apr_hash_t *locks; apr_hash_index_t *hi; const char *URL; svn_ra_session_t *session; svn_ra_callbacks_t *cbtable; apr_hash_t *cfg_hash; svn_auth_baton_t *auth_baton; if (argc <= 1) { printf ("Usage: %s URL\n", argv[0]); printf (" Print all locks at or below URL.\n"); return EXIT_FAILURE; } URL = argv[1]; /* Initialize the app. Send all error messages to 'stderr'. */ if (svn_cmdline_init ("ra_test", stderr) != EXIT_SUCCESS) return EXIT_FAILURE; /* Create top-level memory pool. Be sure to read the HACKING file to understand how to properly use/free subpools. */ pool = svn_pool_create (NULL); /* Initialize the FS library. */ err = svn_fs_initialize (pool); if (err) goto hit_error; /* Make sure the ~/.subversion run-time config files exist, and load. */ err = svn_config_ensure (NULL, pool); if (err) goto hit_error; err = svn_config_get_config (&cfg_hash, NULL, pool); if (err) goto hit_error; /* Build an authentication baton. */ { /* There are many different kinds of authentication back-end "providers". See svn_auth.h for a full overview. */ svn_auth_provider_object_t *provider; apr_array_header_t *providers = apr_array_make (pool, 4, sizeof (svn_auth_provider_object_t *)); svn_client_get_simple_prompt_provider (&provider, my_simple_prompt_callback, NULL, /* baton */ 2, /* retry limit */ pool); APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider; svn_client_get_username_prompt_provider (&provider, my_username_prompt_callback, NULL, /* baton */ 2, /* retry limit */ pool); APR_ARRAY_PUSH (providers, svn_auth_provider_object_t *) = provider; /* Register the auth-providers into the context's auth_baton. */ svn_auth_open (&auth_baton, providers, pool); } /* Create a table of callbacks for the RA session, mostly nonexistent. */ cbtable = apr_pcalloc (pool, sizeof(*cbtable)); cbtable->auth_baton = auth_baton; cbtable->open_tmp_file = open_tmp_file; /* Now do the real work. */ err = svn_ra_open (&session, URL, cbtable, NULL, cfg_hash, pool); if (err) goto hit_error; err = svn_ra_get_locks (session, &locks, "", pool); if (err) goto hit_error; err = svn_cmdline_printf (pool, "\n"); if (err) goto hit_error; for (hi = apr_hash_first (pool, locks); hi; hi = apr_hash_next (hi)) { const void *key; void *val; const char *path, *cr_date, *exp_date; svn_lock_t *lock; apr_hash_this (hi, &key, NULL, &val); path = key; lock = val; cr_date = svn_time_to_human_cstring (lock->creation_date, pool); if (lock->expiration_date) exp_date = svn_time_to_human_cstring (lock->expiration_date, pool); else exp_date = "never"; err = svn_cmdline_printf (pool, "%s\n", path); if (err) goto hit_error; err = svn_cmdline_printf (pool, " UUID Token: %s\n", lock->token); if (err) goto hit_error; err = svn_cmdline_printf (pool, " Owner: %s\n", lock->owner); if (err) goto hit_error; err = svn_cmdline_printf (pool, " Comment: %s\n", lock->comment ? lock->comment : "none"); if (err) goto hit_error; err = svn_cmdline_printf (pool, " Created: %s\n", cr_date); if (err) goto hit_error; err = svn_cmdline_printf (pool, " Expires: %s\n\n", exp_date); if (err) goto hit_error; } return EXIT_SUCCESS; hit_error: svn_handle_error2 (err, stderr, FALSE, "getlocks_test: "); return EXIT_FAILURE; }