2 * upgrade.c: routines for upgrading a working copy
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
24 #include <apr_pools.h>
26 #include "svn_types.h"
27 #include "svn_pools.h"
28 #include "svn_dirent_uri.h"
33 #include "adm_files.h"
34 #include "conflicts.h"
37 #include "tree_conflicts.h"
38 #include "wc-queries.h" /* for STMT_* */
39 #include "workqueue.h"
41 #include "svn_private_config.h"
42 #include "private/svn_wc_private.h"
43 #include "private/svn_sqlite.h"
44 #include "private/svn_token.h"
46 /* WC-1.0 administrative area extensions */
47 #define SVN_WC__BASE_EXT ".svn-base" /* for text and prop bases */
48 #define SVN_WC__WORK_EXT ".svn-work" /* for working propfiles */
49 #define SVN_WC__REVERT_EXT ".svn-revert" /* for reverting a replaced
52 /* Old locations for storing "wcprops" (aka "dav cache"). */
53 #define WCPROPS_SUBDIR_FOR_FILES "wcprops"
54 #define WCPROPS_FNAME_FOR_DIR "dir-wcprops"
55 #define WCPROPS_ALL_DATA "all-wcprops"
57 /* Old property locations. */
58 #define PROPS_SUBDIR "props"
59 #define PROP_BASE_SUBDIR "prop-base"
60 #define PROP_BASE_FOR_DIR "dir-prop-base"
61 #define PROP_REVERT_FOR_DIR "dir-prop-revert"
62 #define PROP_WORKING_FOR_DIR "dir-props"
64 /* Old textbase location. */
65 #define TEXT_BASE_SUBDIR "text-base"
67 #define TEMP_DIR "tmp"
69 /* Old data files that we no longer need/use. */
70 #define ADM_README "README.txt"
71 #define ADM_EMPTY_FILE "empty-file"
73 #define ADM_LOCK "lock"
75 /* New pristine location */
76 #define PRISTINE_STORAGE_RELPATH "pristine"
77 #define PRISTINE_STORAGE_EXT ".svn-base"
78 /* Number of characters in a pristine file basename, in WC format <= 28. */
79 #define PRISTINE_BASENAME_OLD_LEN 40
80 #define SDB_FILE "wc.db"
83 /* Read the properties from the file at PROPFILE_ABSPATH, returning them
84 as a hash in *PROPS. If the propfile is NOT present, then NULL will
85 be returned in *PROPS. */
87 read_propfile(apr_hash_t **props,
88 const char *propfile_abspath,
89 apr_pool_t *result_pool,
90 apr_pool_t *scratch_pool)
96 err = svn_io_stat(&finfo, propfile_abspath, APR_FINFO_SIZE, scratch_pool);
99 && (APR_STATUS_IS_ENOENT(err->apr_err)
100 || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)))
102 svn_error_clear(err);
104 /* The propfile was not there. Signal with a NULL. */
111 /* A 0-bytes file signals an empty property list.
112 (mostly used for revert-props) */
115 *props = apr_hash_make(result_pool);
119 SVN_ERR(svn_stream_open_readonly(&stream, propfile_abspath,
120 scratch_pool, scratch_pool));
122 /* ### does this function need to be smarter? will we see zero-length
123 ### files? see props.c::load_props(). there may be more work here.
124 ### need a historic analysis of 1.x property storage. what will we
125 ### actually run into? */
127 /* ### loggy_write_properties() and immediate_install_props() write
128 ### zero-length files for "no props", so we should be a bit smarter
131 /* ### should we be forgiving in here? I say "no". if we can't be sure,
132 ### then we could effectively corrupt the local working copy. */
134 *props = apr_hash_make(result_pool);
135 SVN_ERR(svn_hash_read2(*props, stream, SVN_HASH_TERMINATOR, result_pool));
137 return svn_error_trace(svn_stream_close(stream));
141 /* Read one proplist (allocated from RESULT_POOL) from STREAM, and place it
142 into ALL_WCPROPS at NAME. */
144 read_one_proplist(apr_hash_t *all_wcprops,
146 svn_stream_t *stream,
147 apr_pool_t *result_pool,
148 apr_pool_t *scratch_pool)
150 apr_hash_t *proplist;
152 proplist = apr_hash_make(result_pool);
153 SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, result_pool));
154 svn_hash_sets(all_wcprops, name, proplist);
160 /* Read the wcprops from all the files in the admin area of DIR_ABSPATH,
161 returning them in *ALL_WCPROPS. Results are allocated in RESULT_POOL,
162 and temporary allocations are performed in SCRATCH_POOL. */
164 read_many_wcprops(apr_hash_t **all_wcprops,
165 const char *dir_abspath,
166 apr_pool_t *result_pool,
167 apr_pool_t *scratch_pool)
169 const char *propfile_abspath;
172 const char *props_dir_abspath;
173 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
174 apr_hash_index_t *hi;
176 *all_wcprops = apr_hash_make(result_pool);
178 /* First, look at dir-wcprops. */
179 propfile_abspath = svn_wc__adm_child(dir_abspath, WCPROPS_FNAME_FOR_DIR,
181 SVN_ERR(read_propfile(&wcprops, propfile_abspath, result_pool, iterpool));
183 svn_hash_sets(*all_wcprops, SVN_WC_ENTRY_THIS_DIR, wcprops);
185 props_dir_abspath = svn_wc__adm_child(dir_abspath, WCPROPS_SUBDIR_FOR_FILES,
188 /* Now walk the wcprops directory. */
189 SVN_ERR(svn_io_get_dirents3(&dirents, props_dir_abspath, TRUE,
190 scratch_pool, scratch_pool));
192 for (hi = apr_hash_first(scratch_pool, dirents);
194 hi = apr_hash_next(hi))
196 const char *name = svn__apr_hash_index_key(hi);
198 svn_pool_clear(iterpool);
200 propfile_abspath = svn_dirent_join(props_dir_abspath, name, iterpool);
202 SVN_ERR(read_propfile(&wcprops, propfile_abspath,
203 result_pool, iterpool));
204 SVN_ERR_ASSERT(wcprops != NULL);
205 svn_hash_sets(*all_wcprops, apr_pstrdup(result_pool, name), wcprops);
208 svn_pool_destroy(iterpool);
213 /* For wcprops stored in a single file in this working copy, read that
214 file and return it in *ALL_WCPROPS, allocated in RESULT_POOL. Use
215 SCRATCH_POOL for temporary allocations. */
217 read_wcprops(apr_hash_t **all_wcprops,
218 const char *dir_abspath,
219 apr_pool_t *result_pool,
220 apr_pool_t *scratch_pool)
222 svn_stream_t *stream;
225 *all_wcprops = apr_hash_make(result_pool);
227 err = svn_wc__open_adm_stream(&stream, dir_abspath,
229 scratch_pool, scratch_pool);
231 /* A non-existent file means there are no props. */
232 if (err && APR_STATUS_IS_ENOENT(err->apr_err))
234 svn_error_clear(err);
239 /* Read the proplist for THIS_DIR. */
240 SVN_ERR(read_one_proplist(*all_wcprops, SVN_WC_ENTRY_THIS_DIR, stream,
241 result_pool, scratch_pool));
243 /* And now, the children. */
246 svn_stringbuf_t *line;
249 SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, result_pool));
253 return svn_error_createf
254 (SVN_ERR_WC_CORRUPT, NULL,
255 _("Missing end of line in wcprops file for '%s'"),
256 svn_dirent_local_style(dir_abspath, scratch_pool));
259 SVN_ERR(read_one_proplist(*all_wcprops, line->data, stream,
260 result_pool, scratch_pool));
263 return svn_error_trace(svn_stream_close(stream));
266 /* Return in CHILDREN, the list of all 1.6 versioned subdirectories
267 which also exist on disk as directories.
269 If DELETE_DIR is not NULL set *DELETE_DIR to TRUE if the directory
270 should be deleted after migrating to WC-NG, otherwise to FALSE.
272 If SKIP_MISSING is TRUE, don't add missing or obstructed subdirectories
273 to the list of children.
276 get_versioned_subdirs(apr_array_header_t **children,
277 svn_boolean_t *delete_dir,
278 const char *dir_abspath,
279 svn_boolean_t skip_missing,
280 apr_pool_t *result_pool,
281 apr_pool_t *scratch_pool)
283 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
285 apr_hash_index_t *hi;
286 svn_wc_entry_t *this_dir = NULL;
288 *children = apr_array_make(result_pool, 10, sizeof(const char *));
290 SVN_ERR(svn_wc__read_entries_old(&entries, dir_abspath,
291 scratch_pool, iterpool));
292 for (hi = apr_hash_first(scratch_pool, entries);
294 hi = apr_hash_next(hi))
296 const char *name = svn__apr_hash_index_key(hi);
297 const svn_wc_entry_t *entry = svn__apr_hash_index_val(hi);
298 const char *child_abspath;
299 svn_boolean_t hidden;
301 /* skip "this dir" */
304 this_dir = svn__apr_hash_index_val(hi);
307 else if (entry->kind != svn_node_dir)
310 svn_pool_clear(iterpool);
312 /* If a directory is 'hidden' skip it as subdir */
313 SVN_ERR(svn_wc__entry_is_hidden(&hidden, entry));
317 child_abspath = svn_dirent_join(dir_abspath, name, scratch_pool);
321 svn_node_kind_t kind;
322 SVN_ERR(svn_io_check_path(child_abspath, &kind, scratch_pool));
324 if (kind != svn_node_dir)
328 APR_ARRAY_PUSH(*children, const char *) = apr_pstrdup(result_pool,
332 svn_pool_destroy(iterpool);
334 if (delete_dir != NULL)
336 *delete_dir = (this_dir != NULL)
337 && (this_dir->schedule == svn_wc_schedule_delete)
338 && ! this_dir->keep_local;
345 /* Return in CHILDREN the names of all versioned *files* in SDB that
346 are children of PARENT_RELPATH. These files' existence on disk is
349 This set of children is intended for property upgrades.
350 Subdirectory's properties exist in the subdirs.
352 Note that this uses just the SDB to locate children, which means
353 that the children must have been upgraded to wc-ng format. */
355 get_versioned_files(const apr_array_header_t **children,
356 const char *parent_relpath,
357 svn_sqlite__db_t *sdb,
359 apr_pool_t *result_pool,
360 apr_pool_t *scratch_pool)
362 svn_sqlite__stmt_t *stmt;
363 apr_array_header_t *child_names;
364 svn_boolean_t have_row;
366 /* ### just select 'file' children. do we need 'symlink' in the future? */
367 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_ALL_FILES));
368 SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, parent_relpath));
370 /* ### 10 is based on Subversion's average of 8.5 files per versioned
371 ### directory in its repository. maybe use a different value? or
372 ### count rows first? */
373 child_names = apr_array_make(result_pool, 10, sizeof(const char *));
375 SVN_ERR(svn_sqlite__step(&have_row, stmt));
378 const char *local_relpath = svn_sqlite__column_text(stmt, 0,
381 APR_ARRAY_PUSH(child_names, const char *)
382 = svn_relpath_basename(local_relpath, result_pool);
384 SVN_ERR(svn_sqlite__step(&have_row, stmt));
387 *children = child_names;
389 return svn_error_trace(svn_sqlite__reset(stmt));
393 /* Return the path of the old-school administrative lock file
394 associated with LOCAL_DIR_ABSPATH, allocated from RESULT_POOL. */
396 build_lockfile_path(const char *local_dir_abspath,
397 apr_pool_t *result_pool)
399 return svn_dirent_join_many(result_pool,
401 svn_wc_get_adm_dir(result_pool),
407 /* Create a physical lock file in the admin directory for ABSPATH. */
409 create_physical_lock(const char *abspath, apr_pool_t *scratch_pool)
411 const char *lock_abspath = build_lockfile_path(abspath, scratch_pool);
415 err = svn_io_file_open(&file, lock_abspath,
416 APR_WRITE | APR_CREATE | APR_EXCL,
420 if (err && APR_STATUS_IS_EEXIST(err->apr_err))
422 /* Congratulations, we just stole a physical lock from somebody */
423 svn_error_clear(err);
427 return svn_error_trace(err);
431 /* Wipe out all the obsolete files/dirs from the administrative area. */
433 wipe_obsolete_files(const char *wcroot_abspath, apr_pool_t *scratch_pool)
435 /* Zap unused files. */
436 svn_error_clear(svn_io_remove_file2(
437 svn_wc__adm_child(wcroot_abspath,
440 TRUE, scratch_pool));
441 svn_error_clear(svn_io_remove_file2(
442 svn_wc__adm_child(wcroot_abspath,
445 TRUE, scratch_pool));
446 svn_error_clear(svn_io_remove_file2(
447 svn_wc__adm_child(wcroot_abspath,
450 TRUE, scratch_pool));
451 svn_error_clear(svn_io_remove_file2(
452 svn_wc__adm_child(wcroot_abspath,
455 TRUE, scratch_pool));
457 /* For formats <= SVN_WC__WCPROPS_MANY_FILES_VERSION, we toss the wcprops
458 for the directory itself, and then all the wcprops for the files. */
459 svn_error_clear(svn_io_remove_file2(
460 svn_wc__adm_child(wcroot_abspath,
461 WCPROPS_FNAME_FOR_DIR,
463 TRUE, scratch_pool));
464 svn_error_clear(svn_io_remove_dir2(
465 svn_wc__adm_child(wcroot_abspath,
466 WCPROPS_SUBDIR_FOR_FILES,
468 FALSE, NULL, NULL, scratch_pool));
470 /* And for later formats, they are aggregated into one file. */
471 svn_error_clear(svn_io_remove_file2(
472 svn_wc__adm_child(wcroot_abspath,
475 TRUE, scratch_pool));
477 /* Remove the old text-base directory and the old text-base files. */
478 svn_error_clear(svn_io_remove_dir2(
479 svn_wc__adm_child(wcroot_abspath,
482 FALSE, NULL, NULL, scratch_pool));
484 /* Remove the old properties files... whole directories at a time. */
485 svn_error_clear(svn_io_remove_dir2(
486 svn_wc__adm_child(wcroot_abspath,
489 FALSE, NULL, NULL, scratch_pool));
490 svn_error_clear(svn_io_remove_dir2(
491 svn_wc__adm_child(wcroot_abspath,
494 FALSE, NULL, NULL, scratch_pool));
495 svn_error_clear(svn_io_remove_file2(
496 svn_wc__adm_child(wcroot_abspath,
497 PROP_WORKING_FOR_DIR,
499 TRUE, scratch_pool));
500 svn_error_clear(svn_io_remove_file2(
501 svn_wc__adm_child(wcroot_abspath,
504 TRUE, scratch_pool));
505 svn_error_clear(svn_io_remove_file2(
506 svn_wc__adm_child(wcroot_abspath,
509 TRUE, scratch_pool));
512 /* ### this checks for a write-lock, and we are not (always) taking out
513 ### a write lock in all callers. */
514 SVN_ERR(svn_wc__adm_cleanup_tmp_area(db, wcroot_abspath, iterpool));
517 /* Remove the old-style lock file LAST. */
518 svn_error_clear(svn_io_remove_file2(
519 build_lockfile_path(wcroot_abspath, scratch_pool),
520 TRUE, scratch_pool));
524 svn_wc__wipe_postupgrade(const char *dir_abspath,
525 svn_boolean_t whole_admin,
526 svn_cancel_func_t cancel_func,
528 apr_pool_t *scratch_pool)
530 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
531 apr_array_header_t *subdirs;
533 svn_boolean_t delete_dir;
537 SVN_ERR((*cancel_func)(cancel_baton));
539 err = get_versioned_subdirs(&subdirs, &delete_dir, dir_abspath, TRUE,
540 scratch_pool, iterpool);
543 if (APR_STATUS_IS_ENOENT(err->apr_err))
545 /* An unversioned dir is obstructing a versioned dir */
546 svn_error_clear(err);
549 svn_pool_destroy(iterpool);
550 return svn_error_trace(err);
552 for (i = 0; i < subdirs->nelts; ++i)
554 const char *child_abspath = APR_ARRAY_IDX(subdirs, i, const char *);
556 svn_pool_clear(iterpool);
557 SVN_ERR(svn_wc__wipe_postupgrade(child_abspath, TRUE,
558 cancel_func, cancel_baton, iterpool));
561 /* ### Should we really be ignoring errors here? */
563 svn_error_clear(svn_io_remove_dir2(svn_wc__adm_child(dir_abspath, "",
565 TRUE, NULL, NULL, iterpool));
567 wipe_obsolete_files(dir_abspath, scratch_pool);
571 /* If this was a WC-NG single database copy, this directory wouldn't
572 be here (unless it was deleted with --keep-local)
574 If the directory is empty, we can just delete it; if not we
577 svn_error_clear(svn_io_dir_remove_nonrecursive(dir_abspath, iterpool));
580 svn_pool_destroy(iterpool);
585 /* Ensure that ENTRY has its REPOS and UUID fields set. These will be
586 used to establish the REPOSITORY row in the new database, and then
587 used within the upgraded entries as they are written into the database.
589 If one or both are not available, then it attempts to retrieve this
590 information from REPOS_CACHE. And if that fails from REPOS_INFO_FUNC,
591 passing REPOS_INFO_BATON.
592 Returns a user understandable error using LOCAL_ABSPATH if the
593 information cannot be obtained. */
595 ensure_repos_info(svn_wc_entry_t *entry,
596 const char *local_abspath,
597 svn_wc_upgrade_get_repos_info_t repos_info_func,
598 void *repos_info_baton,
599 apr_hash_t *repos_cache,
600 apr_pool_t *result_pool,
601 apr_pool_t *scratch_pool)
604 if (entry->repos != NULL && entry->uuid != NULL)
607 if ((entry->repos == NULL || entry->uuid == NULL)
610 apr_hash_index_t *hi;
612 for (hi = apr_hash_first(scratch_pool, repos_cache);
613 hi; hi = apr_hash_next(hi))
615 if (svn_uri__is_ancestor(svn__apr_hash_index_key(hi), entry->url))
618 entry->repos = svn__apr_hash_index_key(hi);
621 entry->uuid = svn__apr_hash_index_val(hi);
628 if (entry->repos == NULL && repos_info_func == NULL)
629 return svn_error_createf(
630 SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
631 _("Working copy '%s' can't be upgraded because the repository root is "
632 "not available and can't be retrieved"),
633 svn_dirent_local_style(local_abspath, scratch_pool));
635 if (entry->uuid == NULL && repos_info_func == NULL)
636 return svn_error_createf(
637 SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
638 _("Working copy '%s' can't be upgraded because the repository uuid is "
639 "not available and can't be retrieved"),
640 svn_dirent_local_style(local_abspath, scratch_pool));
642 if (entry->url == NULL)
643 return svn_error_createf(
644 SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
645 _("Working copy '%s' can't be upgraded because it doesn't have a url"),
646 svn_dirent_local_style(local_abspath, scratch_pool));
648 return svn_error_trace((*repos_info_func)(&entry->repos, &entry->uuid,
651 result_pool, scratch_pool));
656 * Read tree conflict descriptions from @a conflict_data. Set @a *conflicts
657 * to a hash of pointers to svn_wc_conflict_description2_t objects indexed by
658 * svn_wc_conflict_description2_t.local_abspath, all newly allocated in @a
659 * pool. @a dir_path is the path to the working copy directory whose conflicts
660 * are being read. The conflicts read are the tree conflicts on the immediate
661 * child nodes of @a dir_path. Do all allocations in @a pool.
663 * Note: There were some concerns about this function:
665 * ### this is BAD. the CONFLICTS structure should not be dependent upon
666 * ### DIR_PATH. each conflict should be labeled with an entry name, not
667 * ### a whole path. (and a path which happens to vary based upon invocation
668 * ### of the user client and these APIs)
670 * those assumptions were baked into former versions of the data model, so
671 * they have to stick around here. But they have been removed from the
674 read_tree_conflicts(apr_hash_t **conflicts,
675 const char *conflict_data,
676 const char *dir_path,
679 const svn_skel_t *skel;
680 apr_pool_t *iterpool;
682 *conflicts = apr_hash_make(pool);
684 if (conflict_data == NULL)
687 skel = svn_skel__parse(conflict_data, strlen(conflict_data), pool);
689 return svn_error_create(SVN_ERR_WC_CORRUPT, NULL,
690 _("Error parsing tree conflict skel"));
692 iterpool = svn_pool_create(pool);
693 for (skel = skel->children; skel != NULL; skel = skel->next)
695 const svn_wc_conflict_description2_t *conflict;
697 svn_pool_clear(iterpool);
698 SVN_ERR(svn_wc__deserialize_conflict(&conflict, skel, dir_path,
700 if (conflict != NULL)
701 svn_hash_sets(*conflicts,
702 svn_dirent_basename(conflict->local_abspath, pool),
705 svn_pool_destroy(iterpool);
712 migrate_single_tree_conflict_data(svn_sqlite__db_t *sdb,
713 const char *tree_conflict_data,
715 const char *local_relpath,
716 apr_pool_t *scratch_pool)
718 apr_hash_t *conflicts;
719 apr_hash_index_t *hi;
720 apr_pool_t *iterpool;
722 SVN_ERR(read_tree_conflicts(&conflicts, tree_conflict_data, local_relpath,
725 iterpool = svn_pool_create(scratch_pool);
726 for (hi = apr_hash_first(scratch_pool, conflicts);
728 hi = apr_hash_next(hi))
730 const svn_wc_conflict_description2_t *conflict =
731 svn__apr_hash_index_val(hi);
732 const char *conflict_relpath;
733 const char *conflict_data;
734 svn_sqlite__stmt_t *stmt;
735 svn_boolean_t have_row;
738 svn_pool_clear(iterpool);
740 conflict_relpath = svn_dirent_join(local_relpath,
742 conflict->local_abspath, iterpool),
745 SVN_ERR(svn_wc__serialize_conflict(&skel, conflict, iterpool, iterpool));
746 conflict_data = svn_skel__unparse(skel, iterpool)->data;
748 /* See if we need to update or insert an ACTUAL node. */
749 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_ACTUAL_NODE));
750 SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, conflict_relpath));
751 SVN_ERR(svn_sqlite__step(&have_row, stmt));
752 SVN_ERR(svn_sqlite__reset(stmt));
756 /* There is an existing ACTUAL row, so just update it. */
757 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
758 STMT_UPDATE_ACTUAL_CONFLICT_DATA));
762 /* We need to insert an ACTUAL row with the tree conflict data. */
763 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
764 STMT_INSERT_ACTUAL_CONFLICT_DATA));
767 SVN_ERR(svn_sqlite__bindf(stmt, "iss", wc_id, conflict_relpath,
770 SVN_ERR(svn_sqlite__bind_text(stmt, 4, local_relpath));
772 SVN_ERR(svn_sqlite__step_done(stmt));
775 svn_pool_destroy(iterpool);
783 migrate_tree_conflict_data(svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
785 svn_sqlite__stmt_t *stmt;
786 svn_boolean_t have_row;
787 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
789 /* Iterate over each node which has a set of tree conflicts, then insert
790 all of them into the new schema. */
792 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
793 STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT));
795 /* Get all the existing tree conflict data. */
796 SVN_ERR(svn_sqlite__step(&have_row, stmt));
800 const char *local_relpath;
801 const char *tree_conflict_data;
803 svn_pool_clear(iterpool);
805 wc_id = svn_sqlite__column_int64(stmt, 0);
806 local_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
807 tree_conflict_data = svn_sqlite__column_text(stmt, 2, iterpool);
809 SVN_ERR(migrate_single_tree_conflict_data(sdb, tree_conflict_data,
810 wc_id, local_relpath,
813 /* We don't need to do anything but step over the previously
814 prepared statement. */
815 SVN_ERR(svn_sqlite__step(&have_row, stmt));
817 SVN_ERR(svn_sqlite__reset(stmt));
819 /* Erase all the old tree conflict data. */
820 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
821 STMT_UPGRADE_21_ERASE_OLD_CONFLICTS));
822 SVN_ERR(svn_sqlite__step_done(stmt));
824 svn_pool_destroy(iterpool);
830 const char *wcroot_abspath;
833 /* Migrate the properties for one node (LOCAL_ABSPATH). */
835 migrate_node_props(const char *dir_abspath,
836 const char *new_wcroot_abspath,
838 svn_sqlite__db_t *sdb,
841 apr_pool_t *scratch_pool)
843 const char *base_abspath; /* old name. nowadays: "pristine" */
844 const char *revert_abspath; /* old name. nowadays: "BASE" */
845 const char *working_abspath; /* old name. nowadays: "ACTUAL" */
846 apr_hash_t *base_props;
847 apr_hash_t *revert_props;
848 apr_hash_t *working_props;
849 const char *old_wcroot_abspath
850 = svn_dirent_get_longest_ancestor(dir_abspath, new_wcroot_abspath,
852 const char *dir_relpath = svn_dirent_skip_ancestor(old_wcroot_abspath,
857 base_abspath = svn_wc__adm_child(dir_abspath,
858 PROP_BASE_FOR_DIR, scratch_pool);
859 revert_abspath = svn_wc__adm_child(dir_abspath,
860 PROP_REVERT_FOR_DIR, scratch_pool);
861 working_abspath = svn_wc__adm_child(dir_abspath,
862 PROP_WORKING_FOR_DIR, scratch_pool);
866 const char *basedir_abspath;
867 const char *propsdir_abspath;
869 propsdir_abspath = svn_wc__adm_child(dir_abspath, PROPS_SUBDIR,
871 basedir_abspath = svn_wc__adm_child(dir_abspath, PROP_BASE_SUBDIR,
874 base_abspath = svn_dirent_join(basedir_abspath,
875 apr_pstrcat(scratch_pool,
881 revert_abspath = svn_dirent_join(basedir_abspath,
882 apr_pstrcat(scratch_pool,
888 working_abspath = svn_dirent_join(propsdir_abspath,
889 apr_pstrcat(scratch_pool,
896 SVN_ERR(read_propfile(&base_props, base_abspath,
897 scratch_pool, scratch_pool));
898 SVN_ERR(read_propfile(&revert_props, revert_abspath,
899 scratch_pool, scratch_pool));
900 SVN_ERR(read_propfile(&working_props, working_abspath,
901 scratch_pool, scratch_pool));
903 return svn_error_trace(svn_wc__db_upgrade_apply_props(
904 sdb, new_wcroot_abspath,
905 svn_relpath_join(dir_relpath, name, scratch_pool),
906 base_props, revert_props, working_props,
907 original_format, wc_id,
914 migrate_props(const char *dir_abspath,
915 const char *new_wcroot_abspath,
916 svn_sqlite__db_t *sdb,
919 apr_pool_t *scratch_pool)
921 /* General logic here: iterate over all the immediate children of the root
922 (since we aren't yet in a centralized system), and for any properties that
923 exist, map them as follows:
925 if (revert props exist):
929 else if (prop pristine is working [as defined in props.c] ):
936 ### the middle "test" should simply look for a WORKING_NODE row
938 Note that it is legal for "working" props to be missing. That implies
939 no local changes to the properties.
941 const apr_array_header_t *children;
942 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
943 const char *old_wcroot_abspath
944 = svn_dirent_get_longest_ancestor(dir_abspath, new_wcroot_abspath,
946 const char *dir_relpath = svn_dirent_skip_ancestor(old_wcroot_abspath,
950 /* Migrate the props for "this dir". */
951 SVN_ERR(migrate_node_props(dir_abspath, new_wcroot_abspath, "", sdb,
952 original_format, wc_id, iterpool));
954 /* Iterate over all the files in this SDB. */
955 SVN_ERR(get_versioned_files(&children, dir_relpath, sdb, wc_id, scratch_pool,
957 for (i = 0; i < children->nelts; i++)
959 const char *name = APR_ARRAY_IDX(children, i, const char *);
961 svn_pool_clear(iterpool);
963 SVN_ERR(migrate_node_props(dir_abspath, new_wcroot_abspath,
964 name, sdb, original_format, wc_id, iterpool));
967 svn_pool_destroy(iterpool);
973 /* If STR ends with SUFFIX and is longer than SUFFIX, return the part of
974 * STR that comes before SUFFIX; else return NULL. */
976 remove_suffix(const char *str, const char *suffix, apr_pool_t *result_pool)
978 size_t str_len = strlen(str);
979 size_t suffix_len = strlen(suffix);
981 if (str_len > suffix_len
982 && strcmp(str + str_len - suffix_len, suffix) == 0)
984 return apr_pstrmemdup(result_pool, str, str_len - suffix_len);
990 /* Copy all the text-base files from the administrative area of WC directory
991 DIR_ABSPATH into the pristine store of SDB which is located in directory
994 Set *TEXT_BASES_INFO to a new hash, allocated in RESULT_POOL, that maps
995 (const char *) name of the versioned file to (svn_wc__text_base_info_t *)
996 information about the pristine text. */
998 migrate_text_bases(apr_hash_t **text_bases_info,
999 const char *dir_abspath,
1000 const char *new_wcroot_abspath,
1001 svn_sqlite__db_t *sdb,
1002 apr_pool_t *result_pool,
1003 apr_pool_t *scratch_pool)
1005 apr_hash_t *dirents;
1006 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
1007 apr_hash_index_t *hi;
1008 const char *text_base_dir = svn_wc__adm_child(dir_abspath,
1012 *text_bases_info = apr_hash_make(result_pool);
1014 /* Iterate over the text-base files */
1015 SVN_ERR(svn_io_get_dirents3(&dirents, text_base_dir, TRUE,
1016 scratch_pool, scratch_pool));
1017 for (hi = apr_hash_first(scratch_pool, dirents); hi;
1018 hi = apr_hash_next(hi))
1020 const char *text_base_basename = svn__apr_hash_index_key(hi);
1021 svn_checksum_t *md5_checksum;
1022 svn_checksum_t *sha1_checksum;
1024 svn_pool_clear(iterpool);
1026 /* Calculate its checksums and copy it to the pristine store */
1028 const char *pristine_path;
1029 const char *text_base_path;
1030 const char *temp_path;
1031 svn_sqlite__stmt_t *stmt;
1033 svn_stream_t *read_stream;
1034 svn_stream_t *result_stream;
1036 text_base_path = svn_dirent_join(text_base_dir, text_base_basename,
1039 /* Create a copy and calculate a checksum in one step */
1040 SVN_ERR(svn_stream_open_unique(&result_stream, &temp_path,
1042 svn_io_file_del_none,
1043 iterpool, iterpool));
1045 SVN_ERR(svn_stream_open_readonly(&read_stream, text_base_path,
1046 iterpool, iterpool));
1048 read_stream = svn_stream_checksummed2(read_stream, &md5_checksum,
1049 NULL, svn_checksum_md5,
1052 read_stream = svn_stream_checksummed2(read_stream, &sha1_checksum,
1053 NULL, svn_checksum_sha1,
1056 /* This calculates the hash, creates a copy and closes the stream */
1057 SVN_ERR(svn_stream_copy3(read_stream, result_stream,
1058 NULL, NULL, iterpool));
1060 SVN_ERR(svn_io_stat(&finfo, text_base_path, APR_FINFO_SIZE, iterpool));
1062 /* Insert a row into the pristine table. */
1063 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1064 STMT_INSERT_OR_IGNORE_PRISTINE));
1065 SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, iterpool));
1066 SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, iterpool));
1067 SVN_ERR(svn_sqlite__bind_int64(stmt, 3, finfo.size));
1068 SVN_ERR(svn_sqlite__insert(NULL, stmt));
1070 SVN_ERR(svn_wc__db_pristine_get_future_path(&pristine_path,
1073 iterpool, iterpool));
1075 /* Ensure any sharding directories exist. */
1076 SVN_ERR(svn_wc__ensure_directory(svn_dirent_dirname(pristine_path,
1080 /* Now move the file into the pristine store, overwriting
1081 existing files with the same checksum. */
1082 SVN_ERR(svn_io_file_move(temp_path, pristine_path, iterpool));
1085 /* Add the checksums for this text-base to *TEXT_BASES_INFO. */
1087 const char *versioned_file_name;
1088 svn_boolean_t is_revert_base;
1089 svn_wc__text_base_info_t *info;
1090 svn_wc__text_base_file_info_t *file_info;
1092 /* Determine the versioned file name and whether this is a normal base
1093 * or a revert base. */
1094 versioned_file_name = remove_suffix(text_base_basename,
1095 SVN_WC__REVERT_EXT, result_pool);
1096 if (versioned_file_name)
1098 is_revert_base = TRUE;
1102 versioned_file_name = remove_suffix(text_base_basename,
1103 SVN_WC__BASE_EXT, result_pool);
1104 is_revert_base = FALSE;
1107 if (! versioned_file_name)
1109 /* Some file that doesn't end with .svn-base or .svn-revert.
1110 No idea why that would be in our administrative area, but
1111 we shouldn't segfault on this case.
1113 Note that we already copied this file in the pristine store,
1114 but the next cleanup will take care of that.
1119 /* Create a new info struct for this versioned file, or fill in the
1120 * existing one if this is the second text-base we've found for it. */
1121 info = svn_hash_gets(*text_bases_info, versioned_file_name);
1123 info = apr_pcalloc(result_pool, sizeof (*info));
1124 file_info = (is_revert_base ? &info->revert_base : &info->normal_base);
1126 file_info->sha1_checksum = svn_checksum_dup(sha1_checksum, result_pool);
1127 file_info->md5_checksum = svn_checksum_dup(md5_checksum, result_pool);
1128 svn_hash_sets(*text_bases_info, versioned_file_name, info);
1132 svn_pool_destroy(iterpool);
1134 return SVN_NO_ERROR;
1137 static svn_error_t *
1138 bump_to_20(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1140 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_NODES));
1141 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_20));
1142 return SVN_NO_ERROR;
1145 static svn_error_t *
1146 bump_to_21(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1148 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_21));
1149 SVN_ERR(migrate_tree_conflict_data(sdb, scratch_pool));
1150 return SVN_NO_ERROR;
1153 static svn_error_t *
1154 bump_to_22(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1156 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_22));
1157 return SVN_NO_ERROR;
1160 static svn_error_t *
1161 bump_to_23(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1163 const char *wcroot_abspath = ((struct bump_baton *)baton)->wcroot_abspath;
1164 svn_sqlite__stmt_t *stmt;
1165 svn_boolean_t have_row;
1167 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1168 STMT_UPGRADE_23_HAS_WORKING_NODES));
1169 SVN_ERR(svn_sqlite__step(&have_row, stmt));
1170 SVN_ERR(svn_sqlite__reset(stmt));
1172 return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
1173 _("The working copy at '%s' is format 22 with "
1174 "WORKING nodes; use a format 22 client to "
1175 "diff/revert before using this client"),
1178 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_23));
1179 return SVN_NO_ERROR;
1182 static svn_error_t *
1183 bump_to_24(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1185 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_24));
1186 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_NODES_TRIGGERS));
1187 return SVN_NO_ERROR;
1190 static svn_error_t *
1191 bump_to_25(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1193 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_25));
1194 return SVN_NO_ERROR;
1197 static svn_error_t *
1198 bump_to_26(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1200 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_26));
1201 return SVN_NO_ERROR;
1204 static svn_error_t *
1205 bump_to_27(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1207 const char *wcroot_abspath = ((struct bump_baton *)baton)->wcroot_abspath;
1208 svn_sqlite__stmt_t *stmt;
1209 svn_boolean_t have_row;
1211 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1212 STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS));
1213 SVN_ERR(svn_sqlite__step(&have_row, stmt));
1214 SVN_ERR(svn_sqlite__reset(stmt));
1216 return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
1217 _("The working copy at '%s' is format 26 with "
1218 "conflicts; use a format 26 client to resolve "
1219 "before using this client"),
1221 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_27));
1222 return SVN_NO_ERROR;
1225 static svn_error_t *
1226 bump_to_28(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1228 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_28));
1229 return SVN_NO_ERROR;
1232 /* If FINFO indicates that ABSPATH names a file, rename it to
1233 * '<ABSPATH>.svn-base'.
1235 * Ignore any file whose name is not the expected length, in order to make
1236 * life easier for any developer who runs this code twice or has some
1237 * non-standard files in the pristine directory.
1239 * A callback for bump_to_29(), implementing #svn_io_walk_func_t. */
1240 static svn_error_t *
1241 rename_pristine_file(void *baton,
1242 const char *abspath,
1243 const apr_finfo_t *finfo,
1246 if (finfo->filetype == APR_REG
1247 && (strlen(svn_dirent_basename(abspath, pool))
1248 == PRISTINE_BASENAME_OLD_LEN))
1250 const char *new_abspath
1251 = apr_pstrcat(pool, abspath, PRISTINE_STORAGE_EXT, (char *)NULL);
1253 SVN_ERR(svn_io_file_rename(abspath, new_abspath, pool));
1255 return SVN_NO_ERROR;
1258 static svn_error_t *
1259 upgrade_externals(struct bump_baton *bb,
1260 svn_sqlite__db_t *sdb,
1261 apr_pool_t *scratch_pool)
1263 svn_sqlite__stmt_t *stmt;
1264 svn_sqlite__stmt_t *stmt_add;
1265 svn_boolean_t have_row;
1266 apr_pool_t *iterpool;
1268 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1269 STMT_SELECT_EXTERNAL_PROPERTIES));
1271 SVN_ERR(svn_sqlite__get_statement(&stmt_add, sdb,
1272 STMT_INSERT_EXTERNAL));
1274 /* ### For this intermediate upgrade we just assume WC_ID = 1.
1275 ### Before this bump we lost track of externals all the time,
1276 ### so lets keep this easy. */
1277 SVN_ERR(svn_sqlite__bindf(stmt, "is", (apr_int64_t)1, ""));
1279 SVN_ERR(svn_sqlite__step(&have_row, stmt));
1281 iterpool = svn_pool_create(scratch_pool);
1285 const char *externals;
1287 svn_pool_clear(iterpool);
1289 SVN_ERR(svn_sqlite__column_properties(&props, stmt, 0,
1290 iterpool, iterpool));
1292 externals = svn_prop_get_value(props, SVN_PROP_EXTERNALS);
1296 apr_array_header_t *ext;
1297 const char *local_relpath;
1298 const char *local_abspath;
1301 local_relpath = svn_sqlite__column_text(stmt, 1, NULL);
1302 local_abspath = svn_dirent_join(bb->wcroot_abspath, local_relpath,
1305 SVN_ERR(svn_wc_parse_externals_description3(&ext, local_abspath,
1309 for (i = 0; i < ext->nelts; i++)
1311 const svn_wc_external_item2_t *item;
1312 const char *item_relpath;
1314 item = APR_ARRAY_IDX(ext, i, const svn_wc_external_item2_t *);
1315 item_relpath = svn_relpath_join(local_relpath, item->target_dir,
1318 /* Insert dummy externals definitions: Insert an unknown
1319 external, to make sure it will be cleaned up when it is not
1320 updated on the next update. */
1321 SVN_ERR(svn_sqlite__bindf(stmt_add, "isssssis",
1322 (apr_int64_t)1, /* wc_id */
1324 svn_relpath_dirname(item_relpath,
1329 (apr_int64_t)1, /* repos_id */
1330 "" /* repos_relpath */));
1331 SVN_ERR(svn_sqlite__insert(NULL, stmt_add));
1335 SVN_ERR(svn_sqlite__step(&have_row, stmt));
1338 svn_pool_destroy(iterpool);
1339 return svn_error_trace(svn_sqlite__reset(stmt));
1342 static svn_error_t *
1343 bump_to_29(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1345 struct bump_baton *bb = baton;
1346 const char *wcroot_abspath = bb->wcroot_abspath;
1347 const char *pristine_dir_abspath;
1349 /* Rename all pristine files, adding a ".svn-base" suffix. */
1350 pristine_dir_abspath = svn_dirent_join_many(scratch_pool, wcroot_abspath,
1351 svn_wc_get_adm_dir(scratch_pool),
1352 PRISTINE_STORAGE_RELPATH, NULL);
1353 SVN_ERR(svn_io_dir_walk2(pristine_dir_abspath, APR_FINFO_MIN,
1354 rename_pristine_file, NULL, scratch_pool));
1357 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_EXTERNALS));
1359 SVN_ERR(upgrade_externals(bb, sdb, scratch_pool));
1360 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_29));
1361 return SVN_NO_ERROR;
1365 svn_wc__upgrade_conflict_skel_from_raw(svn_skel_t **conflicts,
1367 const char *wri_abspath,
1368 const char *local_relpath,
1369 const char *conflict_old,
1370 const char *conflict_wrk,
1371 const char *conflict_new,
1372 const char *prej_file,
1373 const char *tree_conflict_data,
1374 apr_size_t tree_conflict_len,
1375 apr_pool_t *result_pool,
1376 apr_pool_t *scratch_pool)
1378 svn_skel_t *conflict_data = NULL;
1379 const char *wcroot_abspath;
1381 SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, db, wri_abspath,
1382 scratch_pool, scratch_pool));
1384 if (conflict_old || conflict_new || conflict_wrk)
1386 const char *old_abspath = NULL;
1387 const char *new_abspath = NULL;
1388 const char *wrk_abspath = NULL;
1390 conflict_data = svn_wc__conflict_skel_create(result_pool);
1393 old_abspath = svn_dirent_join(wcroot_abspath, conflict_old,
1397 new_abspath = svn_dirent_join(wcroot_abspath, conflict_new,
1401 wrk_abspath = svn_dirent_join(wcroot_abspath, conflict_wrk,
1404 SVN_ERR(svn_wc__conflict_skel_add_text_conflict(conflict_data,
1415 const char *prej_abspath;
1418 conflict_data = svn_wc__conflict_skel_create(result_pool);
1420 prej_abspath = svn_dirent_join(wcroot_abspath, prej_file, scratch_pool);
1422 SVN_ERR(svn_wc__conflict_skel_add_prop_conflict(conflict_data,
1426 apr_hash_make(scratch_pool),
1431 if (tree_conflict_data)
1433 svn_skel_t *tc_skel;
1434 const svn_wc_conflict_description2_t *tc;
1435 const char *local_abspath;
1438 conflict_data = svn_wc__conflict_skel_create(scratch_pool);
1440 tc_skel = svn_skel__parse(tree_conflict_data, tree_conflict_len,
1443 local_abspath = svn_dirent_join(wcroot_abspath, local_relpath,
1446 SVN_ERR(svn_wc__deserialize_conflict(&tc, tc_skel,
1447 svn_dirent_dirname(local_abspath,
1449 scratch_pool, scratch_pool));
1451 SVN_ERR(svn_wc__conflict_skel_add_tree_conflict(conflict_data,
1459 switch (tc->operation)
1461 case svn_wc_operation_update:
1463 SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_data,
1464 tc->src_left_version,
1465 tc->src_right_version,
1469 case svn_wc_operation_switch:
1470 SVN_ERR(svn_wc__conflict_skel_set_op_switch(conflict_data,
1471 tc->src_left_version,
1472 tc->src_right_version,
1476 case svn_wc_operation_merge:
1477 SVN_ERR(svn_wc__conflict_skel_set_op_merge(conflict_data,
1478 tc->src_left_version,
1479 tc->src_right_version,
1485 else if (conflict_data)
1487 SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_data, NULL, NULL,
1492 *conflicts = conflict_data;
1493 return SVN_NO_ERROR;
1496 /* Helper function to upgrade a single conflict from bump_to_30 */
1497 static svn_error_t *
1498 bump_30_upgrade_one_conflict(svn_wc__db_t *wc_db,
1499 const char *wcroot_abspath,
1500 svn_sqlite__stmt_t *stmt,
1501 svn_sqlite__db_t *sdb,
1502 apr_pool_t *scratch_pool)
1504 svn_sqlite__stmt_t *stmt_store;
1505 svn_stringbuf_t *skel_data;
1506 svn_skel_t *conflict_data;
1507 apr_int64_t wc_id = svn_sqlite__column_int64(stmt, 0);
1508 const char *local_relpath = svn_sqlite__column_text(stmt, 1, NULL);
1509 const char *conflict_old = svn_sqlite__column_text(stmt, 2, NULL);
1510 const char *conflict_wrk = svn_sqlite__column_text(stmt, 3, NULL);
1511 const char *conflict_new = svn_sqlite__column_text(stmt, 4, NULL);
1512 const char *prop_reject = svn_sqlite__column_text(stmt, 5, NULL);
1513 apr_size_t tree_conflict_size;
1514 const char *tree_conflict_data = svn_sqlite__column_blob(stmt, 6,
1515 &tree_conflict_size, NULL);
1517 SVN_ERR(svn_wc__upgrade_conflict_skel_from_raw(&conflict_data,
1518 wc_db, wcroot_abspath,
1526 scratch_pool, scratch_pool));
1528 SVN_ERR_ASSERT(conflict_data != NULL);
1530 skel_data = svn_skel__unparse(conflict_data, scratch_pool);
1532 SVN_ERR(svn_sqlite__get_statement(&stmt_store, sdb,
1533 STMT_UPGRADE_30_SET_CONFLICT));
1534 SVN_ERR(svn_sqlite__bindf(stmt_store, "isb", wc_id, local_relpath,
1535 skel_data->data, skel_data->len));
1536 SVN_ERR(svn_sqlite__step_done(stmt_store));
1538 return SVN_NO_ERROR;
1541 static svn_error_t *
1542 bump_to_30(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1544 struct bump_baton *bb = baton;
1545 svn_boolean_t have_row;
1546 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
1547 svn_sqlite__stmt_t *stmt;
1548 svn_wc__db_t *db; /* Read only temp db */
1550 SVN_ERR(svn_wc__db_open(&db, NULL, TRUE /* open_without_upgrade */, FALSE,
1551 scratch_pool, scratch_pool));
1553 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1554 STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE));
1555 SVN_ERR(svn_sqlite__step(&have_row, stmt));
1560 svn_pool_clear(iterpool);
1562 err = bump_30_upgrade_one_conflict(db, bb->wcroot_abspath, stmt, sdb,
1567 return svn_error_trace(
1568 svn_error_compose_create(
1570 svn_sqlite__reset(stmt)));
1573 SVN_ERR(svn_sqlite__step(&have_row, stmt));
1575 SVN_ERR(svn_sqlite__reset(stmt));
1577 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_30));
1578 SVN_ERR(svn_wc__db_close(db));
1579 return SVN_NO_ERROR;
1582 static svn_error_t *
1583 bump_to_31(void *baton,
1584 svn_sqlite__db_t *sdb,
1585 apr_pool_t *scratch_pool)
1587 svn_sqlite__stmt_t *stmt, *stmt_mark_switch_roots;
1588 svn_boolean_t have_row;
1589 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
1590 apr_array_header_t *empty_iprops = apr_array_make(
1591 scratch_pool, 0, sizeof(svn_prop_inherited_item_t *));
1592 svn_boolean_t iprops_column_exists = FALSE;
1595 /* Add the inherited_props column to NODES if it does not yet exist.
1597 * When using a format >= 31 client to upgrade from old formats which
1598 * did not yet have a NODES table, the inherited_props column has
1599 * already been created as part of the NODES table. Attemping to add
1600 * the inherited_props column will raise an error in this case, so check
1601 * if the column exists first.
1603 * Checking for the existence of a column before ALTER TABLE is not
1604 * possible within SQLite. We need to run a separate query and evaluate
1605 * its result in C first.
1607 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_PRAGMA_TABLE_INFO_NODES));
1608 SVN_ERR(svn_sqlite__step(&have_row, stmt));
1611 const char *column_name = svn_sqlite__column_text(stmt, 1, NULL);
1613 if (strcmp(column_name, "inherited_props") == 0)
1615 iprops_column_exists = TRUE;
1619 SVN_ERR(svn_sqlite__step(&have_row, stmt));
1621 SVN_ERR(svn_sqlite__reset(stmt));
1622 if (!iprops_column_exists)
1623 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_31_ALTER_TABLE));
1625 /* Run additional statements to finalize the upgrade to format 31. */
1626 SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_31_FINALIZE));
1628 /* Set inherited_props to an empty array for the roots of all
1629 switched subtrees in the WC. This allows subsequent updates
1630 to recognize these roots as needing an iprops cache. */
1631 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1632 STMT_UPGRADE_31_SELECT_WCROOT_NODES));
1633 SVN_ERR(svn_sqlite__step(&have_row, stmt));
1635 err = svn_sqlite__get_statement(&stmt_mark_switch_roots, sdb,
1638 return svn_error_compose_create(err, svn_sqlite__reset(stmt));
1642 const char *switched_relpath = svn_sqlite__column_text(stmt, 1, NULL);
1643 apr_int64_t wc_id = svn_sqlite__column_int64(stmt, 0);
1645 err = svn_sqlite__bindf(stmt_mark_switch_roots, "is", wc_id,
1648 err = svn_sqlite__bind_iprops(stmt_mark_switch_roots, 3,
1649 empty_iprops, iterpool);
1651 err = svn_sqlite__step_done(stmt_mark_switch_roots);
1653 err = svn_sqlite__step(&have_row, stmt);
1656 return svn_error_compose_create(
1658 svn_error_compose_create(
1659 /* Reset in either order is OK. */
1660 svn_sqlite__reset(stmt),
1661 svn_sqlite__reset(stmt_mark_switch_roots)));
1664 err = svn_sqlite__reset(stmt_mark_switch_roots);
1666 return svn_error_compose_create(err, svn_sqlite__reset(stmt));
1667 SVN_ERR(svn_sqlite__reset(stmt));
1669 svn_pool_destroy(iterpool);
1671 return SVN_NO_ERROR;
1675 struct upgrade_data_t {
1676 svn_sqlite__db_t *sdb;
1677 const char *root_abspath;
1678 apr_int64_t repos_id;
1682 /* Upgrade the working copy directory represented by DB/DIR_ABSPATH
1683 from OLD_FORMAT to the wc-ng format (SVN_WC__WC_NG_VERSION)'.
1685 Pass REPOS_INFO_FUNC, REPOS_INFO_BATON and REPOS_CACHE to
1686 ensure_repos_info. Add the found repository root and UUID to
1687 REPOS_CACHE if it doesn't have a cached entry for this
1690 *DATA refers to the single root db.
1692 Uses SCRATCH_POOL for all temporary allocation. */
1693 static svn_error_t *
1694 upgrade_to_wcng(void **dir_baton,
1697 const char *dir_abspath,
1700 svn_wc_upgrade_get_repos_info_t repos_info_func,
1701 void *repos_info_baton,
1702 apr_hash_t *repos_cache,
1703 const struct upgrade_data_t *data,
1704 apr_pool_t *result_pool,
1705 apr_pool_t *scratch_pool)
1707 const char *logfile_path = svn_wc__adm_child(dir_abspath, ADM_LOG,
1709 svn_node_kind_t logfile_on_disk_kind;
1710 apr_hash_t *entries;
1711 svn_wc_entry_t *this_dir;
1712 const char *old_wcroot_abspath, *dir_relpath;
1713 apr_hash_t *text_bases_info;
1716 /* Don't try to mess with the WC if there are old log files left. */
1718 /* Is the (first) log file present? */
1719 SVN_ERR(svn_io_check_path(logfile_path, &logfile_on_disk_kind,
1721 if (logfile_on_disk_kind == svn_node_file)
1722 return svn_error_create(SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
1723 _("Cannot upgrade with existing logs; run a "
1724 "cleanup operation on this working copy using "
1725 "a client version which is compatible with this "
1726 "working copy's format (such as the version "
1727 "you are upgrading from), then retry the "
1728 "upgrade with the current version"));
1730 /* Lock this working copy directory, or steal an existing lock. Do this
1731 BEFORE we read the entries. We don't want another process to modify the
1732 entries after we've read them into memory. */
1733 SVN_ERR(create_physical_lock(dir_abspath, scratch_pool));
1735 /* What's going on here?
1737 * We're attempting to upgrade an older working copy to the new wc-ng format.
1738 * The semantics and storage mechanisms between the two are vastly different,
1739 * so it's going to be a bit painful. Here's a plan for the operation:
1741 * 1) Read the old 'entries' using the old-format reader.
1743 * 2) Create the new DB if it hasn't already been created.
1745 * 3) Use our compatibility code for writing entries to fill out the (new)
1746 * DB state. Use the remembered checksums, since an entry has only the
1747 * MD5 not the SHA1 checksum, and in the case of a revert-base doesn't
1750 * 4) Convert wcprop to the wc-ng format
1752 * 5) Migrate regular properties to the WC-NG DB.
1755 /***** ENTRIES - READ *****/
1756 SVN_ERR(svn_wc__read_entries_old(&entries, dir_abspath,
1757 scratch_pool, scratch_pool));
1759 this_dir = svn_hash_gets(entries, SVN_WC_ENTRY_THIS_DIR);
1760 SVN_ERR(ensure_repos_info(this_dir, dir_abspath,
1761 repos_info_func, repos_info_baton,
1763 scratch_pool, scratch_pool));
1765 /* Cache repos UUID pairs for when a subdir doesn't have this information */
1766 if (!svn_hash_gets(repos_cache, this_dir->repos))
1768 apr_pool_t *hash_pool = apr_hash_pool_get(repos_cache);
1770 svn_hash_sets(repos_cache,
1771 apr_pstrdup(hash_pool, this_dir->repos),
1772 apr_pstrdup(hash_pool, this_dir->uuid));
1775 old_wcroot_abspath = svn_dirent_get_longest_ancestor(dir_abspath,
1778 dir_relpath = svn_dirent_skip_ancestor(old_wcroot_abspath, dir_abspath);
1780 /***** TEXT BASES *****/
1781 SVN_ERR(migrate_text_bases(&text_bases_info, dir_abspath, data->root_abspath,
1782 data->sdb, scratch_pool, scratch_pool));
1784 /***** ENTRIES - WRITE *****/
1785 err = svn_wc__write_upgraded_entries(dir_baton, parent_baton, db, data->sdb,
1786 data->repos_id, data->wc_id,
1787 dir_abspath, data->root_abspath,
1788 entries, text_bases_info,
1789 result_pool, scratch_pool);
1790 if (err && err->apr_err == SVN_ERR_WC_CORRUPT)
1791 return svn_error_quick_wrap(err,
1792 _("This working copy is corrupt and "
1793 "cannot be upgraded. Please check out "
1794 "a new working copy."));
1798 /***** WC PROPS *****/
1799 /* If we don't know precisely where the wcprops are, ignore them. */
1800 if (old_format != SVN_WC__WCPROPS_LOST)
1802 apr_hash_t *all_wcprops;
1804 if (old_format <= SVN_WC__WCPROPS_MANY_FILES_VERSION)
1805 SVN_ERR(read_many_wcprops(&all_wcprops, dir_abspath,
1806 scratch_pool, scratch_pool));
1808 SVN_ERR(read_wcprops(&all_wcprops, dir_abspath,
1809 scratch_pool, scratch_pool));
1811 SVN_ERR(svn_wc__db_upgrade_apply_dav_cache(data->sdb, dir_relpath,
1812 all_wcprops, scratch_pool));
1815 /* Upgrade all the properties (including "this dir").
1817 Note: this must come AFTER the entries have been migrated into the
1818 database. The upgrade process needs the children in BASE_NODE and
1819 WORKING_NODE, and to examine the resultant WORKING state. */
1820 SVN_ERR(migrate_props(dir_abspath, data->root_abspath, data->sdb, old_format,
1821 wc_id, scratch_pool));
1823 return SVN_NO_ERROR;
1827 svn_wc__version_string_from_format(int wc_format)
1831 case 4: return "<=1.3";
1832 case 8: return "1.4";
1833 case 9: return "1.5";
1834 case 10: return "1.6";
1835 case SVN_WC__WC_NG_VERSION: return "1.7";
1837 return _("(unreleased development version)");
1841 svn_wc__upgrade_sdb(int *result_format,
1842 const char *wcroot_abspath,
1843 svn_sqlite__db_t *sdb,
1845 apr_pool_t *scratch_pool)
1847 struct bump_baton bb;
1849 bb.wcroot_abspath = wcroot_abspath;
1851 if (start_format < SVN_WC__WC_NG_VERSION /* 12 */)
1852 return svn_error_createf(SVN_ERR_WC_UPGRADE_REQUIRED, NULL,
1853 _("Working copy '%s' is too old (format %d, "
1854 "created by Subversion %s)"),
1855 svn_dirent_local_style(wcroot_abspath,
1858 svn_wc__version_string_from_format(start_format));
1860 /* Early WCNG formats no longer supported. */
1861 if (start_format < 19)
1862 return svn_error_createf(SVN_ERR_WC_UPGRADE_REQUIRED, NULL,
1863 _("Working copy '%s' is an old development "
1864 "version (format %d); to upgrade it, "
1865 "use a format 18 client, then "
1866 "use 'tools/dev/wc-ng/bump-to-19.py', then "
1867 "use the current client"),
1868 svn_dirent_local_style(wcroot_abspath,
1872 /* ### need lock-out. only one upgrade at a time. note that other code
1873 ### cannot use this un-upgraded database until we finish the upgrade. */
1875 /* Note: none of these have "break" statements; the fall-through is
1877 switch (start_format)
1880 SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_20, &bb,
1882 *result_format = 20;
1886 SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_21, &bb,
1888 *result_format = 21;
1892 SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_22, &bb,
1894 *result_format = 22;
1898 SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_23, &bb,
1900 *result_format = 23;
1904 SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_24, &bb,
1906 *result_format = 24;
1910 SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_25, &bb,
1912 *result_format = 25;
1916 SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_26, &bb,
1918 *result_format = 26;
1922 SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_27, &bb,
1924 *result_format = 27;
1928 SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_28, &bb,
1930 *result_format = 28;
1934 SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_29, &bb,
1936 *result_format = 29;
1940 SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_30, &bb,
1942 *result_format = 30;
1945 SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_31, &bb,
1947 *result_format = 31;
1949 /* ### future bumps go here. */
1952 /* Revamp the recording of tree conflicts. */
1953 SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_XXX, &bb,
1955 *result_format = XXX;
1958 case SVN_WC__VERSION:
1959 /* already upgraded */
1960 *result_format = SVN_WC__VERSION;
1962 SVN_SQLITE__WITH_LOCK(
1963 svn_wc__db_install_schema_statistics(sdb, scratch_pool),
1968 if (*result_format != start_format)
1971 SVN_ERR(svn_sqlite__read_schema_version(&schema_version, sdb, scratch_pool));
1973 /* If this assertion fails the schema isn't updated correctly */
1974 SVN_ERR_ASSERT(schema_version == *result_format);
1978 /* Zap anything that might be remaining or escaped our notice. */
1979 wipe_obsolete_files(wcroot_abspath, scratch_pool);
1981 return SVN_NO_ERROR;
1986 static svn_error_t *
1987 upgrade_working_copy(void *parent_baton,
1989 const char *dir_abspath,
1990 svn_wc_upgrade_get_repos_info_t repos_info_func,
1991 void *repos_info_baton,
1992 apr_hash_t *repos_cache,
1993 const struct upgrade_data_t *data,
1994 svn_cancel_func_t cancel_func,
1996 svn_wc_notify_func2_t notify_func,
1998 apr_pool_t *result_pool,
1999 apr_pool_t *scratch_pool)
2003 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
2004 apr_array_header_t *subdirs;
2009 SVN_ERR(cancel_func(cancel_baton));
2011 SVN_ERR(svn_wc__db_temp_get_format(&old_format, db, dir_abspath,
2014 if (old_format >= SVN_WC__WC_NG_VERSION)
2017 notify_func(notify_baton,
2018 svn_wc_create_notify(dir_abspath, svn_wc_notify_skip,
2021 svn_pool_destroy(iterpool);
2022 return SVN_NO_ERROR;
2025 err = get_versioned_subdirs(&subdirs, NULL, dir_abspath, FALSE,
2026 scratch_pool, iterpool);
2029 if (APR_STATUS_IS_ENOENT(err->apr_err)
2030 || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err))
2032 /* An unversioned dir is obstructing a versioned dir */
2033 svn_error_clear(err);
2036 notify_func(notify_baton,
2037 svn_wc_create_notify(dir_abspath, svn_wc_notify_skip,
2041 svn_pool_destroy(iterpool);
2046 SVN_ERR(upgrade_to_wcng(&dir_baton, parent_baton, db, dir_abspath,
2047 old_format, data->wc_id,
2048 repos_info_func, repos_info_baton,
2049 repos_cache, data, scratch_pool, iterpool));
2052 notify_func(notify_baton,
2053 svn_wc_create_notify(dir_abspath, svn_wc_notify_upgraded_path,
2057 for (i = 0; i < subdirs->nelts; ++i)
2059 const char *child_abspath = APR_ARRAY_IDX(subdirs, i, const char *);
2061 svn_pool_clear(iterpool);
2063 SVN_ERR(upgrade_working_copy(dir_baton, db, child_abspath,
2064 repos_info_func, repos_info_baton,
2066 cancel_func, cancel_baton,
2067 notify_func, notify_baton,
2068 iterpool, iterpool));
2071 svn_pool_destroy(iterpool);
2073 return SVN_NO_ERROR;
2077 /* Return a verbose error if LOCAL_ABSPATH is a not a pre-1.7 working
2079 static svn_error_t *
2080 is_old_wcroot(const char *local_abspath,
2081 apr_pool_t *scratch_pool)
2083 apr_hash_t *entries;
2084 const char *parent_abspath, *name;
2085 svn_wc_entry_t *entry;
2086 svn_error_t *err = svn_wc__read_entries_old(&entries, local_abspath,
2087 scratch_pool, scratch_pool);
2090 return svn_error_createf(
2091 SVN_ERR_WC_INVALID_OP_ON_CWD, err,
2092 _("Can't upgrade '%s' as it is not a working copy"),
2093 svn_dirent_local_style(local_abspath, scratch_pool));
2095 else if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
2096 return SVN_NO_ERROR;
2098 svn_dirent_split(&parent_abspath, &name, local_abspath, scratch_pool);
2100 err = svn_wc__read_entries_old(&entries, parent_abspath,
2101 scratch_pool, scratch_pool);
2104 svn_error_clear(err);
2105 return SVN_NO_ERROR;
2108 entry = svn_hash_gets(entries, name);
2111 || (entry->deleted && entry->schedule != svn_wc_schedule_add)
2112 || entry->depth == svn_depth_exclude)
2114 return SVN_NO_ERROR;
2117 while (!svn_dirent_is_root(parent_abspath, strlen(parent_abspath)))
2119 svn_dirent_split(&parent_abspath, &name, parent_abspath, scratch_pool);
2120 err = svn_wc__read_entries_old(&entries, parent_abspath,
2121 scratch_pool, scratch_pool);
2124 svn_error_clear(err);
2125 parent_abspath = svn_dirent_join(parent_abspath, name, scratch_pool);
2128 entry = svn_hash_gets(entries, name);
2131 || (entry->deleted && entry->schedule != svn_wc_schedule_add)
2132 || entry->depth == svn_depth_exclude)
2134 parent_abspath = svn_dirent_join(parent_abspath, name, scratch_pool);
2139 return svn_error_createf(
2140 SVN_ERR_WC_INVALID_OP_ON_CWD, NULL,
2141 _("Can't upgrade '%s' as it is not a working copy root,"
2142 " the root is '%s'"),
2143 svn_dirent_local_style(local_abspath, scratch_pool),
2144 svn_dirent_local_style(parent_abspath, scratch_pool));
2147 /* Data for upgrade_working_copy_txn(). */
2148 typedef struct upgrade_working_copy_baton_t
2151 const char *dir_abspath;
2152 svn_wc_upgrade_get_repos_info_t repos_info_func;
2153 void *repos_info_baton;
2154 apr_hash_t *repos_cache;
2155 const struct upgrade_data_t *data;
2156 svn_cancel_func_t cancel_func;
2158 svn_wc_notify_func2_t notify_func;
2160 apr_pool_t *result_pool;
2161 } upgrade_working_copy_baton_t;
2164 /* Helper for svn_wc_upgrade. Implements svn_sqlite__transaction_callback_t */
2165 static svn_error_t *
2166 upgrade_working_copy_txn(void *baton,
2167 svn_sqlite__db_t *sdb,
2168 apr_pool_t *scratch_pool)
2170 upgrade_working_copy_baton_t *b = baton;
2172 /* Upgrade the pre-wcng into a wcng in a temporary location. */
2173 return(upgrade_working_copy(NULL, b->db, b->dir_abspath,
2174 b->repos_info_func, b->repos_info_baton,
2175 b->repos_cache, b->data,
2176 b->cancel_func, b->cancel_baton,
2177 b->notify_func, b->notify_baton,
2178 b->result_pool, scratch_pool));
2182 svn_wc_upgrade(svn_wc_context_t *wc_ctx,
2183 const char *local_abspath,
2184 svn_wc_upgrade_get_repos_info_t repos_info_func,
2185 void *repos_info_baton,
2186 svn_cancel_func_t cancel_func,
2188 svn_wc_notify_func2_t notify_func,
2190 apr_pool_t *scratch_pool)
2193 struct upgrade_data_t data = { NULL };
2194 svn_skel_t *work_item, *work_items = NULL;
2195 const char *pristine_from, *pristine_to, *db_from, *db_to;
2196 apr_hash_t *repos_cache = apr_hash_make(scratch_pool);
2197 svn_wc_entry_t *this_dir;
2198 apr_hash_t *entries;
2199 const char *root_adm_abspath;
2200 upgrade_working_copy_baton_t cb_baton;
2203 svn_boolean_t bumped_format;
2205 /* Try upgrading a wc-ng-style working copy. */
2206 SVN_ERR(svn_wc__db_open(&db, NULL /* ### config */, TRUE, FALSE,
2207 scratch_pool, scratch_pool));
2210 err = svn_wc__db_bump_format(&result_format, &bumped_format,
2215 if (err->apr_err != SVN_ERR_WC_UPGRADE_REQUIRED)
2217 return svn_error_trace(
2218 svn_error_compose_create(
2220 svn_wc__db_close(db)));
2223 svn_error_clear(err);
2224 /* Pre 1.7: Fall through */
2228 /* Auto-upgrade worked! */
2229 SVN_ERR(svn_wc__db_close(db));
2231 SVN_ERR_ASSERT(result_format == SVN_WC__VERSION);
2233 if (bumped_format && notify_func)
2235 svn_wc_notify_t *notify;
2237 notify = svn_wc_create_notify(local_abspath,
2238 svn_wc_notify_upgraded_path,
2241 notify_func(notify_baton, notify, scratch_pool);
2244 return SVN_NO_ERROR;
2247 SVN_ERR(is_old_wcroot(local_abspath, scratch_pool));
2249 /* Given a pre-wcng root some/wc we create a temporary wcng in
2250 some/wc/.svn/tmp/wcng/wc.db and copy the metadata from one to the
2251 other, then the temporary wc.db file gets moved into the original
2252 root. Until the wc.db file is moved the original working copy
2253 remains a pre-wcng and 'cleanup' with an old client will remove
2254 the partial upgrade. Moving the wc.db file creates a wcng, and
2255 'cleanup' with a new client will complete any outstanding
2258 SVN_ERR(svn_wc__read_entries_old(&entries, local_abspath,
2259 scratch_pool, scratch_pool));
2261 this_dir = svn_hash_gets(entries, SVN_WC_ENTRY_THIS_DIR);
2262 SVN_ERR(ensure_repos_info(this_dir, local_abspath, repos_info_func,
2263 repos_info_baton, repos_cache,
2264 scratch_pool, scratch_pool));
2266 /* Cache repos UUID pairs for when a subdir doesn't have this information */
2267 if (!svn_hash_gets(repos_cache, this_dir->repos))
2268 svn_hash_sets(repos_cache,
2269 apr_pstrdup(scratch_pool, this_dir->repos),
2270 apr_pstrdup(scratch_pool, this_dir->uuid));
2272 /* Create the new DB in the temporary root wc/.svn/tmp/wcng/.svn */
2273 data.root_abspath = svn_dirent_join(svn_wc__adm_child(local_abspath, "tmp",
2275 "wcng", scratch_pool);
2276 root_adm_abspath = svn_wc__adm_child(data.root_abspath, "",
2278 SVN_ERR(svn_io_remove_dir2(root_adm_abspath, TRUE, NULL, NULL,
2280 SVN_ERR(svn_wc__ensure_directory(root_adm_abspath, scratch_pool));
2282 /* Create an empty sqlite database for this directory and store it in DB. */
2283 SVN_ERR(svn_wc__db_upgrade_begin(&data.sdb,
2284 &data.repos_id, &data.wc_id,
2285 db, data.root_abspath,
2286 this_dir->repos, this_dir->uuid,
2289 /* Migrate the entries over to the new database.
2290 ### We need to think about atomicity here.
2292 entries_write_new() writes in current format rather than
2293 f12. Thus, this function bumps a working copy all the way to
2295 SVN_ERR(svn_wc__db_wclock_obtain(db, data.root_abspath, 0, FALSE,
2299 cb_baton.dir_abspath = local_abspath;
2300 cb_baton.repos_info_func = repos_info_func;
2301 cb_baton.repos_info_baton = repos_info_baton;
2302 cb_baton.repos_cache = repos_cache;
2303 cb_baton.data = &data;
2304 cb_baton.cancel_func = cancel_func;
2305 cb_baton.cancel_baton = cancel_baton;
2306 cb_baton.notify_func = notify_func;
2307 cb_baton.notify_baton = notify_baton;
2308 cb_baton.result_pool = scratch_pool;
2310 SVN_ERR(svn_sqlite__with_lock(data.sdb,
2311 upgrade_working_copy_txn,
2315 /* A workqueue item to move the pristine dir into place */
2316 pristine_from = svn_wc__adm_child(data.root_abspath, PRISTINE_STORAGE_RELPATH,
2318 pristine_to = svn_wc__adm_child(local_abspath, PRISTINE_STORAGE_RELPATH,
2320 SVN_ERR(svn_wc__ensure_directory(pristine_from, scratch_pool));
2321 SVN_ERR(svn_wc__wq_build_file_move(&work_item, db, local_abspath,
2322 pristine_from, pristine_to,
2323 scratch_pool, scratch_pool));
2324 work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
2326 /* A workqueue item to remove pre-wcng metadata */
2327 SVN_ERR(svn_wc__wq_build_postupgrade(&work_item, scratch_pool));
2328 work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
2329 SVN_ERR(svn_wc__db_wq_add(db, data.root_abspath, work_items, scratch_pool));
2331 SVN_ERR(svn_wc__db_wclock_release(db, data.root_abspath, scratch_pool));
2332 SVN_ERR(svn_wc__db_close(db));
2334 /* Renaming the db file is what makes the pre-wcng into a wcng */
2335 db_from = svn_wc__adm_child(data.root_abspath, SDB_FILE, scratch_pool);
2336 db_to = svn_wc__adm_child(local_abspath, SDB_FILE, scratch_pool);
2337 SVN_ERR(svn_io_file_rename(db_from, db_to, scratch_pool));
2339 /* Now we have a working wcng, tidy up the droppings */
2340 SVN_ERR(svn_wc__db_open(&db, NULL /* ### config */, FALSE, FALSE,
2341 scratch_pool, scratch_pool));
2342 SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
2344 SVN_ERR(svn_wc__db_close(db));
2346 /* Should we have the workqueue remove this empty dir? */
2347 SVN_ERR(svn_io_remove_dir2(data.root_abspath, FALSE, NULL, NULL,
2350 return SVN_NO_ERROR;
2354 svn_wc__upgrade_add_external_info(svn_wc_context_t *wc_ctx,
2355 const char *local_abspath,
2356 svn_node_kind_t kind,
2357 const char *def_local_abspath,
2358 const char *repos_relpath,
2359 const char *repos_root_url,
2360 const char *repos_uuid,
2361 svn_revnum_t def_peg_revision,
2362 svn_revnum_t def_revision,
2363 apr_pool_t *scratch_pool)
2365 svn_node_kind_t db_kind;
2369 db_kind = svn_node_dir;
2373 db_kind = svn_node_file;
2376 case svn_node_unknown:
2377 db_kind = svn_node_unknown;
2381 SVN_ERR_MALFUNCTION();
2384 SVN_ERR(svn_wc__db_upgrade_insert_external(wc_ctx->db, local_abspath,
2386 svn_dirent_dirname(local_abspath,
2388 def_local_abspath, repos_relpath,
2389 repos_root_url, repos_uuid,
2390 def_peg_revision, def_revision,
2392 return SVN_NO_ERROR;