1251881Speter/*
2251881Speter * adm_files.c: helper routines for handling files & dirs in the
3251881Speter *              working copy administrative area (creating,
4251881Speter *              deleting, opening, and closing).  This is the only
5251881Speter *              code that actually knows where administrative
6251881Speter *              information is kept.
7251881Speter *
8251881Speter * ====================================================================
9251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
10251881Speter *    or more contributor license agreements.  See the NOTICE file
11251881Speter *    distributed with this work for additional information
12251881Speter *    regarding copyright ownership.  The ASF licenses this file
13251881Speter *    to you under the Apache License, Version 2.0 (the
14251881Speter *    "License"); you may not use this file except in compliance
15251881Speter *    with the License.  You may obtain a copy of the License at
16251881Speter *
17251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
18251881Speter *
19251881Speter *    Unless required by applicable law or agreed to in writing,
20251881Speter *    software distributed under the License is distributed on an
21251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22251881Speter *    KIND, either express or implied.  See the License for the
23251881Speter *    specific language governing permissions and limitations
24251881Speter *    under the License.
25251881Speter * ====================================================================
26251881Speter */
27251881Speter
28251881Speter
29251881Speter
30251881Speter#include <stdarg.h>
31251881Speter#include <apr_pools.h>
32251881Speter#include <apr_file_io.h>
33251881Speter#include <apr_strings.h>
34251881Speter
35251881Speter#include "svn_types.h"
36251881Speter#include "svn_error.h"
37251881Speter#include "svn_io.h"
38251881Speter#include "svn_dirent_uri.h"
39251881Speter#include "svn_path.h"
40251881Speter#include "svn_hash.h"
41251881Speter
42251881Speter#include "wc.h"
43251881Speter#include "adm_files.h"
44251881Speter#include "entries.h"
45251881Speter#include "lock.h"
46251881Speter
47251881Speter#include "svn_private_config.h"
48251881Speter#include "private/svn_wc_private.h"
49251881Speter
50251881Speter
51251881Speter/*** File names in the adm area. ***/
52251881Speter
53251881Speter/* The default name of the WC admin directory. This name is always
54251881Speter   checked by svn_wc_is_adm_dir. */
55251881Speterstatic const char default_adm_dir_name[] = ".svn";
56251881Speter
57251881Speter/* The name that is actually used for the WC admin directory.  The
58251881Speter   commonest case where this won't be the default is in Windows
59251881Speter   ASP.NET development environments, which used to choke on ".svn". */
60251881Speterstatic const char *adm_dir_name = default_adm_dir_name;
61251881Speter
62251881Speter
63251881Spetersvn_boolean_t
64251881Spetersvn_wc_is_adm_dir(const char *name, apr_pool_t *pool)
65251881Speter{
66251881Speter  return (0 == strcmp(name, adm_dir_name)
67251881Speter          || 0 == strcmp(name, default_adm_dir_name));
68251881Speter}
69251881Speter
70251881Speter
71251881Speterconst char *
72251881Spetersvn_wc_get_adm_dir(apr_pool_t *pool)
73251881Speter{
74251881Speter  return adm_dir_name;
75251881Speter}
76251881Speter
77251881Speter
78251881Spetersvn_error_t *
79251881Spetersvn_wc_set_adm_dir(const char *name, apr_pool_t *pool)
80251881Speter{
81251881Speter  /* This is the canonical list of administrative directory names.
82251881Speter
83251881Speter     FIXME:
84251881Speter     An identical list is used in
85251881Speter       libsvn_subr/opt.c:svn_opt__args_to_target_array(),
86251881Speter     but that function can't use this list, because that use would
87251881Speter     create a circular dependency between libsvn_wc and libsvn_subr.
88251881Speter     Make sure changes to the lists are always synchronized! */
89251881Speter  static const char *valid_dir_names[] = {
90251881Speter    default_adm_dir_name,
91251881Speter    "_svn",
92251881Speter    NULL
93251881Speter  };
94251881Speter
95251881Speter  const char **dir_name;
96251881Speter  for (dir_name = valid_dir_names; *dir_name; ++dir_name)
97251881Speter    if (0 == strcmp(name, *dir_name))
98251881Speter      {
99251881Speter        /* Use the pointer to the statically allocated string
100251881Speter           constant, to avoid potential pool lifetime issues. */
101251881Speter        adm_dir_name = *dir_name;
102251881Speter        return SVN_NO_ERROR;
103251881Speter      }
104251881Speter  return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL,
105251881Speter                           _("'%s' is not a valid administrative "
106251881Speter                             "directory name"),
107251881Speter                           svn_dirent_local_style(name, pool));
108251881Speter}
109251881Speter
110251881Speter
111251881Speterconst char *
112251881Spetersvn_wc__adm_child(const char *path,
113251881Speter                  const char *child,
114251881Speter                  apr_pool_t *result_pool)
115251881Speter{
116251881Speter  return svn_dirent_join_many(result_pool,
117251881Speter                              path,
118251881Speter                              adm_dir_name,
119251881Speter                              child,
120289180Speter                              SVN_VA_NULL);
121251881Speter}
122251881Speter
123251881Speter
124251881Spetersvn_boolean_t
125251881Spetersvn_wc__adm_area_exists(const char *adm_abspath,
126251881Speter                        apr_pool_t *pool)
127251881Speter{
128251881Speter  const char *path = svn_wc__adm_child(adm_abspath, NULL, pool);
129251881Speter  svn_node_kind_t kind;
130251881Speter  svn_error_t *err;
131251881Speter
132251881Speter  err = svn_io_check_path(path, &kind, pool);
133251881Speter  if (err)
134251881Speter    {
135251881Speter      svn_error_clear(err);
136251881Speter      /* Return early, since kind is undefined in this case. */
137251881Speter      return FALSE;
138251881Speter    }
139251881Speter
140251881Speter  return kind != svn_node_none;
141251881Speter}
142251881Speter
143251881Speter
144251881Speter
145251881Speter/*** Making and using files in the adm area. ***/
146251881Speter
147251881Speter
148251881Speter/* */
149251881Speterstatic svn_error_t *
150251881Spetermake_adm_subdir(const char *path,
151251881Speter                const char *subdir,
152251881Speter                apr_pool_t *pool)
153251881Speter{
154251881Speter  const char *fullpath;
155251881Speter
156251881Speter  fullpath = svn_wc__adm_child(path, subdir, pool);
157251881Speter
158251881Speter  return svn_io_dir_make(fullpath, APR_OS_DEFAULT, pool);
159251881Speter}
160251881Speter
161251881Speter
162251881Speter
163251881Speter/*** Syncing files in the adm area. ***/
164251881Speter
165251881Speter
166251881Spetersvn_error_t *
167251881Spetersvn_wc__text_base_path_to_read(const char **result_abspath,
168251881Speter                               svn_wc__db_t *db,
169251881Speter                               const char *local_abspath,
170251881Speter                               apr_pool_t *result_pool,
171251881Speter                               apr_pool_t *scratch_pool)
172251881Speter{
173251881Speter  svn_wc__db_status_t status;
174251881Speter  svn_node_kind_t kind;
175251881Speter  const svn_checksum_t *checksum;
176251881Speter
177251881Speter  SVN_ERR(svn_wc__db_read_pristine_info(&status, &kind, NULL, NULL, NULL, NULL,
178251881Speter                                        &checksum, NULL, NULL, NULL,
179251881Speter                                        db, local_abspath,
180251881Speter                                        scratch_pool, scratch_pool));
181251881Speter
182251881Speter  /* Sanity */
183251881Speter  if (kind != svn_node_file)
184251881Speter    return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
185251881Speter                             _("Can only get the pristine contents of files; "
186251881Speter                               "'%s' is not a file"),
187251881Speter                             svn_dirent_local_style(local_abspath,
188251881Speter                                                    scratch_pool));
189251881Speter
190251881Speter  if (status == svn_wc__db_status_not_present)
191251881Speter    /* We know that the delete of this node has been committed.
192251881Speter       This should be the same as if called on an unknown path. */
193251881Speter    return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
194251881Speter                             _("Cannot get the pristine contents of '%s' "
195251881Speter                               "because its delete is already committed"),
196251881Speter                             svn_dirent_local_style(local_abspath,
197251881Speter                                                    scratch_pool));
198251881Speter  else if (status == svn_wc__db_status_server_excluded
199251881Speter      || status == svn_wc__db_status_excluded
200251881Speter      || status == svn_wc__db_status_incomplete)
201251881Speter    return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
202251881Speter                             _("Cannot get the pristine contents of '%s' "
203251881Speter                               "because it has an unexpected status"),
204251881Speter                             svn_dirent_local_style(local_abspath,
205251881Speter                                                    scratch_pool));
206251881Speter
207251881Speter  if (checksum == NULL)
208251881Speter    return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
209251881Speter                             _("Node '%s' has no pristine text"),
210251881Speter                             svn_dirent_local_style(local_abspath,
211251881Speter                                                    scratch_pool));
212251881Speter  SVN_ERR(svn_wc__db_pristine_get_path(result_abspath, db, local_abspath,
213251881Speter                                       checksum,
214251881Speter                                       result_pool, scratch_pool));
215251881Speter  return SVN_NO_ERROR;
216251881Speter}
217251881Speter
218251881Spetersvn_error_t *
219251881Spetersvn_wc__get_pristine_contents(svn_stream_t **contents,
220251881Speter                              svn_filesize_t *size,
221251881Speter                              svn_wc__db_t *db,
222251881Speter                              const char *local_abspath,
223251881Speter                              apr_pool_t *result_pool,
224251881Speter                              apr_pool_t *scratch_pool)
225251881Speter{
226251881Speter  svn_wc__db_status_t status;
227251881Speter  svn_node_kind_t kind;
228251881Speter  const svn_checksum_t *sha1_checksum;
229251881Speter
230251881Speter  if (size)
231251881Speter    *size = SVN_INVALID_FILESIZE;
232251881Speter
233251881Speter  SVN_ERR(svn_wc__db_read_pristine_info(&status, &kind, NULL, NULL, NULL, NULL,
234251881Speter                                        &sha1_checksum, NULL, NULL, NULL,
235251881Speter                                        db, local_abspath,
236251881Speter                                        scratch_pool, scratch_pool));
237251881Speter
238251881Speter  /* Sanity */
239251881Speter  if (kind != svn_node_file)
240251881Speter    return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
241251881Speter                             _("Can only get the pristine contents of files; "
242251881Speter                               "'%s' is not a file"),
243251881Speter                             svn_dirent_local_style(local_abspath,
244251881Speter                                                    scratch_pool));
245251881Speter
246251881Speter  if (status == svn_wc__db_status_added && !sha1_checksum)
247251881Speter    {
248251881Speter      /* Simply added. The pristine base does not exist. */
249251881Speter      *contents = NULL;
250251881Speter      return SVN_NO_ERROR;
251251881Speter    }
252251881Speter  else if (status == svn_wc__db_status_not_present)
253251881Speter    /* We know that the delete of this node has been committed.
254251881Speter       This should be the same as if called on an unknown path. */
255251881Speter    return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
256251881Speter                             _("Cannot get the pristine contents of '%s' "
257251881Speter                               "because its delete is already committed"),
258251881Speter                             svn_dirent_local_style(local_abspath,
259251881Speter                                                    scratch_pool));
260251881Speter  else if (status == svn_wc__db_status_server_excluded
261251881Speter      || status == svn_wc__db_status_excluded
262251881Speter      || status == svn_wc__db_status_incomplete)
263251881Speter    return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
264251881Speter                             _("Cannot get the pristine contents of '%s' "
265251881Speter                               "because it has an unexpected status"),
266251881Speter                             svn_dirent_local_style(local_abspath,
267251881Speter                                                    scratch_pool));
268251881Speter  if (sha1_checksum)
269251881Speter    SVN_ERR(svn_wc__db_pristine_read(contents, size, db, local_abspath,
270251881Speter                                     sha1_checksum,
271251881Speter                                     result_pool, scratch_pool));
272251881Speter  else
273251881Speter    *contents = NULL;
274251881Speter
275251881Speter  return SVN_NO_ERROR;
276251881Speter}
277251881Speter
278251881Speter
279251881Speter/*** Opening and closing files in the adm area. ***/
280251881Speter
281251881Spetersvn_error_t *
282251881Spetersvn_wc__open_adm_stream(svn_stream_t **stream,
283251881Speter                        const char *dir_abspath,
284251881Speter                        const char *fname,
285251881Speter                        apr_pool_t *result_pool,
286251881Speter                        apr_pool_t *scratch_pool)
287251881Speter{
288251881Speter  const char *local_abspath;
289251881Speter
290251881Speter  SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
291251881Speter
292251881Speter  local_abspath = svn_wc__adm_child(dir_abspath, fname, scratch_pool);
293251881Speter  return svn_error_trace(svn_stream_open_readonly(stream, local_abspath,
294251881Speter                                                  result_pool, scratch_pool));
295251881Speter}
296251881Speter
297251881Speter
298251881Speter/*** Checking for and creating administrative subdirs. ***/
299251881Speter
300251881Speter
301251881Speter/* */
302251881Speterstatic svn_error_t *
303251881Speterinit_adm_tmp_area(const char *path, apr_pool_t *pool)
304251881Speter{
305251881Speter  /* SVN_WC__ADM_TMP */
306251881Speter  SVN_ERR(make_adm_subdir(path, SVN_WC__ADM_TMP, pool));
307251881Speter
308251881Speter  return SVN_NO_ERROR;
309251881Speter}
310251881Speter
311251881Speter
312251881Speter/* Set up a new adm area for PATH, with REPOS_* as the repos info, and
313251881Speter   INITIAL_REV as the starting revision.  The entries file starts out
314251881Speter   marked as 'incomplete.  The adm area starts out locked; remember to
315251881Speter   unlock it when done. */
316251881Speterstatic svn_error_t *
317251881Speterinit_adm(svn_wc__db_t *db,
318251881Speter         const char *local_abspath,
319251881Speter         const char *repos_relpath,
320251881Speter         const char *repos_root_url,
321251881Speter         const char *repos_uuid,
322251881Speter         svn_revnum_t initial_rev,
323251881Speter         svn_depth_t depth,
324251881Speter         apr_pool_t *pool)
325251881Speter{
326251881Speter  /* First, make an empty administrative area. */
327251881Speter  SVN_ERR(svn_io_dir_make_hidden(svn_wc__adm_child(local_abspath, NULL, pool),
328251881Speter                                 APR_OS_DEFAULT, pool));
329251881Speter
330251881Speter  /** Make subdirectories. ***/
331251881Speter
332251881Speter  /* SVN_WC__ADM_PRISTINE */
333251881Speter  SVN_ERR(make_adm_subdir(local_abspath, SVN_WC__ADM_PRISTINE, pool));
334251881Speter
335251881Speter  /* ### want to add another directory? do a format bump to ensure that
336251881Speter     ### all existing working copies get the new directories. or maybe
337251881Speter     ### create-on-demand (more expensive)  */
338251881Speter
339251881Speter  /** Init the tmp area. ***/
340251881Speter  SVN_ERR(init_adm_tmp_area(local_abspath, pool));
341251881Speter
342251881Speter  /* Create the SDB. */
343251881Speter  SVN_ERR(svn_wc__db_init(db, local_abspath,
344251881Speter                          repos_relpath, repos_root_url, repos_uuid,
345251881Speter                          initial_rev, depth,
346251881Speter                          pool));
347251881Speter
348251881Speter  /* Stamp ENTRIES and FORMAT files for old clients.  */
349251881Speter  SVN_ERR(svn_io_file_create(svn_wc__adm_child(local_abspath,
350251881Speter                                               SVN_WC__ADM_ENTRIES,
351251881Speter                                               pool),
352251881Speter                             SVN_WC__NON_ENTRIES_STRING,
353251881Speter                             pool));
354251881Speter  SVN_ERR(svn_io_file_create(svn_wc__adm_child(local_abspath,
355251881Speter                                               SVN_WC__ADM_FORMAT,
356251881Speter                                               pool),
357251881Speter                             SVN_WC__NON_ENTRIES_STRING,
358251881Speter                             pool));
359251881Speter
360251881Speter  return SVN_NO_ERROR;
361251881Speter}
362251881Speter
363251881Spetersvn_error_t *
364251881Spetersvn_wc__internal_ensure_adm(svn_wc__db_t *db,
365251881Speter                            const char *local_abspath,
366251881Speter                            const char *url,
367251881Speter                            const char *repos_root_url,
368251881Speter                            const char *repos_uuid,
369251881Speter                            svn_revnum_t revision,
370251881Speter                            svn_depth_t depth,
371251881Speter                            apr_pool_t *scratch_pool)
372251881Speter{
373251881Speter  int format;
374251881Speter  const char *original_repos_relpath;
375251881Speter  const char *original_root_url;
376251881Speter  svn_boolean_t is_op_root;
377251881Speter  const char *repos_relpath = svn_uri_skip_ancestor(repos_root_url, url,
378251881Speter                                                    scratch_pool);
379251881Speter  svn_wc__db_status_t status;
380251881Speter  const char *db_repos_relpath, *db_repos_root_url, *db_repos_uuid;
381251881Speter  svn_revnum_t db_revision;
382251881Speter
383251881Speter  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
384251881Speter  SVN_ERR_ASSERT(url != NULL);
385251881Speter  SVN_ERR_ASSERT(repos_root_url != NULL);
386251881Speter  SVN_ERR_ASSERT(repos_uuid != NULL);
387251881Speter  SVN_ERR_ASSERT(repos_relpath != NULL);
388251881Speter
389251881Speter  SVN_ERR(svn_wc__internal_check_wc(&format, db, local_abspath, TRUE,
390251881Speter                                    scratch_pool));
391251881Speter
392251881Speter  /* Early out: we know we're not dealing with an existing wc, so
393251881Speter     just create one. */
394251881Speter  if (format == 0)
395251881Speter    return svn_error_trace(init_adm(db, local_abspath,
396251881Speter                                    repos_relpath, repos_root_url, repos_uuid,
397251881Speter                                    revision, depth, scratch_pool));
398251881Speter
399251881Speter  SVN_ERR(svn_wc__db_read_info(&status, NULL,
400251881Speter                               &db_revision, &db_repos_relpath,
401251881Speter                               &db_repos_root_url, &db_repos_uuid,
402251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL,
403251881Speter                               &original_repos_relpath, &original_root_url,
404251881Speter                               NULL, NULL, NULL, NULL, NULL, NULL,
405251881Speter                               NULL, &is_op_root, NULL, NULL,
406251881Speter                               NULL, NULL, NULL,
407251881Speter                               db, local_abspath, scratch_pool, scratch_pool));
408251881Speter
409251881Speter  /* When the directory exists and is scheduled for deletion or is not-present
410251881Speter   * do not check the revision or the URL.  The revision can be any
411251881Speter   * arbitrary revision and the URL may differ if the add is
412251881Speter   * being driven from a merge which will have a different URL. */
413251881Speter  if (status != svn_wc__db_status_deleted
414251881Speter      && status != svn_wc__db_status_not_present)
415251881Speter    {
416251881Speter      /* ### Should we match copyfrom_revision? */
417251881Speter      if (db_revision != revision)
418251881Speter        return
419251881Speter          svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
420251881Speter                            _("Revision %ld doesn't match existing "
421251881Speter                              "revision %ld in '%s'"),
422251881Speter                            revision, db_revision, local_abspath);
423251881Speter
424251881Speter      if (!db_repos_root_url)
425251881Speter        {
426251881Speter          if (status == svn_wc__db_status_added)
427251881Speter            SVN_ERR(svn_wc__db_scan_addition(NULL, NULL,
428251881Speter                                             &db_repos_relpath,
429251881Speter                                             &db_repos_root_url,
430251881Speter                                             &db_repos_uuid,
431251881Speter                                             NULL, NULL, NULL, NULL,
432251881Speter                                             db, local_abspath,
433251881Speter                                             scratch_pool, scratch_pool));
434251881Speter          else
435289180Speter            SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL,
436289180Speter                                             &db_repos_relpath,
437289180Speter                                             &db_repos_root_url,
438289180Speter                                             &db_repos_uuid, NULL, NULL, NULL,
439289180Speter                                             NULL, NULL, NULL, NULL, NULL,
440289180Speter                                             NULL, NULL,
441289180Speter                                             db, local_abspath,
442289180Speter                                             scratch_pool, scratch_pool));
443251881Speter        }
444251881Speter
445251881Speter      /* The caller gives us a URL which should match the entry. However,
446251881Speter         some callers compensate for an old problem in entry->url and pass
447251881Speter         the copyfrom_url instead. See ^/notes/api-errata/1.7/wc002.txt. As
448251881Speter         a result, we allow the passed URL to match copyfrom_url if it
449251881Speter         does not match the entry's primary URL.  */
450251881Speter      if (strcmp(db_repos_uuid, repos_uuid)
451251881Speter          || strcmp(db_repos_root_url, repos_root_url)
452251881Speter          || !svn_relpath_skip_ancestor(db_repos_relpath, repos_relpath))
453251881Speter        {
454251881Speter          if (!is_op_root /* copy_from was set on op-roots only */
455251881Speter              || original_root_url == NULL
456251881Speter              || strcmp(original_root_url, repos_root_url)
457251881Speter              || strcmp(original_repos_relpath, repos_relpath))
458251881Speter            return
459251881Speter              svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
460251881Speter                                _("URL '%s' (uuid: '%s') doesn't match existing "
461251881Speter                                  "URL '%s' (uuid: '%s') in '%s'"),
462251881Speter                                url,
463251881Speter                                db_repos_uuid,
464251881Speter                                svn_path_url_add_component2(db_repos_root_url,
465251881Speter                                                            db_repos_relpath,
466251881Speter                                                            scratch_pool),
467251881Speter                                repos_uuid,
468251881Speter                                local_abspath);
469251881Speter        }
470251881Speter    }
471251881Speter
472251881Speter  return SVN_NO_ERROR;
473251881Speter}
474251881Speter
475251881Spetersvn_error_t *
476251881Spetersvn_wc_ensure_adm4(svn_wc_context_t *wc_ctx,
477251881Speter                   const char *local_abspath,
478251881Speter                   const char *url,
479251881Speter                   const char *repos_root_url,
480251881Speter                   const char *repos_uuid,
481251881Speter                   svn_revnum_t revision,
482251881Speter                   svn_depth_t depth,
483251881Speter                   apr_pool_t *scratch_pool)
484251881Speter{
485251881Speter  return svn_error_trace(
486251881Speter    svn_wc__internal_ensure_adm(wc_ctx->db, local_abspath, url, repos_root_url,
487251881Speter                                repos_uuid, revision, depth, scratch_pool));
488251881Speter}
489251881Speter
490251881Spetersvn_error_t *
491251881Spetersvn_wc__adm_destroy(svn_wc__db_t *db,
492251881Speter                    const char *dir_abspath,
493251881Speter                    svn_cancel_func_t cancel_func,
494251881Speter                    void *cancel_baton,
495251881Speter                    apr_pool_t *scratch_pool)
496251881Speter{
497251881Speter  svn_boolean_t is_wcroot;
498251881Speter
499251881Speter  SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
500251881Speter
501251881Speter  SVN_ERR(svn_wc__write_check(db, dir_abspath, scratch_pool));
502251881Speter
503251881Speter  SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, db, dir_abspath, scratch_pool));
504251881Speter
505251881Speter  /* Well, the coast is clear for blowing away the administrative
506251881Speter     directory, which also removes remaining locks */
507251881Speter
508251881Speter  /* Now close the DB, and we can delete the working copy */
509251881Speter  if (is_wcroot)
510251881Speter    {
511251881Speter      SVN_ERR(svn_wc__db_drop_root(db, dir_abspath, scratch_pool));
512251881Speter      SVN_ERR(svn_io_remove_dir2(svn_wc__adm_child(dir_abspath, NULL,
513251881Speter                                                   scratch_pool),
514251881Speter                                 FALSE,
515251881Speter                                 cancel_func, cancel_baton,
516251881Speter                                 scratch_pool));
517251881Speter    }
518251881Speter
519251881Speter  return SVN_NO_ERROR;
520251881Speter}
521251881Speter
522251881Speter
523251881Spetersvn_error_t *
524251881Spetersvn_wc__adm_cleanup_tmp_area(svn_wc__db_t *db,
525251881Speter                             const char *adm_abspath,
526251881Speter                             apr_pool_t *scratch_pool)
527251881Speter{
528251881Speter  const char *tmp_path;
529251881Speter
530251881Speter  SVN_ERR_ASSERT(svn_dirent_is_absolute(adm_abspath));
531251881Speter
532251881Speter  SVN_ERR(svn_wc__write_check(db, adm_abspath, scratch_pool));
533251881Speter
534251881Speter  /* Get the path to the tmp area, and blow it away. */
535251881Speter  tmp_path = svn_wc__adm_child(adm_abspath, SVN_WC__ADM_TMP, scratch_pool);
536251881Speter
537251881Speter  SVN_ERR(svn_io_remove_dir2(tmp_path, TRUE, NULL, NULL, scratch_pool));
538251881Speter
539251881Speter  /* Now, rebuild the tmp area. */
540251881Speter  return svn_error_trace(init_adm_tmp_area(adm_abspath, scratch_pool));
541251881Speter}
542251881Speter
543251881Speter
544251881Spetersvn_error_t *
545251881Spetersvn_wc__get_tmpdir(const char **tmpdir_abspath,
546251881Speter                   svn_wc_context_t *wc_ctx,
547251881Speter                   const char *wri_abspath,
548251881Speter                   apr_pool_t *result_pool,
549251881Speter                   apr_pool_t *scratch_pool)
550251881Speter{
551251881Speter  SVN_ERR(svn_wc__db_temp_wcroot_tempdir(tmpdir_abspath,
552251881Speter                                         wc_ctx->db, wri_abspath,
553251881Speter                                         result_pool, scratch_pool));
554251881Speter  return SVN_NO_ERROR;
555251881Speter}
556