Change the format of the revprops block sent in svnserve for
[svn.git] / subversion / libsvn_client / util.c
blob93b5a10ab2046b2684a068893a301306129c1b0d
1 /*
2 * util.c : utility functions for the libsvn_client library
4 * ====================================================================
5 * Copyright (c) 2005-2007 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 #include <assert.h>
20 #include <apr_pools.h>
21 #include <apr_strings.h>
23 #include "svn_pools.h"
24 #include "svn_string.h"
25 #include "svn_error.h"
26 #include "svn_types.h"
27 #include "svn_opt.h"
28 #include "svn_props.h"
29 #include "svn_path.h"
30 #include "svn_wc.h"
31 #include "svn_client.h"
33 #include "private/svn_wc_private.h"
35 #include "client.h"
37 #include "svn_private_config.h"
39 /* Duplicate a HASH containing (char * -> svn_string_t *) key/value
40 pairs using POOL. */
41 static apr_hash_t *
42 string_hash_dup(apr_hash_t *hash, apr_pool_t *pool)
44 apr_hash_index_t *hi;
45 const void *key;
46 apr_ssize_t klen;
47 void *val;
48 apr_hash_t *new_hash = apr_hash_make(pool);
49 for (hi = apr_hash_first(pool, hash); hi; hi = apr_hash_next(hi))
51 apr_hash_this(hi, &key, &klen, &val);
52 key = apr_pstrdup(pool, key);
53 val = svn_string_dup(val, pool);
54 apr_hash_set(new_hash, key, klen, val);
56 return new_hash;
59 svn_error_t *
60 svn_client_commit_item_create(const svn_client_commit_item3_t **item,
61 apr_pool_t *pool)
63 *item = apr_pcalloc(pool, sizeof(svn_client_commit_item3_t));
64 return SVN_NO_ERROR;
67 svn_client_commit_item3_t *
68 svn_client_commit_item3_dup(const svn_client_commit_item3_t *item,
69 apr_pool_t *pool)
71 svn_client_commit_item3_t *new_item = apr_palloc(pool, sizeof(*new_item));
73 *new_item = *item;
75 if (new_item->path)
76 new_item->path = apr_pstrdup(pool, new_item->path);
78 if (new_item->url)
79 new_item->url = apr_pstrdup(pool, new_item->url);
81 if (new_item->copyfrom_url)
82 new_item->copyfrom_url = apr_pstrdup(pool, new_item->copyfrom_url);
84 if (new_item->incoming_prop_changes)
85 new_item->incoming_prop_changes =
86 svn_prop_array_dup(new_item->incoming_prop_changes, pool);
88 if (new_item->outgoing_prop_changes)
89 new_item->outgoing_prop_changes =
90 svn_prop_array_dup(new_item->outgoing_prop_changes, pool);
92 return new_item;
95 svn_client_commit_item2_t *
96 svn_client_commit_item2_dup(const svn_client_commit_item2_t *item,
97 apr_pool_t *pool)
99 svn_client_commit_item2_t *new_item = apr_palloc(pool, sizeof(*new_item));
101 *new_item = *item;
103 if (new_item->path)
104 new_item->path = apr_pstrdup(pool, new_item->path);
106 if (new_item->url)
107 new_item->url = apr_pstrdup(pool, new_item->url);
109 if (new_item->copyfrom_url)
110 new_item->copyfrom_url = apr_pstrdup(pool, new_item->copyfrom_url);
112 if (new_item->wcprop_changes)
113 new_item->wcprop_changes = svn_prop_array_dup(new_item->wcprop_changes,
114 pool);
116 return new_item;
119 svn_client_proplist_item_t *
120 svn_client_proplist_item_dup(const svn_client_proplist_item_t *item,
121 apr_pool_t * pool)
123 svn_client_proplist_item_t *new_item = apr_pcalloc(pool, sizeof(*new_item));
125 if (item->node_name)
126 new_item->node_name = svn_stringbuf_dup(item->node_name, pool);
128 if (item->prop_hash)
129 new_item->prop_hash = string_hash_dup(item->prop_hash, pool);
131 return new_item;
134 /* Return WC_PATH's URL and repository root in *URL and REPOS_ROOT,
135 respectively. Set *NEED_WC_CLEANUP if *ADM_ACCESS needed to be
136 acquired. */
137 static svn_error_t *
138 wc_path_to_repos_urls(const char **url, const char **repos_root,
139 svn_boolean_t *need_wc_cleanup,
140 svn_wc_adm_access_t **adm_access, const char *wc_path,
141 apr_pool_t *pool)
143 const svn_wc_entry_t *entry;
145 if (! *adm_access)
147 SVN_ERR(svn_wc_adm_probe_open3(adm_access, NULL, wc_path,
148 FALSE, 0, NULL, NULL, pool));
149 *need_wc_cleanup = TRUE;
151 SVN_ERR(svn_wc__entry_versioned(&entry, wc_path, *adm_access, FALSE, pool));
153 SVN_ERR(svn_client__entry_location(url, NULL, wc_path,
154 svn_opt_revision_unspecified, entry,
155 pool));
157 /* If we weren't provided a REPOS_ROOT, we'll try to read one from
158 the entry. The entry might not hold a URL -- in that case, we'll
159 need a fallback plan. */
160 if (*repos_root == NULL)
161 *repos_root = entry->repos;
163 return SVN_NO_ERROR;
167 svn_error_t *
168 svn_client__path_relative_to_root(const char **rel_path,
169 const char *path_or_url,
170 const char *repos_root,
171 svn_boolean_t include_leading_slash,
172 svn_ra_session_t *ra_session,
173 svn_wc_adm_access_t *adm_access,
174 apr_pool_t *pool)
176 svn_error_t *err = SVN_NO_ERROR;
177 svn_boolean_t need_wc_cleanup = FALSE;
179 assert(repos_root != NULL || ra_session != NULL);
181 /* If we have a WC path... */
182 if (! svn_path_is_url(path_or_url))
184 /* ...fetch its entry, and attempt to get both its full URL and
185 repository root URL. If we can't get REPOS_ROOT from the WC
186 entry, we'll get it from the RA layer.*/
187 err = wc_path_to_repos_urls(&path_or_url, &repos_root, &need_wc_cleanup,
188 &adm_access, path_or_url, pool);
189 if (err)
190 goto cleanup;
193 /* If we weren't provided a REPOS_ROOT, or couldn't find one in the
194 WC entry, we'll ask the RA layer. */
195 if (repos_root == NULL)
197 if ((err = svn_ra_get_repos_root2(ra_session, &repos_root, pool)))
198 goto cleanup;
201 /* Check if PATH_OR_URL *is* the repository root URL. */
202 if (strcmp(repos_root, path_or_url) == 0)
204 *rel_path = include_leading_slash ? "/" : "";
206 else
208 /* See if PATH_OR_URL is a child of REPOS_ROOT. If we get NULL
209 back from this, the two URLs have no commonality (which
210 should only happen if our caller provided us a REPOS_ROOT and
211 a PATH_OR_URL of something not in that repository). */
212 const char *rel_url = svn_path_is_child(repos_root, path_or_url, pool);
213 if (! rel_url)
215 err = svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
216 _("URL '%s' is not a child of repository "
217 "root URL '%s'"),
218 path_or_url, repos_root);
219 goto cleanup;
221 rel_url = svn_path_uri_decode(rel_url, pool);
222 *rel_path = include_leading_slash
223 ? apr_pstrcat(pool, "/", rel_url, NULL) : rel_url;
226 cleanup:
227 if (need_wc_cleanup)
229 svn_error_t *err2 = svn_wc_adm_close(adm_access);
230 if (! err)
231 err = err2;
232 else
233 svn_error_clear(err2);
235 return err;
238 svn_error_t *
239 svn_client__get_repos_root(const char **repos_root,
240 const char *path_or_url,
241 const svn_opt_revision_t *peg_revision,
242 svn_wc_adm_access_t *adm_access,
243 svn_client_ctx_t *ctx,
244 apr_pool_t *pool)
246 svn_revnum_t rev;
247 const char *target_url;
248 svn_boolean_t need_wc_cleanup = FALSE;
249 svn_error_t *err = SVN_NO_ERROR;
250 apr_pool_t *sesspool = NULL;
252 /* If PATH_OR_URL is a local path and PEG_REVISION keeps us looking
253 locally, we'll first check PATH_OR_URL's entry for a repository
254 root URL. */
255 if (!svn_path_is_url(path_or_url)
256 && (peg_revision->kind == svn_opt_revision_working
257 || peg_revision->kind == svn_opt_revision_base))
259 *repos_root = NULL;
260 err = wc_path_to_repos_urls(&path_or_url, repos_root, &need_wc_cleanup,
261 &adm_access, path_or_url, pool);
262 if (err)
263 goto cleanup;
265 else
267 *repos_root = NULL;
270 /* If PATH_OR_URL was a URL, or PEG_REVISION wasn't a client-side
271 revision, or we weren't otherwise able to find the repository
272 root URL in PATH_OR_URL's WC entry, we use the RA layer to look
273 it up. */
274 if (*repos_root == NULL)
276 svn_ra_session_t *ra_session;
277 sesspool = svn_pool_create(pool);
278 if ((err = svn_client__ra_session_from_path(&ra_session,
279 &rev,
280 &target_url,
281 path_or_url,
282 NULL,
283 peg_revision,
284 peg_revision,
285 ctx,
286 sesspool)))
287 goto cleanup;
289 if ((err = svn_ra_get_repos_root2(ra_session, repos_root, pool)))
290 goto cleanup;
293 cleanup:
294 if (sesspool)
295 svn_pool_destroy(sesspool);
297 if (need_wc_cleanup)
299 svn_error_t *err2 = svn_wc_adm_close(adm_access);
300 if (! err)
301 err = err2;
302 else
303 svn_error_clear(err2);
305 return err;
309 svn_error_t *
310 svn_client__default_walker_error_handler(const char *path,
311 svn_error_t *err,
312 void *walk_baton,
313 apr_pool_t *pool)
315 return err;