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/* */
46static svn_error_t *
47can_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/* Dummy svn_wc_status_func4_t implementation */
71static svn_error_t *
72status_dummy_callback(void *baton,
73                      const char *local_abspath,
74                      const svn_wc_status3_t *status,
75                      apr_pool_t *scratch_pool)
76{
77  return SVN_NO_ERROR;
78}
79
80/* */
81static svn_error_t *
82cleanup_internal(svn_wc__db_t *db,
83                 const char *dir_abspath,
84                 svn_boolean_t break_locks,
85                 svn_boolean_t fix_recorded_timestamps,
86                 svn_boolean_t vacuum_pristines,
87                 svn_cancel_func_t cancel_func,
88                 void *cancel_baton,
89                 apr_pool_t *scratch_pool)
90{
91  int wc_format;
92  svn_boolean_t is_wcroot;
93  const char *lock_abspath;
94
95  /* Can we even work with this directory?  */
96  SVN_ERR(can_be_cleaned(&wc_format, db, dir_abspath, scratch_pool));
97
98  /* We cannot obtain a lock on a directory that's within a locked
99     subtree, so always run cleanup from the lock owner. */
100  SVN_ERR(svn_wc__db_wclock_find_root(&lock_abspath, db, dir_abspath,
101                                      scratch_pool, scratch_pool));
102  if (lock_abspath)
103    dir_abspath = lock_abspath;
104  SVN_ERR(svn_wc__db_wclock_obtain(db, dir_abspath, -1, break_locks, scratch_pool));
105
106  /* Run our changes before the subdirectories. We may not have to recurse
107     if we blow away a subdir.  */
108  if (wc_format >= SVN_WC__HAS_WORK_QUEUE)
109    SVN_ERR(svn_wc__wq_run(db, dir_abspath, cancel_func, cancel_baton,
110                           scratch_pool));
111
112  SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, db, dir_abspath, scratch_pool));
113
114#ifdef SVN_DEBUG
115  SVN_ERR(svn_wc__db_verify(db, dir_abspath, scratch_pool));
116#endif
117
118  /* Perform these operations if we lock the entire working copy.
119     Note that we really need to check a wcroot value and not
120     svn_wc__check_wcroot() as that function, will just return true
121     once we start sharing databases with externals.
122   */
123  if (is_wcroot && vacuum_pristines)
124    {
125    /* Cleanup the tmp area of the admin subdir, if running the log has not
126       removed it!  The logs have been run, so anything left here has no hope
127       of being useful. */
128      SVN_ERR(svn_wc__adm_cleanup_tmp_area(db, dir_abspath, scratch_pool));
129
130      /* Remove unreferenced pristine texts */
131      SVN_ERR(svn_wc__db_pristine_cleanup(db, dir_abspath, scratch_pool));
132    }
133
134  if (fix_recorded_timestamps)
135    {
136      /* Instead of implementing a separate repair step here, use the standard
137         status walker's optimized implementation, which performs repairs when
138         there is a lock. */
139      SVN_ERR(svn_wc__internal_walk_status(db, dir_abspath, svn_depth_infinity,
140                                           FALSE /* get_all */,
141                                           FALSE /* no_ignore */,
142                                           FALSE /* ignore_text_mods */,
143                                           NULL /* ignore patterns */,
144                                           status_dummy_callback, NULL,
145                                           cancel_func, cancel_baton,
146                                           scratch_pool));
147    }
148
149  /* All done, toss the lock */
150  SVN_ERR(svn_wc__db_wclock_release(db, dir_abspath, scratch_pool));
151
152  return SVN_NO_ERROR;
153}
154
155svn_error_t *
156svn_wc_cleanup4(svn_wc_context_t *wc_ctx,
157                const char *local_abspath,
158                svn_boolean_t break_locks,
159                svn_boolean_t fix_recorded_timestamps,
160                svn_boolean_t clear_dav_cache,
161                svn_boolean_t vacuum_pristines,
162                svn_cancel_func_t cancel_func,
163                void *cancel_baton,
164                svn_wc_notify_func2_t notify_func,
165                void *notify_baton,
166                apr_pool_t *scratch_pool)
167{
168  svn_wc__db_t *db;
169
170  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
171  SVN_ERR_ASSERT(wc_ctx != NULL);
172
173  if (break_locks)
174    {
175      /* We'll handle everything manually.  */
176
177      /* Close the existing database (if any) to avoid problems with
178         exclusive database usage */
179      SVN_ERR(svn_wc__db_drop_root(wc_ctx->db, local_abspath,
180                                   scratch_pool));
181
182      SVN_ERR(svn_wc__db_open(&db,
183                              NULL /* ### config */, FALSE, FALSE,
184                              scratch_pool, scratch_pool));
185    }
186  else
187    db = wc_ctx->db;
188
189  SVN_ERR(cleanup_internal(db, local_abspath,
190                           break_locks,
191                           fix_recorded_timestamps,
192                           vacuum_pristines,
193                           cancel_func, cancel_baton,
194                           scratch_pool));
195
196  /* The DAV cache suffers from flakiness from time to time, and the
197     pre-1.7 prescribed workarounds aren't as user-friendly in WC-NG. */
198  if (clear_dav_cache)
199    SVN_ERR(svn_wc__db_base_clear_dav_cache_recursive(db, local_abspath,
200                                                      scratch_pool));
201
202  if (vacuum_pristines)
203    SVN_ERR(svn_wc__db_vacuum(db, local_abspath, scratch_pool));
204
205  /* We're done with this DB, so proactively close it.  */
206  if (break_locks)
207    SVN_ERR(svn_wc__db_close(db));
208
209  return SVN_NO_ERROR;
210}
211