1251881Speter/*
2251881Speter * cleanup.c:  handle cleaning up workqueue items
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter
25251881Speter
26251881Speter#include <string.h>
27251881Speter
28251881Speter#include "svn_wc.h"
29251881Speter#include "svn_error.h"
30251881Speter#include "svn_pools.h"
31251881Speter#include "svn_io.h"
32251881Speter#include "svn_dirent_uri.h"
33251881Speter
34251881Speter#include "wc.h"
35251881Speter#include "adm_files.h"
36251881Speter#include "lock.h"
37251881Speter#include "workqueue.h"
38251881Speter
39251881Speter#include "private/svn_wc_private.h"
40251881Speter#include "svn_private_config.h"
41251881Speter
42251881Speter
43251881Speter/*** Recursively do log things. ***/
44251881Speter
45251881Speter/* */
46251881Speterstatic svn_error_t *
47251881Spetercan_be_cleaned(int *wc_format,
48251881Speter               svn_wc__db_t *db,
49251881Speter               const char *local_abspath,
50251881Speter               apr_pool_t *scratch_pool)
51251881Speter{
52251881Speter  SVN_ERR(svn_wc__internal_check_wc(wc_format, db,
53251881Speter                                    local_abspath, FALSE, scratch_pool));
54251881Speter
55251881Speter  /* a "version" of 0 means a non-wc directory */
56251881Speter  if (*wc_format == 0)
57251881Speter    return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
58251881Speter                             _("'%s' is not a working copy directory"),
59251881Speter                             svn_dirent_local_style(local_abspath,
60251881Speter                                                    scratch_pool));
61251881Speter
62251881Speter  if (*wc_format < SVN_WC__WC_NG_VERSION)
63251881Speter    return svn_error_create(SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
64251881Speter                            _("Log format too old, please use "
65251881Speter                              "Subversion 1.6 or earlier"));
66251881Speter
67251881Speter  return SVN_NO_ERROR;
68251881Speter}
69251881Speter
70289166Speter/* Dummy svn_wc_status_func4_t implementation */
71251881Speterstatic svn_error_t *
72289166Speterstatus_dummy_callback(void *baton,
73289166Speter                      const char *local_abspath,
74289166Speter                      const svn_wc_status3_t *status,
75289166Speter                      apr_pool_t *scratch_pool)
76251881Speter{
77251881Speter  return SVN_NO_ERROR;
78251881Speter}
79251881Speter
80251881Speter/* */
81251881Speterstatic svn_error_t *
82251881Spetercleanup_internal(svn_wc__db_t *db,
83251881Speter                 const char *dir_abspath,
84299742Sdim                 svn_boolean_t break_locks,
85299742Sdim                 svn_boolean_t fix_recorded_timestamps,
86299742Sdim                 svn_boolean_t vacuum_pristines,
87251881Speter                 svn_cancel_func_t cancel_func,
88251881Speter                 void *cancel_baton,
89251881Speter                 apr_pool_t *scratch_pool)
90251881Speter{
91251881Speter  int wc_format;
92251881Speter  svn_boolean_t is_wcroot;
93251881Speter  const char *lock_abspath;
94251881Speter
95251881Speter  /* Can we even work with this directory?  */
96251881Speter  SVN_ERR(can_be_cleaned(&wc_format, db, dir_abspath, scratch_pool));
97251881Speter
98251881Speter  /* We cannot obtain a lock on a directory that's within a locked
99251881Speter     subtree, so always run cleanup from the lock owner. */
100251881Speter  SVN_ERR(svn_wc__db_wclock_find_root(&lock_abspath, db, dir_abspath,
101251881Speter                                      scratch_pool, scratch_pool));
102251881Speter  if (lock_abspath)
103251881Speter    dir_abspath = lock_abspath;
104299742Sdim  SVN_ERR(svn_wc__db_wclock_obtain(db, dir_abspath, -1, break_locks, scratch_pool));
105251881Speter
106251881Speter  /* Run our changes before the subdirectories. We may not have to recurse
107251881Speter     if we blow away a subdir.  */
108251881Speter  if (wc_format >= SVN_WC__HAS_WORK_QUEUE)
109251881Speter    SVN_ERR(svn_wc__wq_run(db, dir_abspath, cancel_func, cancel_baton,
110251881Speter                           scratch_pool));
111251881Speter
112251881Speter  SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, db, dir_abspath, scratch_pool));
113251881Speter
114251881Speter#ifdef SVN_DEBUG
115251881Speter  SVN_ERR(svn_wc__db_verify(db, dir_abspath, scratch_pool));
116251881Speter#endif
117251881Speter
118251881Speter  /* Perform these operations if we lock the entire working copy.
119251881Speter     Note that we really need to check a wcroot value and not
120251881Speter     svn_wc__check_wcroot() as that function, will just return true
121251881Speter     once we start sharing databases with externals.
122251881Speter   */
123299742Sdim  if (is_wcroot && vacuum_pristines)
124251881Speter    {
125251881Speter    /* Cleanup the tmp area of the admin subdir, if running the log has not
126251881Speter       removed it!  The logs have been run, so anything left here has no hope
127251881Speter       of being useful. */
128251881Speter      SVN_ERR(svn_wc__adm_cleanup_tmp_area(db, dir_abspath, scratch_pool));
129251881Speter
130251881Speter      /* Remove unreferenced pristine texts */
131251881Speter      SVN_ERR(svn_wc__db_pristine_cleanup(db, dir_abspath, scratch_pool));
132251881Speter    }
133251881Speter
134299742Sdim  if (fix_recorded_timestamps)
135299742Sdim    {
136299742Sdim      /* Instead of implementing a separate repair step here, use the standard
137299742Sdim         status walker's optimized implementation, which performs repairs when
138299742Sdim         there is a lock. */
139299742Sdim      SVN_ERR(svn_wc__internal_walk_status(db, dir_abspath, svn_depth_infinity,
140299742Sdim                                           FALSE /* get_all */,
141299742Sdim                                           FALSE /* no_ignore */,
142299742Sdim                                           FALSE /* ignore_text_mods */,
143299742Sdim                                           NULL /* ignore patterns */,
144299742Sdim                                           status_dummy_callback, NULL,
145299742Sdim                                           cancel_func, cancel_baton,
146299742Sdim                                           scratch_pool));
147299742Sdim    }
148251881Speter
149251881Speter  /* All done, toss the lock */
150251881Speter  SVN_ERR(svn_wc__db_wclock_release(db, dir_abspath, scratch_pool));
151251881Speter
152251881Speter  return SVN_NO_ERROR;
153251881Speter}
154251881Speter
155251881Spetersvn_error_t *
156299742Sdimsvn_wc_cleanup4(svn_wc_context_t *wc_ctx,
157251881Speter                const char *local_abspath,
158299742Sdim                svn_boolean_t break_locks,
159299742Sdim                svn_boolean_t fix_recorded_timestamps,
160299742Sdim                svn_boolean_t clear_dav_cache,
161299742Sdim                svn_boolean_t vacuum_pristines,
162251881Speter                svn_cancel_func_t cancel_func,
163251881Speter                void *cancel_baton,
164299742Sdim                svn_wc_notify_func2_t notify_func,
165299742Sdim                void *notify_baton,
166251881Speter                apr_pool_t *scratch_pool)
167251881Speter{
168251881Speter  svn_wc__db_t *db;
169251881Speter
170251881Speter  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
171299742Sdim  SVN_ERR_ASSERT(wc_ctx != NULL);
172251881Speter
173299742Sdim  if (break_locks)
174299742Sdim    {
175299742Sdim      /* We'll handle everything manually.  */
176251881Speter
177299742Sdim      /* Close the existing database (if any) to avoid problems with
178299742Sdim         exclusive database usage */
179299742Sdim      SVN_ERR(svn_wc__db_drop_root(wc_ctx->db, local_abspath,
180299742Sdim                                   scratch_pool));
181299742Sdim
182299742Sdim      SVN_ERR(svn_wc__db_open(&db,
183299742Sdim                              NULL /* ### config */, FALSE, FALSE,
184299742Sdim                              scratch_pool, scratch_pool));
185299742Sdim    }
186299742Sdim  else
187299742Sdim    db = wc_ctx->db;
188299742Sdim
189299742Sdim  SVN_ERR(cleanup_internal(db, local_abspath,
190299742Sdim                           break_locks,
191299742Sdim                           fix_recorded_timestamps,
192299742Sdim                           vacuum_pristines,
193299742Sdim                           cancel_func, cancel_baton,
194251881Speter                           scratch_pool));
195251881Speter
196251881Speter  /* The DAV cache suffers from flakiness from time to time, and the
197251881Speter     pre-1.7 prescribed workarounds aren't as user-friendly in WC-NG. */
198299742Sdim  if (clear_dav_cache)
199299742Sdim    SVN_ERR(svn_wc__db_base_clear_dav_cache_recursive(db, local_abspath,
200299742Sdim                                                      scratch_pool));
201251881Speter
202299742Sdim  if (vacuum_pristines)
203299742Sdim    SVN_ERR(svn_wc__db_vacuum(db, local_abspath, scratch_pool));
204251881Speter
205251881Speter  /* We're done with this DB, so proactively close it.  */
206299742Sdim  if (break_locks)
207299742Sdim    SVN_ERR(svn_wc__db_close(db));
208251881Speter
209251881Speter  return SVN_NO_ERROR;
210251881Speter}
211