2 * relocate.c: do wc repos relocation
4 * ====================================================================
5 * Copyright (c) 2002-2006 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 * ====================================================================
22 #include "svn_error.h"
23 #include "svn_pools.h"
31 #include "svn_private_config.h"
34 /* Relocate the main URL and the copyfrom URL for ENTRY by changing FROM to
35 * TO. ADM_ACCESS is the access baton for ENTRY. If DO_SYNC is set then
36 * the new entry will be written to disk immediately, otherwise only the
37 * entries cache will be affected. Calls VALIDATOR passing VALIDATOR_BATON
38 * to validate new URLs.
41 relocate_entry(svn_wc_adm_access_t
*adm_access
,
42 const svn_wc_entry_t
*entry
,
45 svn_wc_relocation_validator3_t validator
,
46 void *validator_baton
,
47 svn_boolean_t do_sync
,
50 svn_wc_entry_t entry2
;
51 apr_uint64_t flags
= 0;
52 apr_size_t from_len
= strlen(from
);
54 if (entry
->url
&& ! strncmp(entry
->url
, from
, from_len
))
56 entry2
.url
= apr_pstrcat(pool
, to
, entry
->url
+ from_len
, NULL
);
58 SVN_ERR(validator(validator_baton
, entry
->uuid
, entry2
.url
, NULL
,
60 flags
|= SVN_WC__ENTRY_MODIFY_URL
;
63 if (entry
->repos
&& (flags
& SVN_WC__ENTRY_MODIFY_URL
))
65 /* We can't relocate beyond the repository root, but the user is allowed
66 to specify a redundant part of the fs path in from and to, but only
67 if this part is identical in both strings. */
68 apr_size_t repos_len
= strlen(entry
->repos
);
70 if (from_len
>= repos_len
)
72 apr_size_t to_len
= strlen(to
);
73 apr_size_t fs_path_len
= from_len
- repos_len
;
74 if (to_len
< fs_path_len
75 || strncmp(from
+ repos_len
, to
+ (to_len
- fs_path_len
),
77 return svn_error_create(SVN_ERR_WC_INVALID_RELOCATION
, NULL
,
78 _("Relocate can only change the "
79 "repository part of an URL"));
80 /* Since the fs path part is redundant, we don't need to change
81 that part anyway, and the below code depends on this. */
83 to
= apr_pstrndup(pool
, to
, to_len
- fs_path_len
);
86 if (strncmp(from
, entry
->repos
, from_len
) == 0)
88 entry2
.repos
= apr_pstrcat(pool
, to
, entry
->repos
+ from_len
, NULL
);
89 flags
|= SVN_WC__ENTRY_MODIFY_REPOS
;
90 /* Make sure to is really the repository root. */
91 SVN_ERR(validator(validator_baton
, entry
->uuid
, entry2
.url
,
96 if (entry
->copyfrom_url
&& ! strncmp(entry
->copyfrom_url
, from
, from_len
))
98 entry2
.copyfrom_url
= apr_pstrcat(pool
, to
,
99 entry
->copyfrom_url
+ from_len
, NULL
);
101 SVN_ERR(validator(validator_baton
, entry
->uuid
,
102 entry2
.copyfrom_url
, NULL
, pool
));
103 flags
|= SVN_WC__ENTRY_MODIFY_COPYFROM_URL
;
107 SVN_ERR(svn_wc__entry_modify(adm_access
, entry
->name
,
108 &entry2
, flags
, do_sync
, pool
));
113 svn_wc_relocate3(const char *path
,
114 svn_wc_adm_access_t
*adm_access
,
117 svn_boolean_t recurse
,
118 svn_wc_relocation_validator3_t validator
,
119 void *validator_baton
,
123 apr_hash_index_t
*hi
;
124 const svn_wc_entry_t
*entry
;
127 SVN_ERR(svn_wc_entry(&entry
, path
, adm_access
, TRUE
, pool
));
129 return svn_error_create(SVN_ERR_ENTRY_NOT_FOUND
, NULL
, NULL
);
131 if (entry
->kind
== svn_node_file
)
133 SVN_ERR(relocate_entry(adm_access
, entry
, from
, to
,
134 validator
, validator_baton
, TRUE
/* sync */,
139 /* Relocate THIS_DIR first, in order to pre-validate the relocated URL
140 of all of the other entries. This is technically cheating because
141 it relies on knowledge of the libsvn_client implementation, but it
142 significantly cuts down on the number of expensive validations the
143 validator has to do. ### Should svn_wc.h document the ordering? */
144 SVN_ERR(svn_wc_entries_read(&entries
, adm_access
, TRUE
, pool
));
145 entry
= apr_hash_get(entries
, SVN_WC_ENTRY_THIS_DIR
, APR_HASH_KEY_STRING
);
146 SVN_ERR(relocate_entry(adm_access
, entry
, from
, to
,
147 validator
, validator_baton
, FALSE
, pool
));
149 subpool
= svn_pool_create(pool
);
151 for (hi
= apr_hash_first(pool
, entries
); hi
; hi
= apr_hash_next(hi
))
156 apr_hash_this(hi
, &key
, NULL
, &val
);
159 if (strcmp(key
, SVN_WC_ENTRY_THIS_DIR
) == 0)
162 svn_pool_clear(subpool
);
164 if (recurse
&& (entry
->kind
== svn_node_dir
)
165 && (! entry
->deleted
|| (entry
->schedule
== svn_wc_schedule_add
))
168 svn_wc_adm_access_t
*subdir_access
;
169 const char *subdir
= svn_path_join(path
, key
, subpool
);
170 if (svn_wc__adm_missing(adm_access
, subdir
))
172 SVN_ERR(svn_wc_adm_retrieve(&subdir_access
, adm_access
,
174 SVN_ERR(svn_wc_relocate3(subdir
, subdir_access
, from
, to
,
176 validator_baton
, subpool
));
178 SVN_ERR(relocate_entry(adm_access
, entry
, from
, to
,
179 validator
, validator_baton
, FALSE
, subpool
));
182 svn_pool_destroy(subpool
);
184 SVN_ERR(svn_wc__props_delete(path
, svn_wc__props_wcprop
, adm_access
, pool
));
185 SVN_ERR(svn_wc__entries_write(entries
, adm_access
, pool
));
189 /* Compatibility baton and wrapper. */
190 struct compat2_baton
{
191 svn_wc_relocation_validator2_t validator
;
195 /* Compatibility baton and wrapper. */
196 struct compat_baton
{
197 svn_wc_relocation_validator_t validator
;
201 /* This implements svn_wc_relocate_validator3_t. */
203 compat2_validator(void *baton
,
206 const char *root_url
,
209 struct compat2_baton
*cb
= baton
;
210 /* The old callback type doesn't set root_url. */
211 return cb
->validator(cb
->baton
, uuid
,
212 (root_url
? root_url
: url
), (root_url
? TRUE
: FALSE
),
216 /* This implements svn_wc_relocate_validator3_t. */
218 compat_validator(void *baton
,
221 const char *root_url
,
224 struct compat_baton
*cb
= baton
;
225 /* The old callback type doesn't allow uuid to be NULL. */
227 return cb
->validator(cb
->baton
, uuid
, url
);
232 svn_wc_relocate2(const char *path
,
233 svn_wc_adm_access_t
*adm_access
,
236 svn_boolean_t recurse
,
237 svn_wc_relocation_validator2_t validator
,
238 void *validator_baton
,
241 struct compat2_baton cb
;
243 cb
.validator
= validator
;
244 cb
.baton
= validator_baton
;
246 return svn_wc_relocate3(path
, adm_access
, from
, to
, recurse
,
247 compat2_validator
, &cb
, pool
);
251 svn_wc_relocate(const char *path
,
252 svn_wc_adm_access_t
*adm_access
,
255 svn_boolean_t recurse
,
256 svn_wc_relocation_validator_t validator
,
257 void *validator_baton
,
260 struct compat_baton cb
;
262 cb
.validator
= validator
;
263 cb
.baton
= validator_baton
;
265 return svn_wc_relocate3(path
, adm_access
, from
, to
, recurse
,
266 compat_validator
, &cb
, pool
);