2 * delete.c: wrappers around wc delete functionality.
4 * ====================================================================
5 * Copyright (c) 2000-2004 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 /* ==================================================================== */
25 #include <apr_file_io.h>
26 #include "svn_types.h"
27 #include "svn_pools.h"
29 #include "svn_client.h"
30 #include "svn_error.h"
34 #include "svn_private_config.h"
41 svn_error_t
*err
; /* the error generated for an undeletable path. */
42 apr_pool_t
*pool
; /* for temporary allocations */
46 /* An svn_wc_status_func_t callback function for finding
47 status structures which are not safely deletable. */
49 find_undeletables(void *baton
,
51 svn_wc_status2_t
*status
)
53 struct status_baton
*sb
= baton
;
55 /* If we already have an error, don't lose that fact. */
59 /* Check for error-ful states. */
60 if (status
->text_status
== svn_wc_status_obstructed
)
61 sb
->err
= svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND
, NULL
,
62 _("'%s' is in the way of the resource "
63 "actually under version control"),
64 svn_path_local_style(path
, sb
->pool
));
65 else if (! status
->entry
)
66 sb
->err
= svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE
, NULL
,
67 _("'%s' is not under version control"),
68 svn_path_local_style(path
, sb
->pool
));
70 else if ((status
->text_status
!= svn_wc_status_normal
71 && status
->text_status
!= svn_wc_status_deleted
72 && status
->text_status
!= svn_wc_status_missing
)
74 (status
->prop_status
!= svn_wc_status_none
75 && status
->prop_status
!= svn_wc_status_normal
))
76 sb
->err
= svn_error_createf(SVN_ERR_CLIENT_MODIFIED
, NULL
,
77 _("'%s' has local modifications"),
78 svn_path_local_style(path
, sb
->pool
));
83 svn_client__can_delete(const char *path
,
84 svn_client_ctx_t
*ctx
,
87 struct status_baton sb
;
88 svn_opt_revision_t revision
;
89 revision
.kind
= svn_opt_revision_unspecified
;
90 sb
.err
= SVN_NO_ERROR
;
93 /* Use an infinite-depth status check to see if there's anything in
94 or under PATH which would make it unsafe for deletion. The
95 status callback function find_undeletables() makes the
96 determination, setting sb.err if it finds anything that shouldn't
98 SVN_ERR(svn_client_status3
99 (NULL
, path
, &revision
, find_undeletables
, &sb
,
100 svn_depth_infinity
, FALSE
, FALSE
, FALSE
, FALSE
, NULL
, ctx
, pool
));
106 path_driver_cb_func(void **dir_baton
,
108 void *callback_baton
,
112 const svn_delta_editor_t
*editor
= callback_baton
;
114 return editor
->delete_entry(path
, SVN_INVALID_REVNUM
, parent_baton
, pool
);
119 delete_urls(svn_commit_info_t
**commit_info_p
,
120 const apr_array_header_t
*paths
,
121 svn_client_ctx_t
*ctx
,
124 svn_ra_session_t
*ra_session
;
125 const svn_delta_editor_t
*editor
;
129 apr_hash_t
*revprop_table
;
130 svn_node_kind_t kind
;
131 apr_array_header_t
*targets
;
135 apr_pool_t
*subpool
= svn_pool_create(pool
);
137 /* Condense our list of deletion targets. */
138 SVN_ERR(svn_path_condense_targets(&common
, &targets
, paths
, TRUE
, pool
));
139 if (! targets
->nelts
)
142 svn_path_split(common
, &common
, &bname
, pool
);
143 APR_ARRAY_PUSH(targets
, const char *) = bname
;
146 /* Create new commit items and add them to the array. */
147 if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx
))
149 svn_client_commit_item3_t
*item
;
150 const char *tmp_file
;
151 apr_array_header_t
*commit_items
152 = apr_array_make(pool
, targets
->nelts
, sizeof(item
));
154 for (i
= 0; i
< targets
->nelts
; i
++)
156 const char *path
= APR_ARRAY_IDX(targets
, i
, const char *);
157 SVN_ERR(svn_client_commit_item_create
158 ((const svn_client_commit_item3_t
**) &item
, pool
));
159 item
->url
= svn_path_join(common
, path
, pool
);
160 item
->state_flags
= SVN_CLIENT_COMMIT_ITEM_DELETE
;
161 APR_ARRAY_PUSH(commit_items
, svn_client_commit_item3_t
*) = item
;
163 SVN_ERR(svn_client__get_log_msg(&log_msg
, &tmp_file
, commit_items
,
167 svn_pool_destroy(subpool
);
174 SVN_ERR(svn_client__get_revprop_table(&revprop_table
, log_msg
, ctx
, pool
));
176 /* Open an RA session for the URL. Note that we don't have a local
177 directory, nor a place to put temp files. */
178 SVN_ERR(svn_client__open_ra_session_internal(&ra_session
, common
, NULL
,
179 NULL
, NULL
, FALSE
, TRUE
,
182 /* Verify that each thing to be deleted actually exists (to prevent
183 the creation of a revision that has no changes, since the
184 filesystem allows for no-op deletes). */
185 for (i
= 0; i
< targets
->nelts
; i
++)
187 const char *path
= APR_ARRAY_IDX(targets
, i
, const char *);
188 svn_pool_clear(subpool
);
189 path
= svn_path_uri_decode(path
, pool
);
190 APR_ARRAY_IDX(targets
, i
, const char *) = path
;
191 SVN_ERR(svn_ra_check_path(ra_session
, path
, SVN_INVALID_REVNUM
,
193 if (kind
== svn_node_none
)
194 return svn_error_createf(SVN_ERR_FS_NOT_FOUND
, NULL
,
195 "URL '%s' does not exist",
196 svn_path_local_style(path
, pool
));
198 svn_pool_destroy(subpool
);
200 /* Fetch RA commit editor */
201 SVN_ERR(svn_client__commit_get_baton(&commit_baton
, commit_info_p
, pool
));
202 SVN_ERR(svn_ra_get_commit_editor3(ra_session
, &editor
, &edit_baton
,
204 svn_client__commit_callback
,
206 NULL
, TRUE
, /* No lock tokens */
209 /* Call the path-based editor driver. */
210 err
= svn_delta_path_driver(editor
, edit_baton
, SVN_INVALID_REVNUM
,
211 targets
, path_driver_cb_func
,
212 (void *)editor
, pool
);
215 /* At least try to abort the edit (and fs txn) before throwing err. */
216 svn_error_clear(editor
->abort_edit(edit_baton
, pool
));
220 /* Close the edit. */
221 SVN_ERR(editor
->close_edit(edit_baton
, pool
));
227 svn_client__wc_delete(const char *path
,
228 svn_wc_adm_access_t
*adm_access
,
230 svn_boolean_t dry_run
,
231 svn_boolean_t keep_local
,
232 svn_wc_notify_func2_t notify_func
,
234 svn_client_ctx_t
*ctx
,
238 if (!force
&& !keep_local
)
239 /* Verify that there are no "awkward" files */
240 SVN_ERR(svn_client__can_delete(path
, ctx
, pool
));
243 /* Mark the entry for commit deletion and perform wc deletion */
244 SVN_ERR(svn_wc_delete3(path
, adm_access
,
245 ctx
->cancel_func
, ctx
->cancel_baton
,
246 notify_func
, notify_baton
, keep_local
, pool
));
252 svn_client_delete3(svn_commit_info_t
**commit_info_p
,
253 const apr_array_header_t
*paths
,
255 svn_boolean_t keep_local
,
256 svn_client_ctx_t
*ctx
,
262 if (svn_path_is_url(APR_ARRAY_IDX(paths
, 0, const char *)))
264 SVN_ERR(delete_urls(commit_info_p
, paths
, ctx
, pool
));
268 apr_pool_t
*subpool
= svn_pool_create(pool
);
271 for (i
= 0; i
< paths
->nelts
; i
++)
273 svn_wc_adm_access_t
*adm_access
;
274 const char *path
= APR_ARRAY_IDX(paths
, i
, const char *);
275 const char *parent_path
;
277 svn_pool_clear(subpool
);
278 parent_path
= svn_path_dirname(path
, subpool
);
280 /* See if the user wants us to stop. */
281 if (ctx
->cancel_func
)
282 SVN_ERR(ctx
->cancel_func(ctx
->cancel_baton
));
284 /* Let the working copy library handle the PATH. */
285 SVN_ERR(svn_wc_adm_open3(&adm_access
, NULL
, parent_path
,
286 TRUE
, 0, ctx
->cancel_func
,
287 ctx
->cancel_baton
, subpool
));
288 SVN_ERR(svn_client__wc_delete(path
, adm_access
, force
,
293 SVN_ERR(svn_wc_adm_close(adm_access
));
295 svn_pool_destroy(subpool
);
302 svn_client_delete2(svn_commit_info_t
**commit_info_p
,
303 const apr_array_header_t
*paths
,
305 svn_client_ctx_t
*ctx
,
308 return svn_client_delete3(commit_info_p
, paths
, force
, FALSE
, ctx
, pool
);
312 svn_client_delete(svn_client_commit_info_t
**commit_info_p
,
313 const apr_array_header_t
*paths
,
315 svn_client_ctx_t
*ctx
,
318 svn_commit_info_t
*commit_info
= NULL
;
319 svn_error_t
*err
= NULL
;
321 err
= svn_client_delete2(&commit_info
, paths
, force
, ctx
, pool
);
322 /* These structs have the same layout for the common fields. */
323 *commit_info_p
= (svn_client_commit_info_t
*) commit_info
;