1 /*
2 * cleanup.c: handle cleaning up workqueue items
3 *
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 * ====================================================================
22 */
23
24
25
26 #include <string.h>
27
28 #include "svn_wc.h"
29 #include "svn_error.h"
30 #include "svn_pools.h"
31 #include "svn_io.h"
32 #include "svn_dirent_uri.h"
33
34 #include "wc.h"
35 #include "adm_files.h"
36 #include "lock.h"
37 #include "workqueue.h"
38
39 #include "private/svn_wc_private.h"
40 #include "svn_private_config.h"
41
42
43 /*** Recursively do log things. ***/
44
45 /* */
46 static svn_error_t *
can_be_cleaned(int * wc_format,svn_wc__db_t * db,const char * local_abspath,apr_pool_t * scratch_pool)47 can_be_cleaned(int *wc_format,
48 svn_wc__db_t *db,
49 const char *local_abspath,
50 apr_pool_t *scratch_pool)
51 {
52 SVN_ERR(svn_wc__internal_check_wc(wc_format, db,
53 local_abspath, FALSE, scratch_pool));
54
55 /* a "version" of 0 means a non-wc directory */
56 if (*wc_format == 0)
57 return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
58 _("'%s' is not a working copy directory"),
59 svn_dirent_local_style(local_abspath,
60 scratch_pool));
61
62 if (*wc_format < SVN_WC__WC_NG_VERSION)
63 return svn_error_create(SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
64 _("Log format too old, please use "
65 "Subversion 1.6 or earlier"));
66
67 return SVN_NO_ERROR;
68 }
69
70 /* Do a modifed check for LOCAL_ABSPATH, and all working children, to force
71 timestamp repair. */
72 static svn_error_t *
repair_timestamps(svn_wc__db_t * db,const char * local_abspath,svn_cancel_func_t cancel_func,void * cancel_baton,apr_pool_t * scratch_pool)73 repair_timestamps(svn_wc__db_t *db,
74 const char *local_abspath,
75 svn_cancel_func_t cancel_func,
76 void *cancel_baton,
77 apr_pool_t *scratch_pool)
78 {
79 svn_node_kind_t kind;
80 svn_wc__db_status_t status;
81
82 if (cancel_func)
83 SVN_ERR(cancel_func(cancel_baton));
84
85 SVN_ERR(svn_wc__db_read_info(&status, &kind,
86 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
87 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
88 NULL, NULL, NULL, NULL, NULL, NULL,
89 NULL, NULL, NULL,
90 db, local_abspath, scratch_pool, scratch_pool));
91
92 if (status == svn_wc__db_status_server_excluded
93 || status == svn_wc__db_status_deleted
94 || status == svn_wc__db_status_excluded
95 || status == svn_wc__db_status_not_present)
96 return SVN_NO_ERROR;
97
98 if (kind == svn_node_file
99 || kind == svn_node_symlink)
100 {
101 svn_boolean_t modified;
102 SVN_ERR(svn_wc__internal_file_modified_p(&modified,
103 db, local_abspath, FALSE,
104 scratch_pool));
105 }
106 else if (kind == svn_node_dir)
107 {
108 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
109 const apr_array_header_t *children;
110 int i;
111
112 SVN_ERR(svn_wc__db_read_children_of_working_node(&children, db,
113 local_abspath,
114 scratch_pool,
115 iterpool));
116 for (i = 0; i < children->nelts; ++i)
117 {
118 const char *child_abspath;
119
120 svn_pool_clear(iterpool);
121
122 child_abspath = svn_dirent_join(local_abspath,
123 APR_ARRAY_IDX(children, i,
124 const char *),
125 iterpool);
126
127 SVN_ERR(repair_timestamps(db, child_abspath,
128 cancel_func, cancel_baton, iterpool));
129 }
130 svn_pool_destroy(iterpool);
131 }
132
133 return SVN_NO_ERROR;
134 }
135
136 /* */
137 static svn_error_t *
cleanup_internal(svn_wc__db_t * db,const char * dir_abspath,svn_cancel_func_t cancel_func,void * cancel_baton,apr_pool_t * scratch_pool)138 cleanup_internal(svn_wc__db_t *db,
139 const char *dir_abspath,
140 svn_cancel_func_t cancel_func,
141 void *cancel_baton,
142 apr_pool_t *scratch_pool)
143 {
144 int wc_format;
145 svn_boolean_t is_wcroot;
146 const char *lock_abspath;
147
148 /* Can we even work with this directory? */
149 SVN_ERR(can_be_cleaned(&wc_format, db, dir_abspath, scratch_pool));
150
151 /* We cannot obtain a lock on a directory that's within a locked
152 subtree, so always run cleanup from the lock owner. */
153 SVN_ERR(svn_wc__db_wclock_find_root(&lock_abspath, db, dir_abspath,
154 scratch_pool, scratch_pool));
155 if (lock_abspath)
156 dir_abspath = lock_abspath;
157 SVN_ERR(svn_wc__db_wclock_obtain(db, dir_abspath, -1, TRUE, scratch_pool));
158
159 /* Run our changes before the subdirectories. We may not have to recurse
160 if we blow away a subdir. */
161 if (wc_format >= SVN_WC__HAS_WORK_QUEUE)
162 SVN_ERR(svn_wc__wq_run(db, dir_abspath, cancel_func, cancel_baton,
163 scratch_pool));
164
165 SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, db, dir_abspath, scratch_pool));
166
167 #ifdef SVN_DEBUG
168 SVN_ERR(svn_wc__db_verify(db, dir_abspath, scratch_pool));
169 #endif
170
171 /* Perform these operations if we lock the entire working copy.
172 Note that we really need to check a wcroot value and not
173 svn_wc__check_wcroot() as that function, will just return true
174 once we start sharing databases with externals.
175 */
176 if (is_wcroot)
177 {
178 /* Cleanup the tmp area of the admin subdir, if running the log has not
179 removed it! The logs have been run, so anything left here has no hope
180 of being useful. */
181 SVN_ERR(svn_wc__adm_cleanup_tmp_area(db, dir_abspath, scratch_pool));
182
183 /* Remove unreferenced pristine texts */
184 SVN_ERR(svn_wc__db_pristine_cleanup(db, dir_abspath, scratch_pool));
185 }
186
187 SVN_ERR(repair_timestamps(db, dir_abspath, cancel_func, cancel_baton,
188 scratch_pool));
189
190 /* All done, toss the lock */
191 SVN_ERR(svn_wc__db_wclock_release(db, dir_abspath, scratch_pool));
192
193 return SVN_NO_ERROR;
194 }
195
196
197 /* ### possibly eliminate the WC_CTX parameter? callers really shouldn't
198 ### be doing anything *but* running a cleanup, and we need a special
199 ### DB anyway. ... *shrug* ... consider later. */
200 svn_error_t *
svn_wc_cleanup3(svn_wc_context_t * wc_ctx,const char * local_abspath,svn_cancel_func_t cancel_func,void * cancel_baton,apr_pool_t * scratch_pool)201 svn_wc_cleanup3(svn_wc_context_t *wc_ctx,
202 const char *local_abspath,
203 svn_cancel_func_t cancel_func,
204 void *cancel_baton,
205 apr_pool_t *scratch_pool)
206 {
207 svn_wc__db_t *db;
208
209 SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
210
211 /* We need a DB that allows a non-empty work queue (though it *will*
212 auto-upgrade). We'll handle everything manually. */
213 SVN_ERR(svn_wc__db_open(&db,
214 NULL /* ### config */, FALSE, FALSE,
215 scratch_pool, scratch_pool));
216
217 SVN_ERR(cleanup_internal(db, local_abspath, cancel_func, cancel_baton,
218 scratch_pool));
219
220 /* The DAV cache suffers from flakiness from time to time, and the
221 pre-1.7 prescribed workarounds aren't as user-friendly in WC-NG. */
222 SVN_ERR(svn_wc__db_base_clear_dav_cache_recursive(db, local_abspath,
223 scratch_pool));
224
225 SVN_ERR(svn_wc__db_vacuum(db, local_abspath, scratch_pool));
226
227 /* We're done with this DB, so proactively close it. */
228 SVN_ERR(svn_wc__db_close(db));
229
230 return SVN_NO_ERROR;
231 }
232