1251881Speter/* 2251881Speter * upgrade.c: routines for upgrading a working copy 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#include <apr_pools.h> 25251881Speter 26251881Speter#include "svn_types.h" 27251881Speter#include "svn_pools.h" 28251881Speter#include "svn_dirent_uri.h" 29251881Speter#include "svn_path.h" 30251881Speter#include "svn_hash.h" 31251881Speter 32251881Speter#include "wc.h" 33251881Speter#include "adm_files.h" 34251881Speter#include "conflicts.h" 35251881Speter#include "entries.h" 36251881Speter#include "wc_db.h" 37251881Speter#include "tree_conflicts.h" 38251881Speter#include "wc-queries.h" /* for STMT_* */ 39251881Speter#include "workqueue.h" 40289180Speter#include "token-map.h" 41251881Speter 42251881Speter#include "svn_private_config.h" 43251881Speter#include "private/svn_wc_private.h" 44251881Speter#include "private/svn_sqlite.h" 45251881Speter#include "private/svn_token.h" 46251881Speter 47251881Speter/* WC-1.0 administrative area extensions */ 48251881Speter#define SVN_WC__BASE_EXT ".svn-base" /* for text and prop bases */ 49251881Speter#define SVN_WC__WORK_EXT ".svn-work" /* for working propfiles */ 50251881Speter#define SVN_WC__REVERT_EXT ".svn-revert" /* for reverting a replaced 51251881Speter file */ 52251881Speter 53251881Speter/* Old locations for storing "wcprops" (aka "dav cache"). */ 54251881Speter#define WCPROPS_SUBDIR_FOR_FILES "wcprops" 55251881Speter#define WCPROPS_FNAME_FOR_DIR "dir-wcprops" 56251881Speter#define WCPROPS_ALL_DATA "all-wcprops" 57251881Speter 58251881Speter/* Old property locations. */ 59251881Speter#define PROPS_SUBDIR "props" 60251881Speter#define PROP_BASE_SUBDIR "prop-base" 61251881Speter#define PROP_BASE_FOR_DIR "dir-prop-base" 62251881Speter#define PROP_REVERT_FOR_DIR "dir-prop-revert" 63251881Speter#define PROP_WORKING_FOR_DIR "dir-props" 64251881Speter 65251881Speter/* Old textbase location. */ 66251881Speter#define TEXT_BASE_SUBDIR "text-base" 67251881Speter 68251881Speter#define TEMP_DIR "tmp" 69251881Speter 70251881Speter/* Old data files that we no longer need/use. */ 71251881Speter#define ADM_README "README.txt" 72251881Speter#define ADM_EMPTY_FILE "empty-file" 73251881Speter#define ADM_LOG "log" 74251881Speter#define ADM_LOCK "lock" 75251881Speter 76251881Speter/* New pristine location */ 77251881Speter#define PRISTINE_STORAGE_RELPATH "pristine" 78251881Speter#define PRISTINE_STORAGE_EXT ".svn-base" 79251881Speter/* Number of characters in a pristine file basename, in WC format <= 28. */ 80251881Speter#define PRISTINE_BASENAME_OLD_LEN 40 81251881Speter#define SDB_FILE "wc.db" 82251881Speter 83251881Speter 84251881Speter/* Read the properties from the file at PROPFILE_ABSPATH, returning them 85251881Speter as a hash in *PROPS. If the propfile is NOT present, then NULL will 86251881Speter be returned in *PROPS. */ 87251881Speterstatic svn_error_t * 88251881Speterread_propfile(apr_hash_t **props, 89251881Speter const char *propfile_abspath, 90251881Speter apr_pool_t *result_pool, 91251881Speter apr_pool_t *scratch_pool) 92251881Speter{ 93251881Speter svn_error_t *err; 94251881Speter svn_stream_t *stream; 95251881Speter apr_finfo_t finfo; 96251881Speter 97251881Speter err = svn_io_stat(&finfo, propfile_abspath, APR_FINFO_SIZE, scratch_pool); 98251881Speter 99251881Speter if (err 100251881Speter && (APR_STATUS_IS_ENOENT(err->apr_err) 101251881Speter || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err))) 102251881Speter { 103251881Speter svn_error_clear(err); 104251881Speter 105251881Speter /* The propfile was not there. Signal with a NULL. */ 106251881Speter *props = NULL; 107251881Speter return SVN_NO_ERROR; 108251881Speter } 109251881Speter else 110251881Speter SVN_ERR(err); 111251881Speter 112251881Speter /* A 0-bytes file signals an empty property list. 113251881Speter (mostly used for revert-props) */ 114251881Speter if (finfo.size == 0) 115251881Speter { 116251881Speter *props = apr_hash_make(result_pool); 117251881Speter return SVN_NO_ERROR; 118251881Speter } 119251881Speter 120251881Speter SVN_ERR(svn_stream_open_readonly(&stream, propfile_abspath, 121251881Speter scratch_pool, scratch_pool)); 122251881Speter 123251881Speter /* ### does this function need to be smarter? will we see zero-length 124251881Speter ### files? see props.c::load_props(). there may be more work here. 125251881Speter ### need a historic analysis of 1.x property storage. what will we 126251881Speter ### actually run into? */ 127251881Speter 128251881Speter /* ### loggy_write_properties() and immediate_install_props() write 129251881Speter ### zero-length files for "no props", so we should be a bit smarter 130251881Speter ### in here. */ 131251881Speter 132251881Speter /* ### should we be forgiving in here? I say "no". if we can't be sure, 133251881Speter ### then we could effectively corrupt the local working copy. */ 134251881Speter 135251881Speter *props = apr_hash_make(result_pool); 136251881Speter SVN_ERR(svn_hash_read2(*props, stream, SVN_HASH_TERMINATOR, result_pool)); 137251881Speter 138251881Speter return svn_error_trace(svn_stream_close(stream)); 139251881Speter} 140251881Speter 141251881Speter 142251881Speter/* Read one proplist (allocated from RESULT_POOL) from STREAM, and place it 143251881Speter into ALL_WCPROPS at NAME. */ 144251881Speterstatic svn_error_t * 145251881Speterread_one_proplist(apr_hash_t *all_wcprops, 146251881Speter const char *name, 147251881Speter svn_stream_t *stream, 148251881Speter apr_pool_t *result_pool, 149251881Speter apr_pool_t *scratch_pool) 150251881Speter{ 151251881Speter apr_hash_t *proplist; 152251881Speter 153251881Speter proplist = apr_hash_make(result_pool); 154251881Speter SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, result_pool)); 155251881Speter svn_hash_sets(all_wcprops, name, proplist); 156251881Speter 157251881Speter return SVN_NO_ERROR; 158251881Speter} 159251881Speter 160251881Speter 161251881Speter/* Read the wcprops from all the files in the admin area of DIR_ABSPATH, 162251881Speter returning them in *ALL_WCPROPS. Results are allocated in RESULT_POOL, 163251881Speter and temporary allocations are performed in SCRATCH_POOL. */ 164251881Speterstatic svn_error_t * 165251881Speterread_many_wcprops(apr_hash_t **all_wcprops, 166251881Speter const char *dir_abspath, 167251881Speter apr_pool_t *result_pool, 168251881Speter apr_pool_t *scratch_pool) 169251881Speter{ 170251881Speter const char *propfile_abspath; 171251881Speter apr_hash_t *wcprops; 172251881Speter apr_hash_t *dirents; 173251881Speter const char *props_dir_abspath; 174251881Speter apr_pool_t *iterpool = svn_pool_create(scratch_pool); 175251881Speter apr_hash_index_t *hi; 176251881Speter 177251881Speter *all_wcprops = apr_hash_make(result_pool); 178251881Speter 179251881Speter /* First, look at dir-wcprops. */ 180251881Speter propfile_abspath = svn_wc__adm_child(dir_abspath, WCPROPS_FNAME_FOR_DIR, 181251881Speter scratch_pool); 182251881Speter SVN_ERR(read_propfile(&wcprops, propfile_abspath, result_pool, iterpool)); 183251881Speter if (wcprops != NULL) 184251881Speter svn_hash_sets(*all_wcprops, SVN_WC_ENTRY_THIS_DIR, wcprops); 185251881Speter 186251881Speter props_dir_abspath = svn_wc__adm_child(dir_abspath, WCPROPS_SUBDIR_FOR_FILES, 187251881Speter scratch_pool); 188251881Speter 189251881Speter /* Now walk the wcprops directory. */ 190251881Speter SVN_ERR(svn_io_get_dirents3(&dirents, props_dir_abspath, TRUE, 191251881Speter scratch_pool, scratch_pool)); 192251881Speter 193251881Speter for (hi = apr_hash_first(scratch_pool, dirents); 194251881Speter hi; 195251881Speter hi = apr_hash_next(hi)) 196251881Speter { 197289180Speter const char *name = apr_hash_this_key(hi); 198251881Speter 199251881Speter svn_pool_clear(iterpool); 200251881Speter 201251881Speter propfile_abspath = svn_dirent_join(props_dir_abspath, name, iterpool); 202251881Speter 203251881Speter SVN_ERR(read_propfile(&wcprops, propfile_abspath, 204251881Speter result_pool, iterpool)); 205251881Speter SVN_ERR_ASSERT(wcprops != NULL); 206251881Speter svn_hash_sets(*all_wcprops, apr_pstrdup(result_pool, name), wcprops); 207251881Speter } 208251881Speter 209251881Speter svn_pool_destroy(iterpool); 210251881Speter return SVN_NO_ERROR; 211251881Speter} 212251881Speter 213251881Speter 214251881Speter/* For wcprops stored in a single file in this working copy, read that 215251881Speter file and return it in *ALL_WCPROPS, allocated in RESULT_POOL. Use 216251881Speter SCRATCH_POOL for temporary allocations. */ 217251881Speterstatic svn_error_t * 218251881Speterread_wcprops(apr_hash_t **all_wcprops, 219251881Speter const char *dir_abspath, 220251881Speter apr_pool_t *result_pool, 221251881Speter apr_pool_t *scratch_pool) 222251881Speter{ 223251881Speter svn_stream_t *stream; 224251881Speter svn_error_t *err; 225251881Speter 226251881Speter *all_wcprops = apr_hash_make(result_pool); 227251881Speter 228251881Speter err = svn_wc__open_adm_stream(&stream, dir_abspath, 229251881Speter WCPROPS_ALL_DATA, 230251881Speter scratch_pool, scratch_pool); 231251881Speter 232251881Speter /* A non-existent file means there are no props. */ 233251881Speter if (err && APR_STATUS_IS_ENOENT(err->apr_err)) 234251881Speter { 235251881Speter svn_error_clear(err); 236251881Speter return SVN_NO_ERROR; 237251881Speter } 238251881Speter SVN_ERR(err); 239251881Speter 240251881Speter /* Read the proplist for THIS_DIR. */ 241251881Speter SVN_ERR(read_one_proplist(*all_wcprops, SVN_WC_ENTRY_THIS_DIR, stream, 242251881Speter result_pool, scratch_pool)); 243251881Speter 244251881Speter /* And now, the children. */ 245251881Speter while (1729) 246251881Speter { 247251881Speter svn_stringbuf_t *line; 248251881Speter svn_boolean_t eof; 249251881Speter 250251881Speter SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, result_pool)); 251251881Speter if (eof) 252251881Speter { 253251881Speter if (line->len > 0) 254251881Speter return svn_error_createf 255251881Speter (SVN_ERR_WC_CORRUPT, NULL, 256251881Speter _("Missing end of line in wcprops file for '%s'"), 257251881Speter svn_dirent_local_style(dir_abspath, scratch_pool)); 258251881Speter break; 259251881Speter } 260251881Speter SVN_ERR(read_one_proplist(*all_wcprops, line->data, stream, 261251881Speter result_pool, scratch_pool)); 262251881Speter } 263251881Speter 264251881Speter return svn_error_trace(svn_stream_close(stream)); 265251881Speter} 266251881Speter 267251881Speter/* Return in CHILDREN, the list of all 1.6 versioned subdirectories 268251881Speter which also exist on disk as directories. 269251881Speter 270251881Speter If DELETE_DIR is not NULL set *DELETE_DIR to TRUE if the directory 271251881Speter should be deleted after migrating to WC-NG, otherwise to FALSE. 272251881Speter 273251881Speter If SKIP_MISSING is TRUE, don't add missing or obstructed subdirectories 274251881Speter to the list of children. 275251881Speter */ 276251881Speterstatic svn_error_t * 277251881Speterget_versioned_subdirs(apr_array_header_t **children, 278251881Speter svn_boolean_t *delete_dir, 279251881Speter const char *dir_abspath, 280251881Speter svn_boolean_t skip_missing, 281251881Speter apr_pool_t *result_pool, 282251881Speter apr_pool_t *scratch_pool) 283251881Speter{ 284251881Speter apr_pool_t *iterpool = svn_pool_create(scratch_pool); 285251881Speter apr_hash_t *entries; 286251881Speter apr_hash_index_t *hi; 287251881Speter svn_wc_entry_t *this_dir = NULL; 288251881Speter 289251881Speter *children = apr_array_make(result_pool, 10, sizeof(const char *)); 290251881Speter 291251881Speter SVN_ERR(svn_wc__read_entries_old(&entries, dir_abspath, 292251881Speter scratch_pool, iterpool)); 293251881Speter for (hi = apr_hash_first(scratch_pool, entries); 294251881Speter hi; 295251881Speter hi = apr_hash_next(hi)) 296251881Speter { 297289180Speter const char *name = apr_hash_this_key(hi); 298289180Speter const svn_wc_entry_t *entry = apr_hash_this_val(hi); 299251881Speter const char *child_abspath; 300251881Speter svn_boolean_t hidden; 301251881Speter 302251881Speter /* skip "this dir" */ 303251881Speter if (*name == '\0') 304251881Speter { 305289180Speter this_dir = apr_hash_this_val(hi); 306251881Speter continue; 307251881Speter } 308251881Speter else if (entry->kind != svn_node_dir) 309251881Speter continue; 310251881Speter 311251881Speter svn_pool_clear(iterpool); 312251881Speter 313251881Speter /* If a directory is 'hidden' skip it as subdir */ 314251881Speter SVN_ERR(svn_wc__entry_is_hidden(&hidden, entry)); 315251881Speter if (hidden) 316251881Speter continue; 317251881Speter 318251881Speter child_abspath = svn_dirent_join(dir_abspath, name, scratch_pool); 319251881Speter 320251881Speter if (skip_missing) 321251881Speter { 322251881Speter svn_node_kind_t kind; 323251881Speter SVN_ERR(svn_io_check_path(child_abspath, &kind, scratch_pool)); 324251881Speter 325251881Speter if (kind != svn_node_dir) 326251881Speter continue; 327251881Speter } 328251881Speter 329251881Speter APR_ARRAY_PUSH(*children, const char *) = apr_pstrdup(result_pool, 330251881Speter child_abspath); 331251881Speter } 332251881Speter 333251881Speter svn_pool_destroy(iterpool); 334251881Speter 335251881Speter if (delete_dir != NULL) 336251881Speter { 337251881Speter *delete_dir = (this_dir != NULL) 338251881Speter && (this_dir->schedule == svn_wc_schedule_delete) 339251881Speter && ! this_dir->keep_local; 340251881Speter } 341251881Speter 342251881Speter return SVN_NO_ERROR; 343251881Speter} 344251881Speter 345251881Speter 346251881Speter/* Return in CHILDREN the names of all versioned *files* in SDB that 347251881Speter are children of PARENT_RELPATH. These files' existence on disk is 348251881Speter not tested. 349251881Speter 350251881Speter This set of children is intended for property upgrades. 351251881Speter Subdirectory's properties exist in the subdirs. 352251881Speter 353251881Speter Note that this uses just the SDB to locate children, which means 354251881Speter that the children must have been upgraded to wc-ng format. */ 355251881Speterstatic svn_error_t * 356251881Speterget_versioned_files(const apr_array_header_t **children, 357251881Speter const char *parent_relpath, 358251881Speter svn_sqlite__db_t *sdb, 359251881Speter apr_int64_t wc_id, 360251881Speter apr_pool_t *result_pool, 361251881Speter apr_pool_t *scratch_pool) 362251881Speter{ 363251881Speter svn_sqlite__stmt_t *stmt; 364251881Speter apr_array_header_t *child_names; 365251881Speter svn_boolean_t have_row; 366251881Speter 367251881Speter /* ### just select 'file' children. do we need 'symlink' in the future? */ 368251881Speter SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_ALL_FILES)); 369251881Speter SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, parent_relpath)); 370251881Speter 371251881Speter /* ### 10 is based on Subversion's average of 8.5 files per versioned 372251881Speter ### directory in its repository. maybe use a different value? or 373251881Speter ### count rows first? */ 374251881Speter child_names = apr_array_make(result_pool, 10, sizeof(const char *)); 375251881Speter 376251881Speter SVN_ERR(svn_sqlite__step(&have_row, stmt)); 377251881Speter while (have_row) 378251881Speter { 379251881Speter const char *local_relpath = svn_sqlite__column_text(stmt, 0, 380251881Speter result_pool); 381251881Speter 382251881Speter APR_ARRAY_PUSH(child_names, const char *) 383251881Speter = svn_relpath_basename(local_relpath, result_pool); 384251881Speter 385251881Speter SVN_ERR(svn_sqlite__step(&have_row, stmt)); 386251881Speter } 387251881Speter 388251881Speter *children = child_names; 389251881Speter 390251881Speter return svn_error_trace(svn_sqlite__reset(stmt)); 391251881Speter} 392251881Speter 393251881Speter 394251881Speter/* Return the path of the old-school administrative lock file 395251881Speter associated with LOCAL_DIR_ABSPATH, allocated from RESULT_POOL. */ 396251881Speterstatic const char * 397251881Speterbuild_lockfile_path(const char *local_dir_abspath, 398251881Speter apr_pool_t *result_pool) 399251881Speter{ 400251881Speter return svn_dirent_join_many(result_pool, 401251881Speter local_dir_abspath, 402251881Speter svn_wc_get_adm_dir(result_pool), 403251881Speter ADM_LOCK, 404289180Speter SVN_VA_NULL); 405251881Speter} 406251881Speter 407251881Speter 408251881Speter/* Create a physical lock file in the admin directory for ABSPATH. */ 409251881Speterstatic svn_error_t * 410251881Spetercreate_physical_lock(const char *abspath, apr_pool_t *scratch_pool) 411251881Speter{ 412251881Speter const char *lock_abspath = build_lockfile_path(abspath, scratch_pool); 413251881Speter svn_error_t *err; 414251881Speter apr_file_t *file; 415251881Speter 416251881Speter err = svn_io_file_open(&file, lock_abspath, 417251881Speter APR_WRITE | APR_CREATE | APR_EXCL, 418251881Speter APR_OS_DEFAULT, 419251881Speter scratch_pool); 420251881Speter 421251881Speter if (err && APR_STATUS_IS_EEXIST(err->apr_err)) 422251881Speter { 423251881Speter /* Congratulations, we just stole a physical lock from somebody */ 424251881Speter svn_error_clear(err); 425251881Speter return SVN_NO_ERROR; 426251881Speter } 427251881Speter 428251881Speter return svn_error_trace(err); 429251881Speter} 430251881Speter 431251881Speter 432251881Speter/* Wipe out all the obsolete files/dirs from the administrative area. */ 433251881Speterstatic void 434251881Speterwipe_obsolete_files(const char *wcroot_abspath, apr_pool_t *scratch_pool) 435251881Speter{ 436251881Speter /* Zap unused files. */ 437251881Speter svn_error_clear(svn_io_remove_file2( 438251881Speter svn_wc__adm_child(wcroot_abspath, 439251881Speter SVN_WC__ADM_FORMAT, 440251881Speter scratch_pool), 441251881Speter TRUE, scratch_pool)); 442251881Speter svn_error_clear(svn_io_remove_file2( 443251881Speter svn_wc__adm_child(wcroot_abspath, 444251881Speter SVN_WC__ADM_ENTRIES, 445251881Speter scratch_pool), 446251881Speter TRUE, scratch_pool)); 447251881Speter svn_error_clear(svn_io_remove_file2( 448251881Speter svn_wc__adm_child(wcroot_abspath, 449251881Speter ADM_EMPTY_FILE, 450251881Speter scratch_pool), 451251881Speter TRUE, scratch_pool)); 452251881Speter svn_error_clear(svn_io_remove_file2( 453251881Speter svn_wc__adm_child(wcroot_abspath, 454251881Speter ADM_README, 455251881Speter scratch_pool), 456251881Speter TRUE, scratch_pool)); 457251881Speter 458251881Speter /* For formats <= SVN_WC__WCPROPS_MANY_FILES_VERSION, we toss the wcprops 459251881Speter for the directory itself, and then all the wcprops for the files. */ 460251881Speter svn_error_clear(svn_io_remove_file2( 461251881Speter svn_wc__adm_child(wcroot_abspath, 462251881Speter WCPROPS_FNAME_FOR_DIR, 463251881Speter scratch_pool), 464251881Speter TRUE, scratch_pool)); 465251881Speter svn_error_clear(svn_io_remove_dir2( 466251881Speter svn_wc__adm_child(wcroot_abspath, 467251881Speter WCPROPS_SUBDIR_FOR_FILES, 468251881Speter scratch_pool), 469251881Speter FALSE, NULL, NULL, scratch_pool)); 470251881Speter 471251881Speter /* And for later formats, they are aggregated into one file. */ 472251881Speter svn_error_clear(svn_io_remove_file2( 473251881Speter svn_wc__adm_child(wcroot_abspath, 474251881Speter WCPROPS_ALL_DATA, 475251881Speter scratch_pool), 476251881Speter TRUE, scratch_pool)); 477251881Speter 478251881Speter /* Remove the old text-base directory and the old text-base files. */ 479251881Speter svn_error_clear(svn_io_remove_dir2( 480251881Speter svn_wc__adm_child(wcroot_abspath, 481251881Speter TEXT_BASE_SUBDIR, 482251881Speter scratch_pool), 483251881Speter FALSE, NULL, NULL, scratch_pool)); 484251881Speter 485251881Speter /* Remove the old properties files... whole directories at a time. */ 486251881Speter svn_error_clear(svn_io_remove_dir2( 487251881Speter svn_wc__adm_child(wcroot_abspath, 488251881Speter PROPS_SUBDIR, 489251881Speter scratch_pool), 490251881Speter FALSE, NULL, NULL, scratch_pool)); 491251881Speter svn_error_clear(svn_io_remove_dir2( 492251881Speter svn_wc__adm_child(wcroot_abspath, 493251881Speter PROP_BASE_SUBDIR, 494251881Speter scratch_pool), 495251881Speter FALSE, NULL, NULL, scratch_pool)); 496251881Speter svn_error_clear(svn_io_remove_file2( 497251881Speter svn_wc__adm_child(wcroot_abspath, 498251881Speter PROP_WORKING_FOR_DIR, 499251881Speter scratch_pool), 500251881Speter TRUE, scratch_pool)); 501251881Speter svn_error_clear(svn_io_remove_file2( 502251881Speter svn_wc__adm_child(wcroot_abspath, 503251881Speter PROP_BASE_FOR_DIR, 504251881Speter scratch_pool), 505251881Speter TRUE, scratch_pool)); 506251881Speter svn_error_clear(svn_io_remove_file2( 507251881Speter svn_wc__adm_child(wcroot_abspath, 508251881Speter PROP_REVERT_FOR_DIR, 509251881Speter scratch_pool), 510251881Speter TRUE, scratch_pool)); 511251881Speter 512251881Speter#if 0 513251881Speter /* ### this checks for a write-lock, and we are not (always) taking out 514251881Speter ### a write lock in all callers. */ 515251881Speter SVN_ERR(svn_wc__adm_cleanup_tmp_area(db, wcroot_abspath, iterpool)); 516251881Speter#endif 517251881Speter 518251881Speter /* Remove the old-style lock file LAST. */ 519251881Speter svn_error_clear(svn_io_remove_file2( 520251881Speter build_lockfile_path(wcroot_abspath, scratch_pool), 521251881Speter TRUE, scratch_pool)); 522251881Speter} 523251881Speter 524251881Spetersvn_error_t * 525251881Spetersvn_wc__wipe_postupgrade(const char *dir_abspath, 526251881Speter svn_boolean_t whole_admin, 527251881Speter svn_cancel_func_t cancel_func, 528251881Speter void *cancel_baton, 529251881Speter apr_pool_t *scratch_pool) 530251881Speter{ 531251881Speter apr_pool_t *iterpool = svn_pool_create(scratch_pool); 532251881Speter apr_array_header_t *subdirs; 533251881Speter svn_error_t *err; 534251881Speter svn_boolean_t delete_dir; 535251881Speter int i; 536251881Speter 537251881Speter if (cancel_func) 538362181Sdim SVN_ERR(cancel_func(cancel_baton)); 539251881Speter 540251881Speter err = get_versioned_subdirs(&subdirs, &delete_dir, dir_abspath, TRUE, 541251881Speter scratch_pool, iterpool); 542251881Speter if (err) 543251881Speter { 544251881Speter if (APR_STATUS_IS_ENOENT(err->apr_err)) 545251881Speter { 546251881Speter /* An unversioned dir is obstructing a versioned dir */ 547251881Speter svn_error_clear(err); 548251881Speter err = NULL; 549251881Speter } 550251881Speter svn_pool_destroy(iterpool); 551251881Speter return svn_error_trace(err); 552251881Speter } 553251881Speter for (i = 0; i < subdirs->nelts; ++i) 554251881Speter { 555251881Speter const char *child_abspath = APR_ARRAY_IDX(subdirs, i, const char *); 556251881Speter 557251881Speter svn_pool_clear(iterpool); 558251881Speter SVN_ERR(svn_wc__wipe_postupgrade(child_abspath, TRUE, 559251881Speter cancel_func, cancel_baton, iterpool)); 560251881Speter } 561251881Speter 562251881Speter /* ### Should we really be ignoring errors here? */ 563251881Speter if (whole_admin) 564251881Speter svn_error_clear(svn_io_remove_dir2(svn_wc__adm_child(dir_abspath, "", 565251881Speter iterpool), 566251881Speter TRUE, NULL, NULL, iterpool)); 567251881Speter else 568251881Speter wipe_obsolete_files(dir_abspath, scratch_pool); 569251881Speter 570251881Speter if (delete_dir) 571251881Speter { 572251881Speter /* If this was a WC-NG single database copy, this directory wouldn't 573251881Speter be here (unless it was deleted with --keep-local) 574251881Speter 575251881Speter If the directory is empty, we can just delete it; if not we 576251881Speter keep it. 577251881Speter */ 578251881Speter svn_error_clear(svn_io_dir_remove_nonrecursive(dir_abspath, iterpool)); 579251881Speter } 580251881Speter 581251881Speter svn_pool_destroy(iterpool); 582251881Speter 583251881Speter return SVN_NO_ERROR; 584251881Speter} 585251881Speter 586251881Speter/* Ensure that ENTRY has its REPOS and UUID fields set. These will be 587251881Speter used to establish the REPOSITORY row in the new database, and then 588251881Speter used within the upgraded entries as they are written into the database. 589251881Speter 590251881Speter If one or both are not available, then it attempts to retrieve this 591251881Speter information from REPOS_CACHE. And if that fails from REPOS_INFO_FUNC, 592251881Speter passing REPOS_INFO_BATON. 593251881Speter Returns a user understandable error using LOCAL_ABSPATH if the 594251881Speter information cannot be obtained. */ 595251881Speterstatic svn_error_t * 596251881Speterensure_repos_info(svn_wc_entry_t *entry, 597251881Speter const char *local_abspath, 598251881Speter svn_wc_upgrade_get_repos_info_t repos_info_func, 599251881Speter void *repos_info_baton, 600251881Speter apr_hash_t *repos_cache, 601251881Speter apr_pool_t *result_pool, 602251881Speter apr_pool_t *scratch_pool) 603251881Speter{ 604251881Speter /* Easy exit. */ 605251881Speter if (entry->repos != NULL && entry->uuid != NULL) 606251881Speter return SVN_NO_ERROR; 607251881Speter 608251881Speter if ((entry->repos == NULL || entry->uuid == NULL) 609251881Speter && entry->url) 610251881Speter { 611251881Speter apr_hash_index_t *hi; 612251881Speter 613251881Speter for (hi = apr_hash_first(scratch_pool, repos_cache); 614251881Speter hi; hi = apr_hash_next(hi)) 615251881Speter { 616289180Speter if (svn_uri__is_ancestor(apr_hash_this_key(hi), entry->url)) 617251881Speter { 618251881Speter if (!entry->repos) 619289180Speter entry->repos = apr_hash_this_key(hi); 620251881Speter 621251881Speter if (!entry->uuid) 622289180Speter entry->uuid = apr_hash_this_val(hi); 623251881Speter 624251881Speter return SVN_NO_ERROR; 625251881Speter } 626251881Speter } 627251881Speter } 628251881Speter 629251881Speter if (entry->repos == NULL && repos_info_func == NULL) 630251881Speter return svn_error_createf( 631251881Speter SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL, 632251881Speter _("Working copy '%s' can't be upgraded because the repository root is " 633251881Speter "not available and can't be retrieved"), 634251881Speter svn_dirent_local_style(local_abspath, scratch_pool)); 635251881Speter 636251881Speter if (entry->uuid == NULL && repos_info_func == NULL) 637251881Speter return svn_error_createf( 638251881Speter SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL, 639251881Speter _("Working copy '%s' can't be upgraded because the repository uuid is " 640251881Speter "not available and can't be retrieved"), 641251881Speter svn_dirent_local_style(local_abspath, scratch_pool)); 642251881Speter 643251881Speter if (entry->url == NULL) 644251881Speter return svn_error_createf( 645251881Speter SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL, 646251881Speter _("Working copy '%s' can't be upgraded because it doesn't have a url"), 647251881Speter svn_dirent_local_style(local_abspath, scratch_pool)); 648251881Speter 649251881Speter return svn_error_trace((*repos_info_func)(&entry->repos, &entry->uuid, 650251881Speter repos_info_baton, 651251881Speter entry->url, 652251881Speter result_pool, scratch_pool)); 653251881Speter} 654251881Speter 655251881Speter 656289180Speter/* ### need much more docco 657251881Speter 658289180Speter ### this function should be called within a sqlite transaction. it makes 659289180Speter ### assumptions around this fact. 660289180Speter 661289180Speter Apply the various sets of properties to the database nodes based on 662289180Speter their existence/presence, the current state of the node, and the original 663289180Speter format of the working copy which provided these property sets. 664289180Speter*/ 665289180Speterstatic svn_error_t * 666289180Speterupgrade_apply_props(svn_sqlite__db_t *sdb, 667289180Speter const char *dir_abspath, 668289180Speter const char *local_relpath, 669289180Speter apr_hash_t *base_props, 670289180Speter apr_hash_t *revert_props, 671289180Speter apr_hash_t *working_props, 672289180Speter int original_format, 673289180Speter apr_int64_t wc_id, 674289180Speter apr_pool_t *scratch_pool) 675289180Speter{ 676289180Speter svn_sqlite__stmt_t *stmt; 677289180Speter svn_boolean_t have_row; 678289180Speter int top_op_depth = -1; 679289180Speter int below_op_depth = -1; 680289180Speter svn_wc__db_status_t top_presence; 681289180Speter svn_wc__db_status_t below_presence; 682289180Speter int affected_rows; 683289180Speter 684289180Speter /* ### working_props: use set_props_txn. 685289180Speter ### if working_props == NULL, then skip. what if they equal the 686289180Speter ### pristine props? we should probably do the compare here. 687289180Speter ### 688289180Speter ### base props go into WORKING_NODE if avail, otherwise BASE. 689289180Speter ### 690289180Speter ### revert only goes into BASE. (and WORKING better be there!) 691289180Speter 692289180Speter Prior to 1.4.0 (ORIGINAL_FORMAT < 8), REVERT_PROPS did not exist. If a 693289180Speter file was deleted, then a copy (potentially with props) was disallowed 694289180Speter and could not replace the deletion. An addition *could* be performed, 695289180Speter but that would never bring its own props. 696289180Speter 697289180Speter 1.4.0 through 1.4.5 created the concept of REVERT_PROPS, but had a 698289180Speter bug in svn_wc_add_repos_file2() whereby a copy-with-props did NOT 699289180Speter construct a REVERT_PROPS if the target had no props. Thus, reverting 700289180Speter the delete/copy would see no REVERT_PROPS to restore, leaving the 701289180Speter props from the copy source intact, and appearing as if they are (now) 702289180Speter the base props for the previously-deleted file. (wc corruption) 703289180Speter 704289180Speter 1.4.6 ensured that an empty REVERT_PROPS would be established at all 705289180Speter times. See issue 2530, and r861670 as starting points. 706289180Speter 707289180Speter We will use ORIGINAL_FORMAT and SVN_WC__NO_REVERT_FILES to determine 708289180Speter the handling of our inputs, relative to the state of this node. 709289180Speter */ 710289180Speter 711289180Speter SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_NODE_INFO)); 712289180Speter SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath)); 713289180Speter SVN_ERR(svn_sqlite__step(&have_row, stmt)); 714289180Speter if (have_row) 715289180Speter { 716289180Speter top_op_depth = svn_sqlite__column_int(stmt, 0); 717289180Speter top_presence = svn_sqlite__column_token(stmt, 3, presence_map); 718289180Speter SVN_ERR(svn_sqlite__step(&have_row, stmt)); 719289180Speter if (have_row) 720289180Speter { 721289180Speter below_presence = svn_sqlite__column_token(stmt, 3, presence_map); 722289180Speter 723289180Speter /* There might be an intermediate layer on mixed-revision copies, 724289180Speter or when BASE is shadowed */ 725289180Speter if (below_presence == svn_wc__db_status_not_present 726289180Speter || below_presence == svn_wc__db_status_deleted) 727289180Speter SVN_ERR(svn_sqlite__step(&have_row, stmt)); 728289180Speter 729289180Speter if (have_row) 730289180Speter { 731289180Speter below_presence = svn_sqlite__column_token(stmt, 3, presence_map); 732289180Speter below_op_depth = svn_sqlite__column_int(stmt, 0); 733289180Speter } 734289180Speter } 735289180Speter } 736289180Speter SVN_ERR(svn_sqlite__reset(stmt)); 737289180Speter 738289180Speter /* Detect the buggy scenario described above. We cannot upgrade this 739289180Speter working copy if we have no idea where BASE_PROPS should go. */ 740289180Speter if (original_format > SVN_WC__NO_REVERT_FILES 741289180Speter && revert_props == NULL 742289180Speter && top_op_depth != -1 743289180Speter && top_presence == svn_wc__db_status_normal 744289180Speter && below_op_depth != -1 745289180Speter && below_presence != svn_wc__db_status_not_present) 746289180Speter { 747289180Speter /* There should be REVERT_PROPS, so it appears that we just ran into 748289180Speter the described bug. Sigh. */ 749289180Speter return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, 750289180Speter _("The properties of '%s' are in an " 751289180Speter "indeterminate state and cannot be " 752289180Speter "upgraded. See issue #2530."), 753289180Speter svn_dirent_local_style( 754289180Speter svn_dirent_join(dir_abspath, local_relpath, 755289180Speter scratch_pool), scratch_pool)); 756289180Speter } 757289180Speter 758289180Speter /* Need at least one row, or two rows if there are revert props */ 759289180Speter if (top_op_depth == -1 760289180Speter || (below_op_depth == -1 && revert_props)) 761289180Speter return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, 762289180Speter _("Insufficient NODES rows for '%s'"), 763289180Speter svn_dirent_local_style( 764289180Speter svn_dirent_join(dir_abspath, local_relpath, 765289180Speter scratch_pool), scratch_pool)); 766289180Speter 767289180Speter /* one row, base props only: upper row gets base props 768289180Speter two rows, base props only: lower row gets base props 769289180Speter two rows, revert props only: lower row gets revert props 770289180Speter two rows, base and revert props: upper row gets base, lower gets revert */ 771289180Speter 772289180Speter 773289180Speter if (revert_props || below_op_depth == -1) 774289180Speter { 775289180Speter SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 776289180Speter STMT_UPDATE_NODE_PROPS)); 777289180Speter SVN_ERR(svn_sqlite__bindf(stmt, "isd", 778289180Speter wc_id, local_relpath, top_op_depth)); 779289180Speter SVN_ERR(svn_sqlite__bind_properties(stmt, 4, base_props, scratch_pool)); 780289180Speter SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); 781289180Speter 782289180Speter SVN_ERR_ASSERT(affected_rows == 1); 783289180Speter } 784289180Speter 785289180Speter if (below_op_depth != -1) 786289180Speter { 787289180Speter apr_hash_t *props = revert_props ? revert_props : base_props; 788289180Speter 789289180Speter SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 790289180Speter STMT_UPDATE_NODE_PROPS)); 791289180Speter SVN_ERR(svn_sqlite__bindf(stmt, "isd", 792289180Speter wc_id, local_relpath, below_op_depth)); 793289180Speter SVN_ERR(svn_sqlite__bind_properties(stmt, 4, props, scratch_pool)); 794289180Speter SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); 795289180Speter 796289180Speter SVN_ERR_ASSERT(affected_rows == 1); 797289180Speter } 798289180Speter 799289180Speter /* If there are WORKING_PROPS, then they always go into ACTUAL_NODE. */ 800289180Speter if (working_props != NULL 801289180Speter && base_props != NULL) 802289180Speter { 803289180Speter apr_array_header_t *diffs; 804289180Speter 805289180Speter SVN_ERR(svn_prop_diffs(&diffs, working_props, base_props, scratch_pool)); 806289180Speter 807289180Speter if (diffs->nelts == 0) 808289180Speter working_props = NULL; /* No differences */ 809289180Speter } 810289180Speter 811289180Speter if (working_props != NULL) 812289180Speter { 813289180Speter SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 814289180Speter STMT_UPDATE_ACTUAL_PROPS)); 815289180Speter SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath)); 816289180Speter SVN_ERR(svn_sqlite__bind_properties(stmt, 3, working_props, 817289180Speter scratch_pool)); 818289180Speter SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); 819289180Speter 820289180Speter if (affected_rows == 0) 821289180Speter { 822289180Speter /* We have to insert a row in ACTUAL */ 823289180Speter 824289180Speter SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 825289180Speter STMT_INSERT_ACTUAL_PROPS)); 826289180Speter SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath)); 827289180Speter if (*local_relpath != '\0') 828289180Speter SVN_ERR(svn_sqlite__bind_text(stmt, 3, 829289180Speter svn_relpath_dirname(local_relpath, 830289180Speter scratch_pool))); 831289180Speter SVN_ERR(svn_sqlite__bind_properties(stmt, 4, working_props, 832289180Speter scratch_pool)); 833289180Speter return svn_error_trace(svn_sqlite__step_done(stmt)); 834289180Speter } 835289180Speter } 836289180Speter 837289180Speter return SVN_NO_ERROR; 838289180Speter} 839289180Speter 840289180Speter 841251881Speterstruct bump_baton { 842251881Speter const char *wcroot_abspath; 843251881Speter}; 844251881Speter 845251881Speter/* Migrate the properties for one node (LOCAL_ABSPATH). */ 846251881Speterstatic svn_error_t * 847251881Spetermigrate_node_props(const char *dir_abspath, 848251881Speter const char *new_wcroot_abspath, 849251881Speter const char *name, 850251881Speter svn_sqlite__db_t *sdb, 851251881Speter int original_format, 852251881Speter apr_int64_t wc_id, 853251881Speter apr_pool_t *scratch_pool) 854251881Speter{ 855251881Speter const char *base_abspath; /* old name. nowadays: "pristine" */ 856251881Speter const char *revert_abspath; /* old name. nowadays: "BASE" */ 857251881Speter const char *working_abspath; /* old name. nowadays: "ACTUAL" */ 858251881Speter apr_hash_t *base_props; 859251881Speter apr_hash_t *revert_props; 860251881Speter apr_hash_t *working_props; 861251881Speter const char *old_wcroot_abspath 862251881Speter = svn_dirent_get_longest_ancestor(dir_abspath, new_wcroot_abspath, 863251881Speter scratch_pool); 864251881Speter const char *dir_relpath = svn_dirent_skip_ancestor(old_wcroot_abspath, 865251881Speter dir_abspath); 866251881Speter 867251881Speter if (*name == '\0') 868251881Speter { 869251881Speter base_abspath = svn_wc__adm_child(dir_abspath, 870251881Speter PROP_BASE_FOR_DIR, scratch_pool); 871251881Speter revert_abspath = svn_wc__adm_child(dir_abspath, 872251881Speter PROP_REVERT_FOR_DIR, scratch_pool); 873251881Speter working_abspath = svn_wc__adm_child(dir_abspath, 874251881Speter PROP_WORKING_FOR_DIR, scratch_pool); 875251881Speter } 876251881Speter else 877251881Speter { 878251881Speter const char *basedir_abspath; 879251881Speter const char *propsdir_abspath; 880251881Speter 881251881Speter propsdir_abspath = svn_wc__adm_child(dir_abspath, PROPS_SUBDIR, 882251881Speter scratch_pool); 883251881Speter basedir_abspath = svn_wc__adm_child(dir_abspath, PROP_BASE_SUBDIR, 884251881Speter scratch_pool); 885251881Speter 886251881Speter base_abspath = svn_dirent_join(basedir_abspath, 887251881Speter apr_pstrcat(scratch_pool, 888251881Speter name, 889251881Speter SVN_WC__BASE_EXT, 890289180Speter SVN_VA_NULL), 891251881Speter scratch_pool); 892251881Speter 893251881Speter revert_abspath = svn_dirent_join(basedir_abspath, 894251881Speter apr_pstrcat(scratch_pool, 895251881Speter name, 896251881Speter SVN_WC__REVERT_EXT, 897289180Speter SVN_VA_NULL), 898251881Speter scratch_pool); 899251881Speter 900251881Speter working_abspath = svn_dirent_join(propsdir_abspath, 901251881Speter apr_pstrcat(scratch_pool, 902251881Speter name, 903251881Speter SVN_WC__WORK_EXT, 904289180Speter SVN_VA_NULL), 905251881Speter scratch_pool); 906251881Speter } 907251881Speter 908251881Speter SVN_ERR(read_propfile(&base_props, base_abspath, 909251881Speter scratch_pool, scratch_pool)); 910251881Speter SVN_ERR(read_propfile(&revert_props, revert_abspath, 911251881Speter scratch_pool, scratch_pool)); 912251881Speter SVN_ERR(read_propfile(&working_props, working_abspath, 913251881Speter scratch_pool, scratch_pool)); 914251881Speter 915289180Speter return svn_error_trace(upgrade_apply_props( 916251881Speter sdb, new_wcroot_abspath, 917251881Speter svn_relpath_join(dir_relpath, name, scratch_pool), 918251881Speter base_props, revert_props, working_props, 919251881Speter original_format, wc_id, 920251881Speter scratch_pool)); 921251881Speter} 922251881Speter 923251881Speter 924251881Speter/* */ 925251881Speterstatic svn_error_t * 926251881Spetermigrate_props(const char *dir_abspath, 927251881Speter const char *new_wcroot_abspath, 928251881Speter svn_sqlite__db_t *sdb, 929251881Speter int original_format, 930251881Speter apr_int64_t wc_id, 931251881Speter apr_pool_t *scratch_pool) 932251881Speter{ 933251881Speter /* General logic here: iterate over all the immediate children of the root 934251881Speter (since we aren't yet in a centralized system), and for any properties that 935251881Speter exist, map them as follows: 936251881Speter 937251881Speter if (revert props exist): 938251881Speter revert -> BASE 939251881Speter base -> WORKING 940251881Speter working -> ACTUAL 941251881Speter else if (prop pristine is working [as defined in props.c] ): 942251881Speter base -> WORKING 943251881Speter working -> ACTUAL 944251881Speter else: 945251881Speter base -> BASE 946251881Speter working -> ACTUAL 947251881Speter 948251881Speter ### the middle "test" should simply look for a WORKING_NODE row 949251881Speter 950251881Speter Note that it is legal for "working" props to be missing. That implies 951251881Speter no local changes to the properties. 952251881Speter */ 953251881Speter const apr_array_header_t *children; 954251881Speter apr_pool_t *iterpool = svn_pool_create(scratch_pool); 955251881Speter const char *old_wcroot_abspath 956251881Speter = svn_dirent_get_longest_ancestor(dir_abspath, new_wcroot_abspath, 957251881Speter scratch_pool); 958251881Speter const char *dir_relpath = svn_dirent_skip_ancestor(old_wcroot_abspath, 959251881Speter dir_abspath); 960251881Speter int i; 961251881Speter 962251881Speter /* Migrate the props for "this dir". */ 963251881Speter SVN_ERR(migrate_node_props(dir_abspath, new_wcroot_abspath, "", sdb, 964251881Speter original_format, wc_id, iterpool)); 965251881Speter 966251881Speter /* Iterate over all the files in this SDB. */ 967251881Speter SVN_ERR(get_versioned_files(&children, dir_relpath, sdb, wc_id, scratch_pool, 968251881Speter iterpool)); 969251881Speter for (i = 0; i < children->nelts; i++) 970251881Speter { 971251881Speter const char *name = APR_ARRAY_IDX(children, i, const char *); 972251881Speter 973251881Speter svn_pool_clear(iterpool); 974251881Speter 975251881Speter SVN_ERR(migrate_node_props(dir_abspath, new_wcroot_abspath, 976251881Speter name, sdb, original_format, wc_id, iterpool)); 977251881Speter } 978251881Speter 979251881Speter svn_pool_destroy(iterpool); 980251881Speter 981251881Speter return SVN_NO_ERROR; 982251881Speter} 983251881Speter 984251881Speter 985251881Speter/* If STR ends with SUFFIX and is longer than SUFFIX, return the part of 986251881Speter * STR that comes before SUFFIX; else return NULL. */ 987251881Speterstatic char * 988251881Speterremove_suffix(const char *str, const char *suffix, apr_pool_t *result_pool) 989251881Speter{ 990251881Speter size_t str_len = strlen(str); 991251881Speter size_t suffix_len = strlen(suffix); 992251881Speter 993251881Speter if (str_len > suffix_len 994251881Speter && strcmp(str + str_len - suffix_len, suffix) == 0) 995251881Speter { 996251881Speter return apr_pstrmemdup(result_pool, str, str_len - suffix_len); 997251881Speter } 998251881Speter 999251881Speter return NULL; 1000251881Speter} 1001251881Speter 1002251881Speter/* Copy all the text-base files from the administrative area of WC directory 1003251881Speter DIR_ABSPATH into the pristine store of SDB which is located in directory 1004251881Speter NEW_WCROOT_ABSPATH. 1005251881Speter 1006251881Speter Set *TEXT_BASES_INFO to a new hash, allocated in RESULT_POOL, that maps 1007251881Speter (const char *) name of the versioned file to (svn_wc__text_base_info_t *) 1008251881Speter information about the pristine text. */ 1009251881Speterstatic svn_error_t * 1010251881Spetermigrate_text_bases(apr_hash_t **text_bases_info, 1011251881Speter const char *dir_abspath, 1012251881Speter const char *new_wcroot_abspath, 1013251881Speter svn_sqlite__db_t *sdb, 1014251881Speter apr_pool_t *result_pool, 1015251881Speter apr_pool_t *scratch_pool) 1016251881Speter{ 1017251881Speter apr_hash_t *dirents; 1018251881Speter apr_pool_t *iterpool = svn_pool_create(scratch_pool); 1019251881Speter apr_hash_index_t *hi; 1020251881Speter const char *text_base_dir = svn_wc__adm_child(dir_abspath, 1021251881Speter TEXT_BASE_SUBDIR, 1022251881Speter scratch_pool); 1023251881Speter 1024251881Speter *text_bases_info = apr_hash_make(result_pool); 1025251881Speter 1026251881Speter /* Iterate over the text-base files */ 1027251881Speter SVN_ERR(svn_io_get_dirents3(&dirents, text_base_dir, TRUE, 1028251881Speter scratch_pool, scratch_pool)); 1029251881Speter for (hi = apr_hash_first(scratch_pool, dirents); hi; 1030251881Speter hi = apr_hash_next(hi)) 1031251881Speter { 1032289180Speter const char *text_base_basename = apr_hash_this_key(hi); 1033251881Speter svn_checksum_t *md5_checksum; 1034251881Speter svn_checksum_t *sha1_checksum; 1035251881Speter 1036251881Speter svn_pool_clear(iterpool); 1037251881Speter 1038251881Speter /* Calculate its checksums and copy it to the pristine store */ 1039251881Speter { 1040251881Speter const char *pristine_path; 1041251881Speter const char *text_base_path; 1042251881Speter const char *temp_path; 1043251881Speter svn_sqlite__stmt_t *stmt; 1044251881Speter apr_finfo_t finfo; 1045251881Speter svn_stream_t *read_stream; 1046251881Speter svn_stream_t *result_stream; 1047251881Speter 1048251881Speter text_base_path = svn_dirent_join(text_base_dir, text_base_basename, 1049251881Speter iterpool); 1050251881Speter 1051251881Speter /* Create a copy and calculate a checksum in one step */ 1052251881Speter SVN_ERR(svn_stream_open_unique(&result_stream, &temp_path, 1053251881Speter new_wcroot_abspath, 1054251881Speter svn_io_file_del_none, 1055251881Speter iterpool, iterpool)); 1056251881Speter 1057251881Speter SVN_ERR(svn_stream_open_readonly(&read_stream, text_base_path, 1058251881Speter iterpool, iterpool)); 1059251881Speter 1060251881Speter read_stream = svn_stream_checksummed2(read_stream, &md5_checksum, 1061251881Speter NULL, svn_checksum_md5, 1062251881Speter TRUE, iterpool); 1063251881Speter 1064251881Speter read_stream = svn_stream_checksummed2(read_stream, &sha1_checksum, 1065251881Speter NULL, svn_checksum_sha1, 1066251881Speter TRUE, iterpool); 1067251881Speter 1068251881Speter /* This calculates the hash, creates a copy and closes the stream */ 1069251881Speter SVN_ERR(svn_stream_copy3(read_stream, result_stream, 1070251881Speter NULL, NULL, iterpool)); 1071251881Speter 1072251881Speter SVN_ERR(svn_io_stat(&finfo, text_base_path, APR_FINFO_SIZE, iterpool)); 1073251881Speter 1074251881Speter /* Insert a row into the pristine table. */ 1075251881Speter SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 1076251881Speter STMT_INSERT_OR_IGNORE_PRISTINE)); 1077251881Speter SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, iterpool)); 1078251881Speter SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, iterpool)); 1079251881Speter SVN_ERR(svn_sqlite__bind_int64(stmt, 3, finfo.size)); 1080251881Speter SVN_ERR(svn_sqlite__insert(NULL, stmt)); 1081251881Speter 1082251881Speter SVN_ERR(svn_wc__db_pristine_get_future_path(&pristine_path, 1083251881Speter new_wcroot_abspath, 1084251881Speter sha1_checksum, 1085251881Speter iterpool, iterpool)); 1086251881Speter 1087251881Speter /* Ensure any sharding directories exist. */ 1088251881Speter SVN_ERR(svn_wc__ensure_directory(svn_dirent_dirname(pristine_path, 1089251881Speter iterpool), 1090251881Speter iterpool)); 1091251881Speter 1092251881Speter /* Now move the file into the pristine store, overwriting 1093251881Speter existing files with the same checksum. */ 1094251881Speter SVN_ERR(svn_io_file_move(temp_path, pristine_path, iterpool)); 1095251881Speter } 1096251881Speter 1097251881Speter /* Add the checksums for this text-base to *TEXT_BASES_INFO. */ 1098251881Speter { 1099251881Speter const char *versioned_file_name; 1100251881Speter svn_boolean_t is_revert_base; 1101251881Speter svn_wc__text_base_info_t *info; 1102251881Speter svn_wc__text_base_file_info_t *file_info; 1103251881Speter 1104251881Speter /* Determine the versioned file name and whether this is a normal base 1105251881Speter * or a revert base. */ 1106251881Speter versioned_file_name = remove_suffix(text_base_basename, 1107251881Speter SVN_WC__REVERT_EXT, result_pool); 1108251881Speter if (versioned_file_name) 1109251881Speter { 1110251881Speter is_revert_base = TRUE; 1111251881Speter } 1112251881Speter else 1113251881Speter { 1114251881Speter versioned_file_name = remove_suffix(text_base_basename, 1115251881Speter SVN_WC__BASE_EXT, result_pool); 1116251881Speter is_revert_base = FALSE; 1117251881Speter } 1118251881Speter 1119251881Speter if (! versioned_file_name) 1120251881Speter { 1121251881Speter /* Some file that doesn't end with .svn-base or .svn-revert. 1122251881Speter No idea why that would be in our administrative area, but 1123251881Speter we shouldn't segfault on this case. 1124251881Speter 1125251881Speter Note that we already copied this file in the pristine store, 1126251881Speter but the next cleanup will take care of that. 1127251881Speter */ 1128251881Speter continue; 1129251881Speter } 1130251881Speter 1131251881Speter /* Create a new info struct for this versioned file, or fill in the 1132251881Speter * existing one if this is the second text-base we've found for it. */ 1133251881Speter info = svn_hash_gets(*text_bases_info, versioned_file_name); 1134251881Speter if (info == NULL) 1135251881Speter info = apr_pcalloc(result_pool, sizeof (*info)); 1136251881Speter file_info = (is_revert_base ? &info->revert_base : &info->normal_base); 1137251881Speter 1138251881Speter file_info->sha1_checksum = svn_checksum_dup(sha1_checksum, result_pool); 1139251881Speter file_info->md5_checksum = svn_checksum_dup(md5_checksum, result_pool); 1140251881Speter svn_hash_sets(*text_bases_info, versioned_file_name, info); 1141251881Speter } 1142251881Speter } 1143251881Speter 1144251881Speter svn_pool_destroy(iterpool); 1145251881Speter 1146251881Speter return SVN_NO_ERROR; 1147251881Speter} 1148251881Speter 1149251881Spetersvn_error_t * 1150251881Spetersvn_wc__upgrade_conflict_skel_from_raw(svn_skel_t **conflicts, 1151251881Speter svn_wc__db_t *db, 1152251881Speter const char *wri_abspath, 1153251881Speter const char *local_relpath, 1154251881Speter const char *conflict_old, 1155251881Speter const char *conflict_wrk, 1156251881Speter const char *conflict_new, 1157251881Speter const char *prej_file, 1158251881Speter const char *tree_conflict_data, 1159251881Speter apr_size_t tree_conflict_len, 1160251881Speter apr_pool_t *result_pool, 1161251881Speter apr_pool_t *scratch_pool) 1162251881Speter{ 1163251881Speter svn_skel_t *conflict_data = NULL; 1164251881Speter const char *wcroot_abspath; 1165251881Speter 1166251881Speter SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, db, wri_abspath, 1167251881Speter scratch_pool, scratch_pool)); 1168251881Speter 1169251881Speter if (conflict_old || conflict_new || conflict_wrk) 1170251881Speter { 1171251881Speter const char *old_abspath = NULL; 1172251881Speter const char *new_abspath = NULL; 1173251881Speter const char *wrk_abspath = NULL; 1174251881Speter 1175251881Speter conflict_data = svn_wc__conflict_skel_create(result_pool); 1176251881Speter 1177251881Speter if (conflict_old) 1178251881Speter old_abspath = svn_dirent_join(wcroot_abspath, conflict_old, 1179251881Speter scratch_pool); 1180251881Speter 1181251881Speter if (conflict_new) 1182251881Speter new_abspath = svn_dirent_join(wcroot_abspath, conflict_new, 1183251881Speter scratch_pool); 1184251881Speter 1185251881Speter if (conflict_wrk) 1186251881Speter wrk_abspath = svn_dirent_join(wcroot_abspath, conflict_wrk, 1187251881Speter scratch_pool); 1188251881Speter 1189251881Speter SVN_ERR(svn_wc__conflict_skel_add_text_conflict(conflict_data, 1190251881Speter db, wri_abspath, 1191251881Speter wrk_abspath, 1192251881Speter old_abspath, 1193251881Speter new_abspath, 1194251881Speter scratch_pool, 1195251881Speter scratch_pool)); 1196251881Speter } 1197251881Speter 1198251881Speter if (prej_file) 1199251881Speter { 1200251881Speter const char *prej_abspath; 1201251881Speter 1202251881Speter if (!conflict_data) 1203251881Speter conflict_data = svn_wc__conflict_skel_create(result_pool); 1204251881Speter 1205251881Speter prej_abspath = svn_dirent_join(wcroot_abspath, prej_file, scratch_pool); 1206251881Speter 1207251881Speter SVN_ERR(svn_wc__conflict_skel_add_prop_conflict(conflict_data, 1208251881Speter db, wri_abspath, 1209251881Speter prej_abspath, 1210251881Speter NULL, NULL, NULL, 1211251881Speter apr_hash_make(scratch_pool), 1212251881Speter scratch_pool, 1213251881Speter scratch_pool)); 1214251881Speter } 1215251881Speter 1216251881Speter if (tree_conflict_data) 1217251881Speter { 1218251881Speter svn_skel_t *tc_skel; 1219251881Speter const svn_wc_conflict_description2_t *tc; 1220251881Speter const char *local_abspath; 1221251881Speter 1222251881Speter if (!conflict_data) 1223251881Speter conflict_data = svn_wc__conflict_skel_create(scratch_pool); 1224251881Speter 1225251881Speter tc_skel = svn_skel__parse(tree_conflict_data, tree_conflict_len, 1226251881Speter scratch_pool); 1227251881Speter 1228251881Speter local_abspath = svn_dirent_join(wcroot_abspath, local_relpath, 1229251881Speter scratch_pool); 1230251881Speter 1231251881Speter SVN_ERR(svn_wc__deserialize_conflict(&tc, tc_skel, 1232251881Speter svn_dirent_dirname(local_abspath, 1233251881Speter scratch_pool), 1234251881Speter scratch_pool, scratch_pool)); 1235251881Speter 1236251881Speter SVN_ERR(svn_wc__conflict_skel_add_tree_conflict(conflict_data, 1237251881Speter db, wri_abspath, 1238251881Speter tc->reason, 1239251881Speter tc->action, 1240362181Sdim NULL, NULL, 1241251881Speter scratch_pool, 1242251881Speter scratch_pool)); 1243251881Speter 1244251881Speter switch (tc->operation) 1245251881Speter { 1246251881Speter case svn_wc_operation_update: 1247251881Speter default: 1248251881Speter SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_data, 1249251881Speter tc->src_left_version, 1250251881Speter tc->src_right_version, 1251251881Speter scratch_pool, 1252251881Speter scratch_pool)); 1253251881Speter break; 1254251881Speter case svn_wc_operation_switch: 1255251881Speter SVN_ERR(svn_wc__conflict_skel_set_op_switch(conflict_data, 1256251881Speter tc->src_left_version, 1257251881Speter tc->src_right_version, 1258251881Speter scratch_pool, 1259251881Speter scratch_pool)); 1260251881Speter break; 1261251881Speter case svn_wc_operation_merge: 1262251881Speter SVN_ERR(svn_wc__conflict_skel_set_op_merge(conflict_data, 1263251881Speter tc->src_left_version, 1264251881Speter tc->src_right_version, 1265251881Speter scratch_pool, 1266251881Speter scratch_pool)); 1267251881Speter break; 1268251881Speter } 1269251881Speter } 1270251881Speter else if (conflict_data) 1271251881Speter { 1272251881Speter SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_data, NULL, NULL, 1273251881Speter scratch_pool, 1274251881Speter scratch_pool)); 1275251881Speter } 1276251881Speter 1277251881Speter *conflicts = conflict_data; 1278251881Speter return SVN_NO_ERROR; 1279251881Speter} 1280251881Speter 1281251881Speter/* Helper function to upgrade a single conflict from bump_to_30 */ 1282251881Speterstatic svn_error_t * 1283251881Speterbump_30_upgrade_one_conflict(svn_wc__db_t *wc_db, 1284251881Speter const char *wcroot_abspath, 1285251881Speter svn_sqlite__stmt_t *stmt, 1286251881Speter svn_sqlite__db_t *sdb, 1287251881Speter apr_pool_t *scratch_pool) 1288251881Speter{ 1289251881Speter svn_sqlite__stmt_t *stmt_store; 1290251881Speter svn_stringbuf_t *skel_data; 1291251881Speter svn_skel_t *conflict_data; 1292251881Speter apr_int64_t wc_id = svn_sqlite__column_int64(stmt, 0); 1293251881Speter const char *local_relpath = svn_sqlite__column_text(stmt, 1, NULL); 1294251881Speter const char *conflict_old = svn_sqlite__column_text(stmt, 2, NULL); 1295251881Speter const char *conflict_wrk = svn_sqlite__column_text(stmt, 3, NULL); 1296251881Speter const char *conflict_new = svn_sqlite__column_text(stmt, 4, NULL); 1297251881Speter const char *prop_reject = svn_sqlite__column_text(stmt, 5, NULL); 1298251881Speter apr_size_t tree_conflict_size; 1299251881Speter const char *tree_conflict_data = svn_sqlite__column_blob(stmt, 6, 1300251881Speter &tree_conflict_size, NULL); 1301251881Speter 1302251881Speter SVN_ERR(svn_wc__upgrade_conflict_skel_from_raw(&conflict_data, 1303251881Speter wc_db, wcroot_abspath, 1304251881Speter local_relpath, 1305251881Speter conflict_old, 1306251881Speter conflict_wrk, 1307251881Speter conflict_new, 1308251881Speter prop_reject, 1309251881Speter tree_conflict_data, 1310251881Speter tree_conflict_size, 1311251881Speter scratch_pool, scratch_pool)); 1312251881Speter 1313251881Speter SVN_ERR_ASSERT(conflict_data != NULL); 1314251881Speter 1315251881Speter skel_data = svn_skel__unparse(conflict_data, scratch_pool); 1316251881Speter 1317251881Speter SVN_ERR(svn_sqlite__get_statement(&stmt_store, sdb, 1318251881Speter STMT_UPGRADE_30_SET_CONFLICT)); 1319251881Speter SVN_ERR(svn_sqlite__bindf(stmt_store, "isb", wc_id, local_relpath, 1320251881Speter skel_data->data, skel_data->len)); 1321251881Speter SVN_ERR(svn_sqlite__step_done(stmt_store)); 1322251881Speter 1323251881Speter return SVN_NO_ERROR; 1324251881Speter} 1325251881Speter 1326251881Speterstatic svn_error_t * 1327251881Speterbump_to_30(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) 1328251881Speter{ 1329251881Speter struct bump_baton *bb = baton; 1330251881Speter svn_boolean_t have_row; 1331251881Speter apr_pool_t *iterpool = svn_pool_create(scratch_pool); 1332251881Speter svn_sqlite__stmt_t *stmt; 1333251881Speter svn_wc__db_t *db; /* Read only temp db */ 1334251881Speter 1335251881Speter SVN_ERR(svn_wc__db_open(&db, NULL, TRUE /* open_without_upgrade */, FALSE, 1336251881Speter scratch_pool, scratch_pool)); 1337251881Speter 1338251881Speter SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 1339251881Speter STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE)); 1340251881Speter SVN_ERR(svn_sqlite__step(&have_row, stmt)); 1341251881Speter 1342251881Speter while (have_row) 1343251881Speter { 1344251881Speter svn_error_t *err; 1345251881Speter svn_pool_clear(iterpool); 1346251881Speter 1347251881Speter err = bump_30_upgrade_one_conflict(db, bb->wcroot_abspath, stmt, sdb, 1348251881Speter iterpool); 1349251881Speter 1350251881Speter if (err) 1351251881Speter { 1352251881Speter return svn_error_trace( 1353251881Speter svn_error_compose_create( 1354251881Speter err, 1355251881Speter svn_sqlite__reset(stmt))); 1356251881Speter } 1357251881Speter 1358251881Speter SVN_ERR(svn_sqlite__step(&have_row, stmt)); 1359251881Speter } 1360251881Speter SVN_ERR(svn_sqlite__reset(stmt)); 1361251881Speter 1362251881Speter SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_30)); 1363251881Speter SVN_ERR(svn_wc__db_close(db)); 1364251881Speter return SVN_NO_ERROR; 1365251881Speter} 1366251881Speter 1367251881Speterstatic svn_error_t * 1368251881Speterbump_to_31(void *baton, 1369251881Speter svn_sqlite__db_t *sdb, 1370251881Speter apr_pool_t *scratch_pool) 1371251881Speter{ 1372251881Speter svn_sqlite__stmt_t *stmt, *stmt_mark_switch_roots; 1373251881Speter svn_boolean_t have_row; 1374251881Speter apr_pool_t *iterpool = svn_pool_create(scratch_pool); 1375251881Speter apr_array_header_t *empty_iprops = apr_array_make( 1376251881Speter scratch_pool, 0, sizeof(svn_prop_inherited_item_t *)); 1377251881Speter svn_error_t *err; 1378251881Speter 1379251881Speter /* Run additional statements to finalize the upgrade to format 31. */ 1380362181Sdim SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_31)); 1381251881Speter 1382251881Speter /* Set inherited_props to an empty array for the roots of all 1383251881Speter switched subtrees in the WC. This allows subsequent updates 1384251881Speter to recognize these roots as needing an iprops cache. */ 1385251881Speter SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 1386251881Speter STMT_UPGRADE_31_SELECT_WCROOT_NODES)); 1387251881Speter SVN_ERR(svn_sqlite__step(&have_row, stmt)); 1388251881Speter 1389251881Speter err = svn_sqlite__get_statement(&stmt_mark_switch_roots, sdb, 1390251881Speter STMT_UPDATE_IPROP); 1391251881Speter if (err) 1392251881Speter return svn_error_compose_create(err, svn_sqlite__reset(stmt)); 1393251881Speter 1394251881Speter while (have_row) 1395251881Speter { 1396251881Speter const char *switched_relpath = svn_sqlite__column_text(stmt, 1, NULL); 1397251881Speter apr_int64_t wc_id = svn_sqlite__column_int64(stmt, 0); 1398251881Speter 1399251881Speter err = svn_sqlite__bindf(stmt_mark_switch_roots, "is", wc_id, 1400251881Speter switched_relpath); 1401251881Speter if (!err) 1402251881Speter err = svn_sqlite__bind_iprops(stmt_mark_switch_roots, 3, 1403251881Speter empty_iprops, iterpool); 1404251881Speter if (!err) 1405251881Speter err = svn_sqlite__step_done(stmt_mark_switch_roots); 1406251881Speter if (!err) 1407251881Speter err = svn_sqlite__step(&have_row, stmt); 1408251881Speter 1409251881Speter if (err) 1410251881Speter return svn_error_compose_create( 1411251881Speter err, 1412251881Speter svn_error_compose_create( 1413251881Speter /* Reset in either order is OK. */ 1414251881Speter svn_sqlite__reset(stmt), 1415251881Speter svn_sqlite__reset(stmt_mark_switch_roots))); 1416251881Speter } 1417251881Speter 1418251881Speter err = svn_sqlite__reset(stmt_mark_switch_roots); 1419251881Speter if (err) 1420251881Speter return svn_error_compose_create(err, svn_sqlite__reset(stmt)); 1421251881Speter SVN_ERR(svn_sqlite__reset(stmt)); 1422251881Speter 1423251881Speter svn_pool_destroy(iterpool); 1424251881Speter 1425251881Speter return SVN_NO_ERROR; 1426251881Speter} 1427251881Speter 1428289180Speterstatic svn_error_t * 1429289180Speterupgrade_apply_dav_cache(svn_sqlite__db_t *sdb, 1430289180Speter const char *dir_relpath, 1431289180Speter apr_int64_t wc_id, 1432289180Speter apr_hash_t *cache_values, 1433289180Speter apr_pool_t *scratch_pool) 1434289180Speter{ 1435289180Speter apr_pool_t *iterpool = svn_pool_create(scratch_pool); 1436289180Speter apr_hash_index_t *hi; 1437289180Speter svn_sqlite__stmt_t *stmt; 1438251881Speter 1439289180Speter SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 1440289180Speter STMT_UPDATE_BASE_NODE_DAV_CACHE)); 1441289180Speter 1442289180Speter /* Iterate over all the wcprops, writing each one to the wc_db. */ 1443289180Speter for (hi = apr_hash_first(scratch_pool, cache_values); 1444289180Speter hi; 1445289180Speter hi = apr_hash_next(hi)) 1446289180Speter { 1447289180Speter const char *name = apr_hash_this_key(hi); 1448289180Speter apr_hash_t *props = apr_hash_this_val(hi); 1449289180Speter const char *local_relpath; 1450289180Speter 1451289180Speter svn_pool_clear(iterpool); 1452289180Speter 1453289180Speter local_relpath = svn_relpath_join(dir_relpath, name, iterpool); 1454289180Speter 1455289180Speter SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath)); 1456289180Speter SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, iterpool)); 1457289180Speter SVN_ERR(svn_sqlite__step_done(stmt)); 1458289180Speter } 1459289180Speter 1460289180Speter svn_pool_destroy(iterpool); 1461289180Speter 1462289180Speter return SVN_NO_ERROR; 1463289180Speter} 1464289180Speter 1465289180Speter 1466251881Speterstruct upgrade_data_t { 1467251881Speter svn_sqlite__db_t *sdb; 1468251881Speter const char *root_abspath; 1469251881Speter apr_int64_t repos_id; 1470251881Speter apr_int64_t wc_id; 1471251881Speter}; 1472251881Speter 1473251881Speter/* Upgrade the working copy directory represented by DB/DIR_ABSPATH 1474251881Speter from OLD_FORMAT to the wc-ng format (SVN_WC__WC_NG_VERSION)'. 1475251881Speter 1476251881Speter Pass REPOS_INFO_FUNC, REPOS_INFO_BATON and REPOS_CACHE to 1477251881Speter ensure_repos_info. Add the found repository root and UUID to 1478251881Speter REPOS_CACHE if it doesn't have a cached entry for this 1479251881Speter repository. 1480251881Speter 1481251881Speter *DATA refers to the single root db. 1482251881Speter 1483251881Speter Uses SCRATCH_POOL for all temporary allocation. */ 1484251881Speterstatic svn_error_t * 1485251881Speterupgrade_to_wcng(void **dir_baton, 1486251881Speter void *parent_baton, 1487251881Speter svn_wc__db_t *db, 1488251881Speter const char *dir_abspath, 1489251881Speter int old_format, 1490251881Speter apr_int64_t wc_id, 1491251881Speter svn_wc_upgrade_get_repos_info_t repos_info_func, 1492251881Speter void *repos_info_baton, 1493251881Speter apr_hash_t *repos_cache, 1494251881Speter const struct upgrade_data_t *data, 1495251881Speter apr_pool_t *result_pool, 1496251881Speter apr_pool_t *scratch_pool) 1497251881Speter{ 1498251881Speter const char *logfile_path = svn_wc__adm_child(dir_abspath, ADM_LOG, 1499251881Speter scratch_pool); 1500251881Speter svn_node_kind_t logfile_on_disk_kind; 1501251881Speter apr_hash_t *entries; 1502251881Speter svn_wc_entry_t *this_dir; 1503251881Speter const char *old_wcroot_abspath, *dir_relpath; 1504251881Speter apr_hash_t *text_bases_info; 1505251881Speter svn_error_t *err; 1506251881Speter 1507251881Speter /* Don't try to mess with the WC if there are old log files left. */ 1508251881Speter 1509251881Speter /* Is the (first) log file present? */ 1510251881Speter SVN_ERR(svn_io_check_path(logfile_path, &logfile_on_disk_kind, 1511251881Speter scratch_pool)); 1512251881Speter if (logfile_on_disk_kind == svn_node_file) 1513251881Speter return svn_error_create(SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL, 1514251881Speter _("Cannot upgrade with existing logs; run a " 1515251881Speter "cleanup operation on this working copy using " 1516251881Speter "a client version which is compatible with this " 1517251881Speter "working copy's format (such as the version " 1518251881Speter "you are upgrading from), then retry the " 1519251881Speter "upgrade with the current version")); 1520251881Speter 1521251881Speter /* Lock this working copy directory, or steal an existing lock. Do this 1522251881Speter BEFORE we read the entries. We don't want another process to modify the 1523251881Speter entries after we've read them into memory. */ 1524251881Speter SVN_ERR(create_physical_lock(dir_abspath, scratch_pool)); 1525251881Speter 1526251881Speter /* What's going on here? 1527251881Speter * 1528251881Speter * We're attempting to upgrade an older working copy to the new wc-ng format. 1529251881Speter * The semantics and storage mechanisms between the two are vastly different, 1530251881Speter * so it's going to be a bit painful. Here's a plan for the operation: 1531251881Speter * 1532251881Speter * 1) Read the old 'entries' using the old-format reader. 1533251881Speter * 1534251881Speter * 2) Create the new DB if it hasn't already been created. 1535251881Speter * 1536251881Speter * 3) Use our compatibility code for writing entries to fill out the (new) 1537251881Speter * DB state. Use the remembered checksums, since an entry has only the 1538251881Speter * MD5 not the SHA1 checksum, and in the case of a revert-base doesn't 1539251881Speter * even have that. 1540251881Speter * 1541251881Speter * 4) Convert wcprop to the wc-ng format 1542251881Speter * 1543251881Speter * 5) Migrate regular properties to the WC-NG DB. 1544251881Speter */ 1545251881Speter 1546251881Speter /***** ENTRIES - READ *****/ 1547251881Speter SVN_ERR(svn_wc__read_entries_old(&entries, dir_abspath, 1548251881Speter scratch_pool, scratch_pool)); 1549251881Speter 1550251881Speter this_dir = svn_hash_gets(entries, SVN_WC_ENTRY_THIS_DIR); 1551251881Speter SVN_ERR(ensure_repos_info(this_dir, dir_abspath, 1552251881Speter repos_info_func, repos_info_baton, 1553251881Speter repos_cache, 1554251881Speter scratch_pool, scratch_pool)); 1555251881Speter 1556251881Speter /* Cache repos UUID pairs for when a subdir doesn't have this information */ 1557251881Speter if (!svn_hash_gets(repos_cache, this_dir->repos)) 1558251881Speter { 1559251881Speter apr_pool_t *hash_pool = apr_hash_pool_get(repos_cache); 1560251881Speter 1561251881Speter svn_hash_sets(repos_cache, 1562251881Speter apr_pstrdup(hash_pool, this_dir->repos), 1563251881Speter apr_pstrdup(hash_pool, this_dir->uuid)); 1564251881Speter } 1565251881Speter 1566251881Speter old_wcroot_abspath = svn_dirent_get_longest_ancestor(dir_abspath, 1567251881Speter data->root_abspath, 1568251881Speter scratch_pool); 1569251881Speter dir_relpath = svn_dirent_skip_ancestor(old_wcroot_abspath, dir_abspath); 1570251881Speter 1571251881Speter /***** TEXT BASES *****/ 1572251881Speter SVN_ERR(migrate_text_bases(&text_bases_info, dir_abspath, data->root_abspath, 1573251881Speter data->sdb, scratch_pool, scratch_pool)); 1574251881Speter 1575251881Speter /***** ENTRIES - WRITE *****/ 1576251881Speter err = svn_wc__write_upgraded_entries(dir_baton, parent_baton, db, data->sdb, 1577251881Speter data->repos_id, data->wc_id, 1578251881Speter dir_abspath, data->root_abspath, 1579251881Speter entries, text_bases_info, 1580251881Speter result_pool, scratch_pool); 1581251881Speter if (err && err->apr_err == SVN_ERR_WC_CORRUPT) 1582251881Speter return svn_error_quick_wrap(err, 1583251881Speter _("This working copy is corrupt and " 1584251881Speter "cannot be upgraded. Please check out " 1585251881Speter "a new working copy.")); 1586251881Speter else 1587251881Speter SVN_ERR(err); 1588251881Speter 1589251881Speter /***** WC PROPS *****/ 1590251881Speter /* If we don't know precisely where the wcprops are, ignore them. */ 1591251881Speter if (old_format != SVN_WC__WCPROPS_LOST) 1592251881Speter { 1593251881Speter apr_hash_t *all_wcprops; 1594251881Speter 1595251881Speter if (old_format <= SVN_WC__WCPROPS_MANY_FILES_VERSION) 1596251881Speter SVN_ERR(read_many_wcprops(&all_wcprops, dir_abspath, 1597251881Speter scratch_pool, scratch_pool)); 1598251881Speter else 1599251881Speter SVN_ERR(read_wcprops(&all_wcprops, dir_abspath, 1600251881Speter scratch_pool, scratch_pool)); 1601251881Speter 1602289180Speter SVN_ERR(upgrade_apply_dav_cache(data->sdb, dir_relpath, wc_id, 1603289180Speter all_wcprops, scratch_pool)); 1604251881Speter } 1605251881Speter 1606251881Speter /* Upgrade all the properties (including "this dir"). 1607251881Speter 1608251881Speter Note: this must come AFTER the entries have been migrated into the 1609251881Speter database. The upgrade process needs the children in BASE_NODE and 1610251881Speter WORKING_NODE, and to examine the resultant WORKING state. */ 1611251881Speter SVN_ERR(migrate_props(dir_abspath, data->root_abspath, data->sdb, old_format, 1612251881Speter wc_id, scratch_pool)); 1613251881Speter 1614251881Speter return SVN_NO_ERROR; 1615251881Speter} 1616251881Speter 1617251881Speterconst char * 1618251881Spetersvn_wc__version_string_from_format(int wc_format) 1619251881Speter{ 1620251881Speter switch (wc_format) 1621251881Speter { 1622251881Speter case 4: return "<=1.3"; 1623251881Speter case 8: return "1.4"; 1624251881Speter case 9: return "1.5"; 1625251881Speter case 10: return "1.6"; 1626251881Speter case SVN_WC__WC_NG_VERSION: return "1.7"; 1627251881Speter } 1628251881Speter return _("(unreleased development version)"); 1629251881Speter} 1630251881Speter 1631251881Spetersvn_error_t * 1632251881Spetersvn_wc__upgrade_sdb(int *result_format, 1633251881Speter const char *wcroot_abspath, 1634251881Speter svn_sqlite__db_t *sdb, 1635251881Speter int start_format, 1636251881Speter apr_pool_t *scratch_pool) 1637251881Speter{ 1638251881Speter struct bump_baton bb; 1639251881Speter 1640251881Speter bb.wcroot_abspath = wcroot_abspath; 1641251881Speter 1642251881Speter if (start_format < SVN_WC__WC_NG_VERSION /* 12 */) 1643251881Speter return svn_error_createf(SVN_ERR_WC_UPGRADE_REQUIRED, NULL, 1644251881Speter _("Working copy '%s' is too old (format %d, " 1645251881Speter "created by Subversion %s)"), 1646251881Speter svn_dirent_local_style(wcroot_abspath, 1647251881Speter scratch_pool), 1648251881Speter start_format, 1649251881Speter svn_wc__version_string_from_format(start_format)); 1650251881Speter 1651251881Speter /* Early WCNG formats no longer supported. */ 1652251881Speter if (start_format < 19) 1653251881Speter return svn_error_createf(SVN_ERR_WC_UPGRADE_REQUIRED, NULL, 1654251881Speter _("Working copy '%s' is an old development " 1655251881Speter "version (format %d); to upgrade it, " 1656251881Speter "use a format 18 client, then " 1657251881Speter "use 'tools/dev/wc-ng/bump-to-19.py', then " 1658251881Speter "use the current client"), 1659251881Speter svn_dirent_local_style(wcroot_abspath, 1660251881Speter scratch_pool), 1661251881Speter start_format); 1662362181Sdim else if (start_format < 29) 1663362181Sdim return svn_error_createf(SVN_ERR_WC_UPGRADE_REQUIRED, NULL, 1664362181Sdim _("Working copy '%s' is an old development " 1665362181Sdim "version (format %d); to upgrade it, " 1666362181Sdim "use a Subversion 1.7-1.9 client, then " 1667362181Sdim "use the current client"), 1668362181Sdim svn_dirent_local_style(wcroot_abspath, 1669362181Sdim scratch_pool), 1670362181Sdim start_format); 1671251881Speter 1672251881Speter /* ### need lock-out. only one upgrade at a time. note that other code 1673251881Speter ### cannot use this un-upgraded database until we finish the upgrade. */ 1674251881Speter 1675251881Speter /* Note: none of these have "break" statements; the fall-through is 1676251881Speter intentional. */ 1677251881Speter switch (start_format) 1678251881Speter { 1679251881Speter case 29: 1680251881Speter SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_30, &bb, 1681251881Speter scratch_pool)); 1682251881Speter *result_format = 30; 1683251881Speter 1684251881Speter case 30: 1685251881Speter SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_31, &bb, 1686251881Speter scratch_pool)); 1687251881Speter *result_format = 31; 1688251881Speter /* FALLTHROUGH */ 1689251881Speter /* ### future bumps go here. */ 1690251881Speter#if 0 1691251881Speter case XXX-1: 1692251881Speter /* Revamp the recording of tree conflicts. */ 1693251881Speter SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_XXX, &bb, 1694251881Speter scratch_pool)); 1695251881Speter *result_format = XXX; 1696251881Speter /* FALLTHROUGH */ 1697251881Speter#endif 1698251881Speter case SVN_WC__VERSION: 1699251881Speter /* already upgraded */ 1700251881Speter *result_format = SVN_WC__VERSION; 1701262250Speter 1702262250Speter SVN_SQLITE__WITH_LOCK( 1703262250Speter svn_wc__db_install_schema_statistics(sdb, scratch_pool), 1704262250Speter sdb); 1705251881Speter } 1706251881Speter 1707251881Speter#ifdef SVN_DEBUG 1708251881Speter if (*result_format != start_format) 1709251881Speter { 1710251881Speter int schema_version; 1711251881Speter SVN_ERR(svn_sqlite__read_schema_version(&schema_version, sdb, scratch_pool)); 1712251881Speter 1713251881Speter /* If this assertion fails the schema isn't updated correctly */ 1714251881Speter SVN_ERR_ASSERT(schema_version == *result_format); 1715251881Speter } 1716251881Speter#endif 1717251881Speter 1718251881Speter /* Zap anything that might be remaining or escaped our notice. */ 1719251881Speter wipe_obsolete_files(wcroot_abspath, scratch_pool); 1720251881Speter 1721251881Speter return SVN_NO_ERROR; 1722251881Speter} 1723251881Speter 1724251881Speter 1725251881Speter/* */ 1726251881Speterstatic svn_error_t * 1727251881Speterupgrade_working_copy(void *parent_baton, 1728251881Speter svn_wc__db_t *db, 1729251881Speter const char *dir_abspath, 1730251881Speter svn_wc_upgrade_get_repos_info_t repos_info_func, 1731251881Speter void *repos_info_baton, 1732251881Speter apr_hash_t *repos_cache, 1733251881Speter const struct upgrade_data_t *data, 1734251881Speter svn_cancel_func_t cancel_func, 1735251881Speter void *cancel_baton, 1736251881Speter svn_wc_notify_func2_t notify_func, 1737251881Speter void *notify_baton, 1738251881Speter apr_pool_t *result_pool, 1739251881Speter apr_pool_t *scratch_pool) 1740251881Speter{ 1741251881Speter void *dir_baton; 1742251881Speter int old_format; 1743251881Speter apr_pool_t *iterpool = svn_pool_create(scratch_pool); 1744251881Speter apr_array_header_t *subdirs; 1745251881Speter svn_error_t *err; 1746251881Speter int i; 1747251881Speter 1748251881Speter if (cancel_func) 1749251881Speter SVN_ERR(cancel_func(cancel_baton)); 1750251881Speter 1751251881Speter SVN_ERR(svn_wc__db_temp_get_format(&old_format, db, dir_abspath, 1752251881Speter iterpool)); 1753251881Speter 1754251881Speter if (old_format >= SVN_WC__WC_NG_VERSION) 1755251881Speter { 1756251881Speter if (notify_func) 1757251881Speter notify_func(notify_baton, 1758251881Speter svn_wc_create_notify(dir_abspath, svn_wc_notify_skip, 1759251881Speter iterpool), 1760251881Speter iterpool); 1761251881Speter svn_pool_destroy(iterpool); 1762251881Speter return SVN_NO_ERROR; 1763251881Speter } 1764251881Speter 1765251881Speter err = get_versioned_subdirs(&subdirs, NULL, dir_abspath, FALSE, 1766251881Speter scratch_pool, iterpool); 1767251881Speter if (err) 1768251881Speter { 1769251881Speter if (APR_STATUS_IS_ENOENT(err->apr_err) 1770251881Speter || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)) 1771251881Speter { 1772251881Speter /* An unversioned dir is obstructing a versioned dir */ 1773251881Speter svn_error_clear(err); 1774251881Speter err = NULL; 1775251881Speter if (notify_func) 1776251881Speter notify_func(notify_baton, 1777251881Speter svn_wc_create_notify(dir_abspath, svn_wc_notify_skip, 1778251881Speter iterpool), 1779251881Speter iterpool); 1780251881Speter } 1781251881Speter svn_pool_destroy(iterpool); 1782251881Speter return err; 1783251881Speter } 1784251881Speter 1785251881Speter 1786251881Speter SVN_ERR(upgrade_to_wcng(&dir_baton, parent_baton, db, dir_abspath, 1787251881Speter old_format, data->wc_id, 1788251881Speter repos_info_func, repos_info_baton, 1789251881Speter repos_cache, data, scratch_pool, iterpool)); 1790251881Speter 1791251881Speter if (notify_func) 1792251881Speter notify_func(notify_baton, 1793251881Speter svn_wc_create_notify(dir_abspath, svn_wc_notify_upgraded_path, 1794251881Speter iterpool), 1795251881Speter iterpool); 1796251881Speter 1797251881Speter for (i = 0; i < subdirs->nelts; ++i) 1798251881Speter { 1799251881Speter const char *child_abspath = APR_ARRAY_IDX(subdirs, i, const char *); 1800251881Speter 1801251881Speter svn_pool_clear(iterpool); 1802251881Speter 1803251881Speter SVN_ERR(upgrade_working_copy(dir_baton, db, child_abspath, 1804251881Speter repos_info_func, repos_info_baton, 1805251881Speter repos_cache, data, 1806251881Speter cancel_func, cancel_baton, 1807251881Speter notify_func, notify_baton, 1808251881Speter iterpool, iterpool)); 1809251881Speter } 1810251881Speter 1811251881Speter svn_pool_destroy(iterpool); 1812251881Speter 1813251881Speter return SVN_NO_ERROR; 1814251881Speter} 1815251881Speter 1816251881Speter 1817251881Speter/* Return a verbose error if LOCAL_ABSPATH is a not a pre-1.7 working 1818251881Speter copy root */ 1819251881Speterstatic svn_error_t * 1820251881Speteris_old_wcroot(const char *local_abspath, 1821251881Speter apr_pool_t *scratch_pool) 1822251881Speter{ 1823251881Speter apr_hash_t *entries; 1824251881Speter const char *parent_abspath, *name; 1825251881Speter svn_wc_entry_t *entry; 1826251881Speter svn_error_t *err = svn_wc__read_entries_old(&entries, local_abspath, 1827251881Speter scratch_pool, scratch_pool); 1828251881Speter if (err) 1829251881Speter { 1830251881Speter return svn_error_createf( 1831251881Speter SVN_ERR_WC_INVALID_OP_ON_CWD, err, 1832251881Speter _("Can't upgrade '%s' as it is not a working copy"), 1833251881Speter svn_dirent_local_style(local_abspath, scratch_pool)); 1834251881Speter } 1835251881Speter else if (svn_dirent_is_root(local_abspath, strlen(local_abspath))) 1836251881Speter return SVN_NO_ERROR; 1837251881Speter 1838251881Speter svn_dirent_split(&parent_abspath, &name, local_abspath, scratch_pool); 1839251881Speter 1840251881Speter err = svn_wc__read_entries_old(&entries, parent_abspath, 1841251881Speter scratch_pool, scratch_pool); 1842251881Speter if (err) 1843251881Speter { 1844251881Speter svn_error_clear(err); 1845251881Speter return SVN_NO_ERROR; 1846251881Speter } 1847251881Speter 1848251881Speter entry = svn_hash_gets(entries, name); 1849251881Speter if (!entry 1850251881Speter || entry->absent 1851251881Speter || (entry->deleted && entry->schedule != svn_wc_schedule_add) 1852251881Speter || entry->depth == svn_depth_exclude) 1853251881Speter { 1854251881Speter return SVN_NO_ERROR; 1855251881Speter } 1856251881Speter 1857251881Speter while (!svn_dirent_is_root(parent_abspath, strlen(parent_abspath))) 1858251881Speter { 1859251881Speter svn_dirent_split(&parent_abspath, &name, parent_abspath, scratch_pool); 1860251881Speter err = svn_wc__read_entries_old(&entries, parent_abspath, 1861251881Speter scratch_pool, scratch_pool); 1862251881Speter if (err) 1863251881Speter { 1864251881Speter svn_error_clear(err); 1865251881Speter parent_abspath = svn_dirent_join(parent_abspath, name, scratch_pool); 1866251881Speter break; 1867251881Speter } 1868251881Speter entry = svn_hash_gets(entries, name); 1869251881Speter if (!entry 1870251881Speter || entry->absent 1871251881Speter || (entry->deleted && entry->schedule != svn_wc_schedule_add) 1872251881Speter || entry->depth == svn_depth_exclude) 1873251881Speter { 1874251881Speter parent_abspath = svn_dirent_join(parent_abspath, name, scratch_pool); 1875251881Speter break; 1876251881Speter } 1877251881Speter } 1878251881Speter 1879251881Speter return svn_error_createf( 1880251881Speter SVN_ERR_WC_INVALID_OP_ON_CWD, NULL, 1881251881Speter _("Can't upgrade '%s' as it is not a working copy root," 1882251881Speter " the root is '%s'"), 1883251881Speter svn_dirent_local_style(local_abspath, scratch_pool), 1884251881Speter svn_dirent_local_style(parent_abspath, scratch_pool)); 1885251881Speter} 1886251881Speter 1887251881Spetersvn_error_t * 1888251881Spetersvn_wc_upgrade(svn_wc_context_t *wc_ctx, 1889251881Speter const char *local_abspath, 1890251881Speter svn_wc_upgrade_get_repos_info_t repos_info_func, 1891251881Speter void *repos_info_baton, 1892251881Speter svn_cancel_func_t cancel_func, 1893251881Speter void *cancel_baton, 1894251881Speter svn_wc_notify_func2_t notify_func, 1895251881Speter void *notify_baton, 1896251881Speter apr_pool_t *scratch_pool) 1897251881Speter{ 1898251881Speter svn_wc__db_t *db; 1899251881Speter struct upgrade_data_t data = { NULL }; 1900251881Speter svn_skel_t *work_item, *work_items = NULL; 1901251881Speter const char *pristine_from, *pristine_to, *db_from, *db_to; 1902251881Speter apr_hash_t *repos_cache = apr_hash_make(scratch_pool); 1903251881Speter svn_wc_entry_t *this_dir; 1904251881Speter apr_hash_t *entries; 1905251881Speter const char *root_adm_abspath; 1906251881Speter svn_error_t *err; 1907251881Speter int result_format; 1908253734Speter svn_boolean_t bumped_format; 1909251881Speter 1910251881Speter /* Try upgrading a wc-ng-style working copy. */ 1911251881Speter SVN_ERR(svn_wc__db_open(&db, NULL /* ### config */, TRUE, FALSE, 1912251881Speter scratch_pool, scratch_pool)); 1913251881Speter 1914251881Speter 1915253734Speter err = svn_wc__db_bump_format(&result_format, &bumped_format, 1916253734Speter db, local_abspath, 1917251881Speter scratch_pool); 1918251881Speter if (err) 1919251881Speter { 1920251881Speter if (err->apr_err != SVN_ERR_WC_UPGRADE_REQUIRED) 1921251881Speter { 1922251881Speter return svn_error_trace( 1923251881Speter svn_error_compose_create( 1924251881Speter err, 1925251881Speter svn_wc__db_close(db))); 1926251881Speter } 1927251881Speter 1928251881Speter svn_error_clear(err); 1929251881Speter /* Pre 1.7: Fall through */ 1930251881Speter } 1931251881Speter else 1932251881Speter { 1933251881Speter /* Auto-upgrade worked! */ 1934251881Speter SVN_ERR(svn_wc__db_close(db)); 1935251881Speter 1936251881Speter SVN_ERR_ASSERT(result_format == SVN_WC__VERSION); 1937251881Speter 1938253734Speter if (bumped_format && notify_func) 1939253734Speter { 1940253734Speter svn_wc_notify_t *notify; 1941253734Speter 1942253734Speter notify = svn_wc_create_notify(local_abspath, 1943253734Speter svn_wc_notify_upgraded_path, 1944253734Speter scratch_pool); 1945253734Speter 1946253734Speter notify_func(notify_baton, notify, scratch_pool); 1947253734Speter } 1948253734Speter 1949251881Speter return SVN_NO_ERROR; 1950251881Speter } 1951251881Speter 1952251881Speter SVN_ERR(is_old_wcroot(local_abspath, scratch_pool)); 1953251881Speter 1954251881Speter /* Given a pre-wcng root some/wc we create a temporary wcng in 1955251881Speter some/wc/.svn/tmp/wcng/wc.db and copy the metadata from one to the 1956251881Speter other, then the temporary wc.db file gets moved into the original 1957251881Speter root. Until the wc.db file is moved the original working copy 1958251881Speter remains a pre-wcng and 'cleanup' with an old client will remove 1959251881Speter the partial upgrade. Moving the wc.db file creates a wcng, and 1960251881Speter 'cleanup' with a new client will complete any outstanding 1961251881Speter upgrade. */ 1962251881Speter 1963251881Speter SVN_ERR(svn_wc__read_entries_old(&entries, local_abspath, 1964251881Speter scratch_pool, scratch_pool)); 1965251881Speter 1966251881Speter this_dir = svn_hash_gets(entries, SVN_WC_ENTRY_THIS_DIR); 1967251881Speter SVN_ERR(ensure_repos_info(this_dir, local_abspath, repos_info_func, 1968251881Speter repos_info_baton, repos_cache, 1969251881Speter scratch_pool, scratch_pool)); 1970251881Speter 1971251881Speter /* Cache repos UUID pairs for when a subdir doesn't have this information */ 1972251881Speter if (!svn_hash_gets(repos_cache, this_dir->repos)) 1973251881Speter svn_hash_sets(repos_cache, 1974251881Speter apr_pstrdup(scratch_pool, this_dir->repos), 1975251881Speter apr_pstrdup(scratch_pool, this_dir->uuid)); 1976251881Speter 1977251881Speter /* Create the new DB in the temporary root wc/.svn/tmp/wcng/.svn */ 1978251881Speter data.root_abspath = svn_dirent_join(svn_wc__adm_child(local_abspath, "tmp", 1979251881Speter scratch_pool), 1980251881Speter "wcng", scratch_pool); 1981251881Speter root_adm_abspath = svn_wc__adm_child(data.root_abspath, "", 1982251881Speter scratch_pool); 1983251881Speter SVN_ERR(svn_io_remove_dir2(root_adm_abspath, TRUE, NULL, NULL, 1984251881Speter scratch_pool)); 1985251881Speter SVN_ERR(svn_wc__ensure_directory(root_adm_abspath, scratch_pool)); 1986251881Speter 1987251881Speter /* Create an empty sqlite database for this directory and store it in DB. */ 1988251881Speter SVN_ERR(svn_wc__db_upgrade_begin(&data.sdb, 1989251881Speter &data.repos_id, &data.wc_id, 1990251881Speter db, data.root_abspath, 1991251881Speter this_dir->repos, this_dir->uuid, 1992251881Speter scratch_pool)); 1993251881Speter 1994251881Speter /* Migrate the entries over to the new database. 1995251881Speter ### We need to think about atomicity here. 1996251881Speter 1997251881Speter entries_write_new() writes in current format rather than 1998251881Speter f12. Thus, this function bumps a working copy all the way to 1999251881Speter current. */ 2000251881Speter SVN_ERR(svn_wc__db_wclock_obtain(db, data.root_abspath, 0, FALSE, 2001251881Speter scratch_pool)); 2002251881Speter 2003289180Speter SVN_SQLITE__WITH_LOCK( 2004289180Speter upgrade_working_copy(NULL, db, local_abspath, 2005289180Speter repos_info_func, repos_info_baton, 2006289180Speter repos_cache, &data, 2007289180Speter cancel_func, cancel_baton, 2008289180Speter notify_func, notify_baton, 2009289180Speter scratch_pool, scratch_pool), 2010289180Speter data.sdb); 2011251881Speter 2012251881Speter /* A workqueue item to move the pristine dir into place */ 2013251881Speter pristine_from = svn_wc__adm_child(data.root_abspath, PRISTINE_STORAGE_RELPATH, 2014251881Speter scratch_pool); 2015251881Speter pristine_to = svn_wc__adm_child(local_abspath, PRISTINE_STORAGE_RELPATH, 2016251881Speter scratch_pool); 2017251881Speter SVN_ERR(svn_wc__ensure_directory(pristine_from, scratch_pool)); 2018251881Speter SVN_ERR(svn_wc__wq_build_file_move(&work_item, db, local_abspath, 2019251881Speter pristine_from, pristine_to, 2020251881Speter scratch_pool, scratch_pool)); 2021251881Speter work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool); 2022251881Speter 2023251881Speter /* A workqueue item to remove pre-wcng metadata */ 2024251881Speter SVN_ERR(svn_wc__wq_build_postupgrade(&work_item, scratch_pool)); 2025251881Speter work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool); 2026251881Speter SVN_ERR(svn_wc__db_wq_add(db, data.root_abspath, work_items, scratch_pool)); 2027251881Speter 2028251881Speter SVN_ERR(svn_wc__db_wclock_release(db, data.root_abspath, scratch_pool)); 2029251881Speter SVN_ERR(svn_wc__db_close(db)); 2030251881Speter 2031251881Speter /* Renaming the db file is what makes the pre-wcng into a wcng */ 2032251881Speter db_from = svn_wc__adm_child(data.root_abspath, SDB_FILE, scratch_pool); 2033251881Speter db_to = svn_wc__adm_child(local_abspath, SDB_FILE, scratch_pool); 2034362181Sdim SVN_ERR(svn_io_file_rename2(db_from, db_to, FALSE, scratch_pool)); 2035251881Speter 2036251881Speter /* Now we have a working wcng, tidy up the droppings */ 2037251881Speter SVN_ERR(svn_wc__db_open(&db, NULL /* ### config */, FALSE, FALSE, 2038251881Speter scratch_pool, scratch_pool)); 2039251881Speter SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton, 2040251881Speter scratch_pool)); 2041251881Speter SVN_ERR(svn_wc__db_close(db)); 2042251881Speter 2043251881Speter /* Should we have the workqueue remove this empty dir? */ 2044251881Speter SVN_ERR(svn_io_remove_dir2(data.root_abspath, FALSE, NULL, NULL, 2045251881Speter scratch_pool)); 2046251881Speter 2047251881Speter return SVN_NO_ERROR; 2048251881Speter} 2049251881Speter 2050251881Spetersvn_error_t * 2051251881Spetersvn_wc__upgrade_add_external_info(svn_wc_context_t *wc_ctx, 2052251881Speter const char *local_abspath, 2053251881Speter svn_node_kind_t kind, 2054251881Speter const char *def_local_abspath, 2055251881Speter const char *repos_relpath, 2056251881Speter const char *repos_root_url, 2057251881Speter const char *repos_uuid, 2058251881Speter svn_revnum_t def_peg_revision, 2059251881Speter svn_revnum_t def_revision, 2060251881Speter apr_pool_t *scratch_pool) 2061251881Speter{ 2062251881Speter svn_node_kind_t db_kind; 2063251881Speter switch (kind) 2064251881Speter { 2065251881Speter case svn_node_dir: 2066251881Speter db_kind = svn_node_dir; 2067251881Speter break; 2068251881Speter 2069251881Speter case svn_node_file: 2070251881Speter db_kind = svn_node_file; 2071251881Speter break; 2072251881Speter 2073251881Speter case svn_node_unknown: 2074251881Speter db_kind = svn_node_unknown; 2075251881Speter break; 2076251881Speter 2077251881Speter default: 2078251881Speter SVN_ERR_MALFUNCTION(); 2079251881Speter } 2080251881Speter 2081251881Speter SVN_ERR(svn_wc__db_upgrade_insert_external(wc_ctx->db, local_abspath, 2082251881Speter db_kind, 2083251881Speter svn_dirent_dirname(local_abspath, 2084251881Speter scratch_pool), 2085251881Speter def_local_abspath, repos_relpath, 2086251881Speter repos_root_url, repos_uuid, 2087251881Speter def_peg_revision, def_revision, 2088251881Speter scratch_pool)); 2089251881Speter return SVN_NO_ERROR; 2090251881Speter} 2091