static svn_error_t * reporter_link_path(void *reporter_baton, const char *path, const char *url, svn_revnum_t revision, svn_depth_t depth, svn_boolean_t start_empty, const char *lock_token, apr_pool_t *pool) { reporter_baton_t *rbaton = reporter_baton; const char *fs_path = NULL; const char *repos_url_decoded; int repos_url_len; url = svn_path_uri_decode(url, pool); repos_url_decoded = svn_path_uri_decode(rbaton->sess->repos_url, pool); repos_url_len = strlen(repos_url_decoded); if (strncmp(url, repos_url_decoded, repos_url_len) != 0) return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, _("'%s'\n" "is not the same repository as\n" "'%s'"), url, rbaton->sess->repos_url); fs_path = url + repos_url_len; return svn_repos_link_path3(rbaton->report_baton, path, fs_path, revision, depth, start_empty, lock_token, pool); }
static svn_error_t * svn_ra_local__reparent(svn_ra_session_t *session, const char *url, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; const char *relpath = ""; /* If the new URL isn't the same as our repository root URL, then let's ensure that it's some child of it. */ if (strcmp(url, sess->repos_url) != 0) relpath = svn_path_is_child(sess->repos_url, url, pool); if (! relpath) return svn_error_createf (SVN_ERR_RA_ILLEGAL_URL, NULL, _("URL '%s' is not a child of the session's repository root " "URL '%s'"), url, sess->repos_url); /* Update our FS_PATH sess member to point to our new relative-URL-turned-absolute-filesystem-path. */ relpath = apr_pstrcat(pool, "/", svn_path_uri_decode(relpath, pool), NULL); svn_stringbuf_set(sess->fs_path, relpath); return SVN_NO_ERROR; }
/* This implements the 'svn_ra_get_wc_prop_func_t' interface. */ static svn_error_t * get_wc_prop(void *baton, const char *relpath, const char *name, const svn_string_t **value, apr_pool_t *pool) { svn_client__callback_baton_t *cb = baton; *value = NULL; /* If we have a list of commit_items, search through that for a match for this relative URL. */ if (cb->commit_items) { int i; for (i = 0; i < cb->commit_items->nelts; i++) { svn_client_commit_item3_t *item = APR_ARRAY_IDX(cb->commit_items, i, svn_client_commit_item3_t *); if (! strcmp(relpath, svn_path_uri_decode(item->url, pool))) return svn_wc_prop_get(value, name, item->path, cb->base_access, pool); } return SVN_NO_ERROR; }
std::string Url::unescape(const char * url) { Pool pool; return svn_path_uri_decode(url, pool); }
/* Return the portion of URL that is relative to ANCHOR. */ static const char * subtract_anchor(const char *anchor, const char *url, apr_pool_t *pool) { if (! strcmp(url, anchor)) return ""; else return svn_path_uri_decode(svn_path_is_child(anchor, url, pool), pool); }
QString svn::InfoEntry::prettyUrl(const char*_url)const { if (_url) { Pool pool; _url = svn_path_uri_decode(_url,pool); return QString::fromUtf8(_url); } return QString::fromUtf8(""); }
static svn_error_t * change_dir_prop(void *dir_baton, const char *name, const svn_string_t *value, apr_pool_t *pool) { node_baton_t *db = dir_baton; edit_baton_t *eb = db->edit_baton; /* Only regular properties can pass over libsvn_ra */ if (svn_property_kind2(name) != svn_prop_regular_kind) return SVN_NO_ERROR; /* Maybe drop svn:mergeinfo. */ if (eb->strip_mergeinfo && (strcmp(name, SVN_PROP_MERGEINFO) == 0)) { eb->mergeinfo_stripped = TRUE; return SVN_NO_ERROR; } /* Maybe convert svnmerge-integrated data into svn:mergeinfo. (We ignore svnmerge-blocked for now.) */ /* ### FIXME: Consult the mirror repository's HEAD prop values and ### merge svn:mergeinfo, svnmerge-integrated, and svnmerge-blocked. */ if (eb->migrate_svnmerge && (strcmp(name, "svnmerge-integrated") == 0)) { if (value) { /* svnmerge-integrated differs from svn:mergeinfo in a pair of ways. First, it can use tabs, newlines, or spaces to delimit source information. Secondly, the source paths are relative URLs, whereas svn:mergeinfo uses relative paths (not URI-encoded). */ svn_error_t *err; svn_stringbuf_t *mergeinfo_buf = svn_stringbuf_create_empty(pool); svn_mergeinfo_t mergeinfo; int i; apr_array_header_t *sources = svn_cstring_split(value->data, " \t\n", TRUE, pool); svn_string_t *new_value; for (i = 0; i < sources->nelts; i++) { const char *rel_path; apr_array_header_t *path_revs = svn_cstring_split(APR_ARRAY_IDX(sources, i, const char *), ":", TRUE, pool); /* ### TODO: Warn? */ if (path_revs->nelts != 2) continue; /* Append this source's mergeinfo data. */ rel_path = APR_ARRAY_IDX(path_revs, 0, const char *); rel_path = svn_path_uri_decode(rel_path, pool); svn_stringbuf_appendcstr(mergeinfo_buf, rel_path); svn_stringbuf_appendcstr(mergeinfo_buf, ":"); svn_stringbuf_appendcstr(mergeinfo_buf, APR_ARRAY_IDX(path_revs, 1, const char *)); svn_stringbuf_appendcstr(mergeinfo_buf, "\n"); } /* Try to parse the mergeinfo string we've created, just to check for bogosity. If all goes well, we'll unparse it again and use that as our property value. */ err = svn_mergeinfo_parse(&mergeinfo, mergeinfo_buf->data, pool); if (err) { svn_error_clear(err); return SVN_NO_ERROR; } SVN_ERR(svn_mergeinfo_to_string(&new_value, mergeinfo, pool)); value = new_value; } name = SVN_PROP_MERGEINFO; eb->svnmerge_migrated = TRUE; } /* Remember if we see any svnmerge-blocked properties. */ if (eb->migrate_svnmerge && (strcmp(name, "svnmerge-blocked") == 0)) { eb->svnmerge_blocked = TRUE; } /* Normalize svn:* properties as necessary. */ if (svn_prop_needs_translation(name)) { svn_boolean_t was_normalized; svn_boolean_t mergeinfo_tweaked = FALSE; /* Normalize encoding to UTF-8, and EOL style to LF. */ SVN_ERR(normalize_string(&value, &was_normalized, eb->source_prop_encoding, pool, pool)); /* Maybe adjust svn:mergeinfo. */ if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0) { SVN_ERR(remove_r0_mergeinfo(&value, &mergeinfo_tweaked, pool, pool)); if (mergeinfo_tweaked) eb->mergeinfo_tweaked = TRUE; } if (was_normalized) (*(eb->normalized_node_props_counter))++; } return eb->wrapped_editor->change_dir_prop(db->wrapped_node_baton, name, value, 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; }
/* Helper func for recursively fetching svn_dirent_t's from a remote directory and pushing them at an info-receiver callback. DEPTH is the depth starting at DIR, even though RECEIVER is never invoked on DIR: if DEPTH is svn_depth_immediates, then invoke RECEIVER on all children of DIR, but none of their children; if svn_depth_files, then invoke RECEIVER on file children of DIR but not on subdirectories; if svn_depth_infinity, recurse fully. */ static svn_error_t * push_dir_info(svn_ra_session_t *ra_session, const char *session_URL, const char *dir, svn_revnum_t rev, const char *repos_UUID, const char *repos_root, svn_info_receiver_t receiver, void *receiver_baton, svn_depth_t depth, svn_client_ctx_t *ctx, apr_hash_t *locks, apr_pool_t *pool) { apr_hash_t *tmpdirents; svn_dirent_t *the_ent; svn_info_t *info; apr_hash_index_t *hi; apr_pool_t *subpool = svn_pool_create(pool); SVN_ERR(svn_ra_get_dir2(ra_session, &tmpdirents, NULL, NULL, dir, rev, DIRENT_FIELDS, pool)); for (hi = apr_hash_first(pool, tmpdirents); hi; hi = apr_hash_next(hi)) { const char *path, *URL, *fs_path; const void *key; svn_lock_t *lock; void *val; svn_pool_clear(subpool); if (ctx->cancel_func) SVN_ERR(ctx->cancel_func(ctx->cancel_baton)); apr_hash_this(hi, &key, NULL, &val); the_ent = val; path = svn_path_join(dir, key, subpool); URL = svn_path_url_add_component(session_URL, key, subpool); fs_path = svn_path_is_child(repos_root, URL, subpool); fs_path = apr_pstrcat(subpool, "/", fs_path, NULL); fs_path = svn_path_uri_decode(fs_path, subpool); lock = apr_hash_get(locks, fs_path, APR_HASH_KEY_STRING); SVN_ERR(build_info_from_dirent(&info, the_ent, lock, URL, rev, repos_UUID, repos_root, subpool)); if (depth >= svn_depth_immediates || (depth == svn_depth_files && the_ent->kind == svn_node_file)) { SVN_ERR(receiver(receiver_baton, path, info, subpool)); } if (depth == svn_depth_infinity && the_ent->kind == svn_node_dir) { SVN_ERR(push_dir_info(ra_session, URL, path, rev, repos_UUID, repos_root, receiver, receiver_baton, depth, ctx, locks, subpool)); } } svn_pool_destroy(subpool); return SVN_NO_ERROR; }
static svn_error_t * svn_ra_local__get_commit_editor(svn_ra_session_t *session, const svn_delta_editor_t **editor, void **edit_baton, apr_hash_t *revprop_table, svn_commit_callback2_t callback, void *callback_baton, apr_hash_t *lock_tokens, svn_boolean_t keep_locks, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; struct deltify_etc_baton *db = apr_palloc(pool, sizeof(*db)); apr_hash_index_t *hi; svn_fs_access_t *fs_access; db->fs = sess->fs; db->repos = sess->repos; db->fs_path = sess->fs_path->data; if (! keep_locks) db->lock_tokens = lock_tokens; else db->lock_tokens = NULL; db->pool = pool; db->callback = callback; db->callback_baton = callback_baton; SVN_ERR(get_username(session, pool)); /* If there are lock tokens to add, do so. */ if (lock_tokens) { SVN_ERR(svn_fs_get_access(&fs_access, sess->fs)); /* If there is no access context, the filesystem will scream if a lock is needed. */ if (fs_access) { for (hi = apr_hash_first(pool, lock_tokens); hi; hi = apr_hash_next(hi)) { void *val; const char *path, *token; const void *key; apr_hash_this(hi, &key, NULL, &val); path = svn_path_join(sess->fs_path->data, (const char *)key, pool); token = val; SVN_ERR(svn_fs_access_add_lock_token2(fs_access, path, token)); } } } /* Copy the revprops table so we can add the username. */ revprop_table = apr_hash_copy(pool, revprop_table); apr_hash_set(revprop_table, SVN_PROP_REVISION_AUTHOR, APR_HASH_KEY_STRING, svn_string_create(sess->username, pool)); /* Get the repos commit-editor */ return svn_repos_get_commit_editor5 (editor, edit_baton, sess->repos, NULL, svn_path_uri_decode(sess->repos_url, pool), sess->fs_path->data, revprop_table, deltify_etc, db, NULL, NULL, pool); }
/* This function is the shared guts of add_file() and add_directory(), which see for the meanings of the parameters. The only extra parameter here is IS_DIR, which is TRUE when adding a directory, and FALSE when adding a file. */ static svn_error_t * add_file_or_directory(const char *path, void *parent_baton, const char *copy_path, svn_revnum_t copy_revision, svn_boolean_t is_dir, apr_pool_t *pool, void **return_baton) { struct dir_baton *pb = parent_baton; struct edit_baton *eb = pb->edit_baton; apr_pool_t *subpool = svn_pool_create(pool); svn_boolean_t was_copied = FALSE; const char *full_path; full_path = svn_fspath__join(eb->base_path, svn_relpath_canonicalize(path, pool), pool); /* Sanity check. */ if (copy_path && (! SVN_IS_VALID_REVNUM(copy_revision))) return svn_error_createf (SVN_ERR_FS_GENERAL, NULL, _("Got source path but no source revision for '%s'"), full_path); if (copy_path) { const char *fs_path; svn_fs_root_t *copy_root; svn_node_kind_t kind; size_t repos_url_len; svn_repos_authz_access_t required; /* Copy requires recursive write access to the destination path and write access to the parent path. */ required = svn_authz_write | (is_dir ? svn_authz_recursive : 0); SVN_ERR(check_authz(eb, full_path, eb->txn_root, required, subpool)); SVN_ERR(check_authz(eb, pb->path, eb->txn_root, svn_authz_write, subpool)); /* Check PATH in our transaction. Make sure it does not exist unless its parent directory was copied (in which case, the thing might have been copied in as well), else return an out-of-dateness error. */ SVN_ERR(svn_fs_check_path(&kind, eb->txn_root, full_path, subpool)); if ((kind != svn_node_none) && (! pb->was_copied)) return out_of_date(full_path, kind); /* For now, require that the url come from the same repository that this commit is operating on. */ copy_path = svn_path_uri_decode(copy_path, subpool); repos_url_len = strlen(eb->repos_url); if (strncmp(copy_path, eb->repos_url, repos_url_len) != 0) return svn_error_createf (SVN_ERR_FS_GENERAL, NULL, _("Source url '%s' is from different repository"), copy_path); fs_path = apr_pstrdup(subpool, copy_path + repos_url_len); /* Now use the "fs_path" as an absolute path within the repository to make the copy from. */ SVN_ERR(svn_fs_revision_root(©_root, eb->fs, copy_revision, subpool)); /* Copy also requires (recursive) read access to the source */ required = svn_authz_read | (is_dir ? svn_authz_recursive : 0); SVN_ERR(check_authz(eb, fs_path, copy_root, required, subpool)); SVN_ERR(svn_fs_copy(copy_root, fs_path, eb->txn_root, full_path, subpool)); was_copied = TRUE; } else { /* No ancestry given, just make a new directory or empty file. Note that we don't perform an existence check here like the copy-from case does -- that's because svn_fs_make_*() already errors out if the file already exists. Verify write access to the full path and to the parent. */ SVN_ERR(check_authz(eb, full_path, eb->txn_root, svn_authz_write, subpool)); SVN_ERR(check_authz(eb, pb->path, eb->txn_root, svn_authz_write, subpool)); if (is_dir) SVN_ERR(svn_fs_make_dir(eb->txn_root, full_path, subpool)); else SVN_ERR(svn_fs_make_file(eb->txn_root, full_path, subpool)); } /* Cleanup our temporary subpool. */ svn_pool_destroy(subpool); /* Build a new child baton. */ if (is_dir) { *return_baton = make_dir_baton(eb, pb, full_path, was_copied, SVN_INVALID_REVNUM, pool); } else { struct file_baton *new_fb = apr_pcalloc(pool, sizeof(*new_fb)); new_fb->edit_baton = eb; new_fb->path = full_path; *return_baton = new_fb; } return SVN_NO_ERROR; }
svn_error_t * svn_ra_local__split_URL(svn_repos_t **repos, const char **repos_url, const char **fs_path, const char *URL, apr_pool_t *pool) { svn_error_t *err = SVN_NO_ERROR; const char *repos_root; const char *hostname, *path; svn_stringbuf_t *urlbuf; /* Verify that the URL is well-formed (loosely) */ /* First, check for the "file://" prefix. */ if (strncmp(URL, "file://", 7) != 0) return svn_error_createf (SVN_ERR_RA_ILLEGAL_URL, NULL, _("Local URL '%s' does not contain 'file://' prefix"), URL); /* Then, skip what's between the "file://" prefix and the next occurance of '/' -- this is the hostname, and we are considering everything from that '/' until the end of the URL to be the absolute path portion of the URL. If we got just "file://", treat it the same as "file:///". */ hostname = URL + 7; if (*hostname == '\0') { path = "/"; hostname = NULL; } else { path = strchr(hostname, '/'); if (! path) return svn_error_createf (SVN_ERR_RA_ILLEGAL_URL, NULL, _("Local URL '%s' contains only a hostname, no path"), URL); /* Treat localhost as an empty hostname. */ if (hostname != path) { hostname = svn_path_uri_decode(apr_pstrmemdup(pool, hostname, path - hostname), pool); if (strncmp(hostname, "localhost", 9) == 0) hostname = NULL; } else hostname = NULL; } /* Duplicate the URL, starting at the top of the path. At the same time, we URI-decode the path. */ #if defined(WIN32) || defined(__CYGWIN__) /* On Windows, we'll typically have to skip the leading / if the path starts with a drive letter. Like most Web browsers, We support two variants of this scheme: file:///X:/path and file:///X|/path Note that, at least on WinNT and above, file:////./X:/path will also work, so we must make sure the transformation doesn't break that, and file:///path (that looks within the current drive only) should also keep working. If we got a non-empty hostname other than localhost, we convert this into an UNC path. In this case, we obviously don't strip the slash even if the path looks like it starts with a drive letter. Another thing to remember is that the form file:///\machine/share was the only way to access UNC paths in svn before 1.2. We need to support that for compatibility with old working copies. */ { static const char valid_drive_letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; /* Casting away const! */ char *dup_path = (char *)svn_path_uri_decode(path, pool); if (!hostname && dup_path[1] && strchr(valid_drive_letters, dup_path[1]) && (dup_path[2] == ':' || dup_path[2] == '|') && dup_path[3] == '/') { /* Skip the leading slash. */ ++dup_path; /* We're using path below to calculate fs_path, so keep it in sync. */ ++path; if (dup_path[1] == '|') dup_path[1] = ':'; } if (hostname) /* We still know that the path starts with a slash. */ repos_root = apr_pstrcat(pool, "//", hostname, path, NULL); else repos_root = dup_path; } #else /* Currently, the only hostnames we are allowing on non-Win32 platforms are the empty string and 'localhost'. */ if (hostname) return svn_error_createf (SVN_ERR_RA_ILLEGAL_URL, NULL, _("Local URL '%s' contains unsupported hostname"), URL); repos_root = svn_path_uri_decode(path, pool); #endif /* Search for a repository in the full path. */ repos_root = svn_repos_find_root_path(repos_root, pool); if (!repos_root) return svn_error_createf (SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED, NULL, _("Unable to open repository '%s'"), URL); /* Attempt to open a repository at URL. */ err = svn_repos_open(repos, repos_root, pool); if (err) return svn_error_createf (SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED, err, _("Unable to open repository '%s'"), URL); /* Assert capabilities directly, since client == server. */ { apr_array_header_t *caps = apr_array_make(pool, 1, sizeof(const char *)); APR_ARRAY_PUSH(caps, const char *) = SVN_RA_CAPABILITY_MERGEINFO; SVN_ERR(svn_repos_remember_client_capabilities(*repos, caps)); } /* What remains of URL after being hacked at in the previous step is REPOS_URL. FS_PATH is what we've hacked off in the process. Note that path is not encoded and what we gave to svn_root_find_root_path may have been destroyed by that function. So we have to decode it once more. But then, it is ours... We want the suffix of path after the repos root part. Note that repos_root may contain //hostname, but path doesn't. */ *fs_path = svn_path_uri_decode(path, pool) + (strlen(repos_root) - (hostname ? strlen(hostname) + 2 : 0)); /* Ensure that *FS_PATH has its leading slash. */ if (**fs_path != '/') *fs_path = apr_pstrcat(pool, "/", *fs_path, NULL); /* Remove the path components in *fs_path from the original URL, to get the URL to the repository root. */ urlbuf = svn_stringbuf_create(URL, pool); svn_path_remove_components(urlbuf, svn_path_component_count(*fs_path)); *repos_url = urlbuf->data; return SVN_NO_ERROR; }
svn_error_t * svn_opt_parse_path(svn_opt_revision_t *rev, const char **truepath, const char *path /* UTF-8! */, apr_pool_t *pool) { const char *peg_rev; SVN_ERR(svn_opt__split_arg_at_peg_revision(truepath, &peg_rev, path, pool)); /* Parse the peg revision, if one was found */ if (strlen(peg_rev)) { int ret; svn_opt_revision_t start_revision, end_revision; end_revision.kind = svn_opt_revision_unspecified; if (peg_rev[1] == '\0') /* looking at empty peg revision */ { ret = 0; start_revision.kind = svn_opt_revision_unspecified; } else /* looking at non-empty peg revision */ { const char *rev_str = &peg_rev[1]; /* URLs get treated differently from wc paths. */ if (svn_path_is_url(path)) { /* URLs are URI-encoded, so we look for dates with URI-encoded delimeters. */ int rev_len = strlen(rev_str); if (rev_len > 6 && rev_str[0] == '%' && rev_str[1] == '7' && (rev_str[2] == 'B' || rev_str[2] == 'b') && rev_str[rev_len-3] == '%' && rev_str[rev_len-2] == '7' && (rev_str[rev_len-1] == 'D' || rev_str[rev_len-1] == 'd')) { rev_str = svn_path_uri_decode(rev_str, pool); } } ret = svn_opt_parse_revision(&start_revision, &end_revision, rev_str, pool); } if (ret || end_revision.kind != svn_opt_revision_unspecified) return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("Syntax error parsing revision '%s'"), &peg_rev[1]); rev->kind = start_revision.kind; rev->value = start_revision.value; } else { /* Didn't find a peg revision. */ rev->kind = svn_opt_revision_unspecified; } return SVN_NO_ERROR; }
/* This implements the `svn_opt_subcommand_t' interface. */ svn_error_t * svn_cl__export(apr_getopt_t *os, void *baton, apr_pool_t *pool) { svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state; svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx; const char *from, *to; apr_array_header_t *targets; svn_error_t *err; svn_opt_revision_t peg_revision; const char *truefrom; SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os, opt_state->targets, ctx, pool)); /* We want exactly 1 or 2 targets for this subcommand. */ if (targets->nelts < 1) return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL); if (targets->nelts > 2) return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, 0, NULL); /* The first target is the `from' path. */ from = APR_ARRAY_IDX(targets, 0, const char *); /* Get the peg revision if present. */ SVN_ERR(svn_opt_parse_path(&peg_revision, &truefrom, from, pool)); /* If only one target was given, split off the basename to use as the `to' path. Else, a `to' path was supplied. */ if (targets->nelts == 1) to = svn_path_uri_decode(svn_path_basename(truefrom, pool), pool); else to = APR_ARRAY_IDX(targets, 1, const char *); SVN_ERR(svn_opt__split_arg_at_peg_revision(&to, NULL, to, pool)); if (! opt_state->quiet) svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE, TRUE, FALSE, pool); if (opt_state->depth == svn_depth_unknown) opt_state->depth = svn_depth_infinity; /* Decode the partially encoded URL and escape all URL unsafe characters. */ if (svn_path_is_url(truefrom)) truefrom = svn_path_uri_encode(svn_path_uri_decode(truefrom, pool), pool); /* Do the export. */ err = svn_client_export4(NULL, truefrom, to, &peg_revision, &(opt_state->start_revision), opt_state->force, opt_state->ignore_externals, opt_state->depth, opt_state->native_eol, ctx, pool); if (err && err->apr_err == SVN_ERR_WC_OBSTRUCTED_UPDATE && !opt_state->force) SVN_ERR_W(err, _("Destination directory exists; please remove " "the directory or use --force to overwrite")); return err; }
static svn_error_t * make_reporter(svn_ra_session_t *session, const svn_ra_reporter3_t **reporter, void **report_baton, svn_revnum_t revision, const char *target, const char *other_url, svn_boolean_t text_deltas, svn_depth_t depth, svn_boolean_t send_copyfrom_args, svn_boolean_t ignore_ancestry, const svn_delta_editor_t *editor, void *edit_baton, apr_pool_t *pool) { svn_ra_local__session_baton_t *sess = session->priv; void *rbaton; int repos_url_len; const char *other_fs_path = NULL; const char *repos_url_decoded; /* Get the HEAD revision if one is not supplied. */ if (! SVN_IS_VALID_REVNUM(revision)) SVN_ERR(svn_fs_youngest_rev(&revision, sess->fs, pool)); /* If OTHER_URL was provided, validate it and convert it into a regular filesystem path. */ if (other_url) { other_url = svn_path_uri_decode(other_url, pool); repos_url_decoded = svn_path_uri_decode(sess->repos_url, pool); repos_url_len = strlen(repos_url_decoded); /* Sanity check: the other_url better be in the same repository as the original session url! */ if (strncmp(other_url, repos_url_decoded, repos_url_len) != 0) return svn_error_createf (SVN_ERR_RA_ILLEGAL_URL, NULL, _("'%s'\n" "is not the same repository as\n" "'%s'"), other_url, sess->repos_url); other_fs_path = other_url + repos_url_len; } /* Pass back our reporter */ *reporter = &ra_local_reporter; SVN_ERR(get_username(session, pool)); if (sess->callbacks) SVN_ERR(svn_delta_get_cancellation_editor(sess->callbacks->cancel_func, sess->callback_baton, editor, edit_baton, &editor, &edit_baton, pool)); /* Build a reporter baton. */ SVN_ERR(svn_repos_begin_report2(&rbaton, revision, sess->repos, sess->fs_path->data, target, other_fs_path, text_deltas, depth, ignore_ancestry, send_copyfrom_args, editor, edit_baton, NULL, NULL, pool)); /* Wrap the report baton given us by the repos layer with our own reporter baton. */ *report_baton = make_reporter_baton(sess, rbaton, pool); return SVN_NO_ERROR; }
svn_error_t * svn_opt_parse_path(svn_opt_revision_t *rev, const char **truepath, const char *path /* UTF-8! */, apr_pool_t *pool) { const char *peg_rev; SVN_ERR(svn_opt__split_arg_at_peg_revision(truepath, &peg_rev, path, pool)); /* Parse the peg revision, if one was found */ if (strlen(peg_rev)) { int ret; svn_opt_revision_t start_revision, end_revision; end_revision.kind = svn_opt_revision_unspecified; if (peg_rev[1] == '\0') /* looking at empty peg revision */ { ret = 0; start_revision.kind = svn_opt_revision_unspecified; start_revision.value.number = 0; } else /* looking at non-empty peg revision */ { const char *rev_str = &peg_rev[1]; /* URLs get treated differently from wc paths. */ if (svn_path_is_url(path)) { /* URLs are URI-encoded, so we look for dates with URI-encoded delimeters. */ size_t rev_len = strlen(rev_str); if (rev_len > 6 && rev_str[0] == '%' && rev_str[1] == '7' && (rev_str[2] == 'B' || rev_str[2] == 'b') && rev_str[rev_len-3] == '%' && rev_str[rev_len-2] == '7' && (rev_str[rev_len-1] == 'D' || rev_str[rev_len-1] == 'd')) { rev_str = svn_path_uri_decode(rev_str, pool); } } ret = svn_opt_parse_revision(&start_revision, &end_revision, rev_str, pool); } if (ret || end_revision.kind != svn_opt_revision_unspecified) { /* If an svn+ssh URL was used and it contains only one @, * provide an error message that presents a possible solution * to the parsing error (issue #2349). */ if (strncmp(path, "svn+ssh://", 10) == 0) { const char *at; at = strchr(path, '@'); if (at && strrchr(path, '@') == at) return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("Syntax error parsing peg revision " "'%s'; did you mean '%s@'?"), &peg_rev[1], path); } return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("Syntax error parsing peg revision '%s'"), &peg_rev[1]); } rev->kind = start_revision.kind; rev->value = start_revision.value; } else { /* Didn't find a peg revision. */ rev->kind = svn_opt_revision_unspecified; } return SVN_NO_ERROR; }
svn_error_t *svn_ra_neon__get_baseline_props(svn_string_t *bc_relative, svn_ra_neon__resource_t **bln_rsrc, svn_ra_neon__session_t *sess, const char *url, svn_revnum_t revision, const ne_propname *which_props, apr_pool_t *pool) { svn_ra_neon__resource_t *rsrc; const char *vcc; const svn_string_t *relative_path; const char *my_bc_relative; const char *lopped_path; /* ### we may be able to replace some/all of this code with an ### expand-property REPORT when that is available on the server. */ /* ------------------------------------------------------------------- STEP 1 Fetch the following properties from the given URL (or, if URL no longer exists in HEAD, get the properties from the nearest still-existing parent resource): *) DAV:version-controlled-configuration so that we can reach the baseline information. *) svn:baseline-relative-path so that we can find this resource within a Baseline Collection. If we need to search up parent directories, then the relative path is this property value *plus* any trailing components we had to chop off. *) DAV:resourcetype so that we can identify whether this resource is a collection or not -- assuming we never had to search up parent directories. */ SVN_ERR(svn_ra_neon__search_for_starting_props(&rsrc, &lopped_path, sess, url, pool)); SVN_ERR(svn_ra_neon__get_vcc(&vcc, sess, url, pool)); if (vcc == NULL) { /* ### better error reporting... */ /* ### need an SVN_ERR here */ return svn_error_create(APR_EGENERAL, NULL, _("The VCC property was not found on the " "resource")); } /* Allocate our own bc_relative path. */ relative_path = apr_hash_get(rsrc->propset, SVN_RA_NEON__PROP_BASELINE_RELPATH, APR_HASH_KEY_STRING); if (relative_path == NULL) { /* ### better error reporting... */ /* ### need an SVN_ERR here */ return svn_error_create(APR_EGENERAL, NULL, _("The relative-path property was not " "found on the resource")); } /* don't forget to tack on the parts we lopped off in order to find the VCC... We are expected to return a URI decoded relative path, so decode the lopped path first. */ my_bc_relative = svn_path_join(relative_path->data, svn_path_uri_decode(lopped_path, pool), pool); /* if they want the relative path (could be, they're just trying to find the baseline collection), then return it */ if (bc_relative) { bc_relative->data = my_bc_relative; bc_relative->len = strlen(my_bc_relative); } /* ------------------------------------------------------------------- STEP 2 We have the Version Controlled Configuration (VCC). From here, we need to reach the Baseline for specified revision. If the revision is SVN_INVALID_REVNUM, then we're talking about the HEAD revision. We have one extra step to reach the Baseline: *) Fetch the DAV:checked-in from the VCC; it points to the Baseline. If we have a specific revision, then we use a Label header when fetching props from the VCC. This will direct us to the Baseline with that label (in this case, the label == the revision number). From the Baseline, we fetch the following properties: *) DAV:baseline-collection, which is a complete tree of the Baseline (in SVN terms, this tree is rooted at a specific revision) *) DAV:version-name to get the revision of the Baseline that we are querying. When asking about the HEAD, this tells us its revision. */ if (revision == SVN_INVALID_REVNUM) { /* Fetch the latest revision */ const svn_string_t *baseline; /* Get the Baseline from the DAV:checked-in value, then fetch its DAV:baseline-collection property. */ /* ### should wrap this with info about rsrc==VCC */ SVN_ERR(svn_ra_neon__get_one_prop(&baseline, sess, vcc, NULL, &svn_ra_neon__checked_in_prop, pool)); /* ### do we want to optimize the props we fetch, based on what the ### user asked for? i.e. omit version-name if latest_rev is NULL */ SVN_ERR(svn_ra_neon__get_props_resource(&rsrc, sess, baseline->data, NULL, which_props, pool)); } else { /* Fetch a specific revision */ char label[20]; /* ### send Label hdr, get DAV:baseline-collection [from the baseline] */ apr_snprintf(label, sizeof(label), "%ld", revision); /* ### do we want to optimize the props we fetch, based on what the ### user asked for? i.e. omit version-name if latest_rev is NULL */ SVN_ERR(svn_ra_neon__get_props_resource(&rsrc, sess, vcc, label, which_props, pool)); } /* Return the baseline rsrc, which now contains whatever set of props the caller wanted. */ *bln_rsrc = rsrc; return SVN_NO_ERROR; }