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