]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/subversion/subversion/libsvn_wc/upgrade.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / subversion / subversion / libsvn_wc / upgrade.c
1 /*
2  * upgrade.c:  routines for upgrading a working copy
3  *
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
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
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
20  *    under the License.
21  * ====================================================================
22  */
23
24 #include <apr_pools.h>
25
26 #include "svn_types.h"
27 #include "svn_pools.h"
28 #include "svn_dirent_uri.h"
29 #include "svn_path.h"
30 #include "svn_hash.h"
31
32 #include "wc.h"
33 #include "adm_files.h"
34 #include "conflicts.h"
35 #include "entries.h"
36 #include "wc_db.h"
37 #include "tree_conflicts.h"
38 #include "wc-queries.h"  /* for STMT_*  */
39 #include "workqueue.h"
40
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"
45
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
50                                                file */
51
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"
56
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"
63
64 /* Old textbase location. */
65 #define TEXT_BASE_SUBDIR "text-base"
66
67 #define TEMP_DIR "tmp"
68
69 /* Old data files that we no longer need/use.  */
70 #define ADM_README "README.txt"
71 #define ADM_EMPTY_FILE "empty-file"
72 #define ADM_LOG "log"
73 #define ADM_LOCK "lock"
74
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"
81
82
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.  */
86 static svn_error_t *
87 read_propfile(apr_hash_t **props,
88               const char *propfile_abspath,
89               apr_pool_t *result_pool,
90               apr_pool_t *scratch_pool)
91 {
92   svn_error_t *err;
93   svn_stream_t *stream;
94   apr_finfo_t finfo;
95
96   err = svn_io_stat(&finfo, propfile_abspath, APR_FINFO_SIZE, scratch_pool);
97
98   if (err
99       && (APR_STATUS_IS_ENOENT(err->apr_err)
100           || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)))
101     {
102       svn_error_clear(err);
103
104       /* The propfile was not there. Signal with a NULL.  */
105       *props = NULL;
106       return SVN_NO_ERROR;
107     }
108   else
109     SVN_ERR(err);
110
111   /* A 0-bytes file signals an empty property list.
112      (mostly used for revert-props) */
113   if (finfo.size == 0)
114     {
115       *props = apr_hash_make(result_pool);
116       return SVN_NO_ERROR;
117     }
118
119   SVN_ERR(svn_stream_open_readonly(&stream, propfile_abspath,
120                                    scratch_pool, scratch_pool));
121
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?  */
126
127   /* ### loggy_write_properties() and immediate_install_props() write
128      ### zero-length files for "no props", so we should be a bit smarter
129      ### in here.  */
130
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.  */
133
134   *props = apr_hash_make(result_pool);
135   SVN_ERR(svn_hash_read2(*props, stream, SVN_HASH_TERMINATOR, result_pool));
136
137   return svn_error_trace(svn_stream_close(stream));
138 }
139
140
141 /* Read one proplist (allocated from RESULT_POOL) from STREAM, and place it
142    into ALL_WCPROPS at NAME.  */
143 static svn_error_t *
144 read_one_proplist(apr_hash_t *all_wcprops,
145                   const char *name,
146                   svn_stream_t *stream,
147                   apr_pool_t *result_pool,
148                   apr_pool_t *scratch_pool)
149 {
150   apr_hash_t *proplist;
151
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);
155
156   return SVN_NO_ERROR;
157 }
158
159
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.  */
163 static svn_error_t *
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)
168 {
169   const char *propfile_abspath;
170   apr_hash_t *wcprops;
171   apr_hash_t *dirents;
172   const char *props_dir_abspath;
173   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
174   apr_hash_index_t *hi;
175
176   *all_wcprops = apr_hash_make(result_pool);
177
178   /* First, look at dir-wcprops. */
179   propfile_abspath = svn_wc__adm_child(dir_abspath, WCPROPS_FNAME_FOR_DIR,
180                                        scratch_pool);
181   SVN_ERR(read_propfile(&wcprops, propfile_abspath, result_pool, iterpool));
182   if (wcprops != NULL)
183     svn_hash_sets(*all_wcprops, SVN_WC_ENTRY_THIS_DIR, wcprops);
184
185   props_dir_abspath = svn_wc__adm_child(dir_abspath, WCPROPS_SUBDIR_FOR_FILES,
186                                         scratch_pool);
187
188   /* Now walk the wcprops directory. */
189   SVN_ERR(svn_io_get_dirents3(&dirents, props_dir_abspath, TRUE,
190                               scratch_pool, scratch_pool));
191
192   for (hi = apr_hash_first(scratch_pool, dirents);
193        hi;
194        hi = apr_hash_next(hi))
195     {
196       const char *name = svn__apr_hash_index_key(hi);
197
198       svn_pool_clear(iterpool);
199
200       propfile_abspath = svn_dirent_join(props_dir_abspath, name, iterpool);
201
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);
206     }
207
208   svn_pool_destroy(iterpool);
209   return SVN_NO_ERROR;
210 }
211
212
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. */
216 static svn_error_t *
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)
221 {
222   svn_stream_t *stream;
223   svn_error_t *err;
224
225   *all_wcprops = apr_hash_make(result_pool);
226
227   err = svn_wc__open_adm_stream(&stream, dir_abspath,
228                                 WCPROPS_ALL_DATA,
229                                 scratch_pool, scratch_pool);
230
231   /* A non-existent file means there are no props. */
232   if (err && APR_STATUS_IS_ENOENT(err->apr_err))
233     {
234       svn_error_clear(err);
235       return SVN_NO_ERROR;
236     }
237   SVN_ERR(err);
238
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));
242
243   /* And now, the children. */
244   while (1729)
245     {
246       svn_stringbuf_t *line;
247       svn_boolean_t eof;
248
249       SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, result_pool));
250       if (eof)
251         {
252           if (line->len > 0)
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));
257           break;
258         }
259       SVN_ERR(read_one_proplist(*all_wcprops, line->data, stream,
260                                 result_pool, scratch_pool));
261     }
262
263   return svn_error_trace(svn_stream_close(stream));
264 }
265
266 /* Return in CHILDREN, the list of all 1.6 versioned subdirectories
267    which also exist on disk as directories.
268
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.
271
272    If SKIP_MISSING is TRUE, don't add missing or obstructed subdirectories
273    to the list of children.
274    */
275 static svn_error_t *
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)
282 {
283   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
284   apr_hash_t *entries;
285   apr_hash_index_t *hi;
286   svn_wc_entry_t *this_dir = NULL;
287
288   *children = apr_array_make(result_pool, 10, sizeof(const char *));
289
290   SVN_ERR(svn_wc__read_entries_old(&entries, dir_abspath,
291                                    scratch_pool, iterpool));
292   for (hi = apr_hash_first(scratch_pool, entries);
293        hi;
294        hi = apr_hash_next(hi))
295     {
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;
300
301       /* skip "this dir"  */
302       if (*name == '\0')
303         {
304           this_dir = svn__apr_hash_index_val(hi);
305           continue;
306         }
307       else if (entry->kind != svn_node_dir)
308         continue;
309
310       svn_pool_clear(iterpool);
311
312       /* If a directory is 'hidden' skip it as subdir */
313       SVN_ERR(svn_wc__entry_is_hidden(&hidden, entry));
314       if (hidden)
315         continue;
316
317       child_abspath = svn_dirent_join(dir_abspath, name, scratch_pool);
318
319       if (skip_missing)
320         {
321           svn_node_kind_t kind;
322           SVN_ERR(svn_io_check_path(child_abspath, &kind, scratch_pool));
323
324           if (kind != svn_node_dir)
325             continue;
326         }
327
328       APR_ARRAY_PUSH(*children, const char *) = apr_pstrdup(result_pool,
329                                                             child_abspath);
330     }
331
332   svn_pool_destroy(iterpool);
333
334   if (delete_dir != NULL)
335     {
336       *delete_dir = (this_dir != NULL)
337                      && (this_dir->schedule == svn_wc_schedule_delete)
338                      && ! this_dir->keep_local;
339     }
340
341   return SVN_NO_ERROR;
342 }
343
344
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
347    not tested.
348
349    This set of children is intended for property upgrades.
350    Subdirectory's properties exist in the subdirs.
351
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. */
354 static svn_error_t *
355 get_versioned_files(const apr_array_header_t **children,
356                     const char *parent_relpath,
357                     svn_sqlite__db_t *sdb,
358                     apr_int64_t wc_id,
359                     apr_pool_t *result_pool,
360                     apr_pool_t *scratch_pool)
361 {
362   svn_sqlite__stmt_t *stmt;
363   apr_array_header_t *child_names;
364   svn_boolean_t have_row;
365
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));
369
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 *));
374
375   SVN_ERR(svn_sqlite__step(&have_row, stmt));
376   while (have_row)
377     {
378       const char *local_relpath = svn_sqlite__column_text(stmt, 0,
379                                                           result_pool);
380
381       APR_ARRAY_PUSH(child_names, const char *)
382         = svn_relpath_basename(local_relpath, result_pool);
383
384       SVN_ERR(svn_sqlite__step(&have_row, stmt));
385     }
386
387   *children = child_names;
388
389   return svn_error_trace(svn_sqlite__reset(stmt));
390 }
391
392
393 /* Return the path of the old-school administrative lock file
394    associated with LOCAL_DIR_ABSPATH, allocated from RESULT_POOL. */
395 static const char *
396 build_lockfile_path(const char *local_dir_abspath,
397                     apr_pool_t *result_pool)
398 {
399   return svn_dirent_join_many(result_pool,
400                               local_dir_abspath,
401                               svn_wc_get_adm_dir(result_pool),
402                               ADM_LOCK,
403                               NULL);
404 }
405
406
407 /* Create a physical lock file in the admin directory for ABSPATH.  */
408 static svn_error_t *
409 create_physical_lock(const char *abspath, apr_pool_t *scratch_pool)
410 {
411   const char *lock_abspath = build_lockfile_path(abspath, scratch_pool);
412   svn_error_t *err;
413   apr_file_t *file;
414
415   err = svn_io_file_open(&file, lock_abspath,
416                          APR_WRITE | APR_CREATE | APR_EXCL,
417                          APR_OS_DEFAULT,
418                          scratch_pool);
419
420   if (err && APR_STATUS_IS_EEXIST(err->apr_err))
421     {
422       /* Congratulations, we just stole a physical lock from somebody */
423       svn_error_clear(err);
424       return SVN_NO_ERROR;
425     }
426
427   return svn_error_trace(err);
428 }
429
430
431 /* Wipe out all the obsolete files/dirs from the administrative area.  */
432 static void
433 wipe_obsolete_files(const char *wcroot_abspath, apr_pool_t *scratch_pool)
434 {
435   /* Zap unused files.  */
436   svn_error_clear(svn_io_remove_file2(
437                     svn_wc__adm_child(wcroot_abspath,
438                                       SVN_WC__ADM_FORMAT,
439                                       scratch_pool),
440                     TRUE, scratch_pool));
441   svn_error_clear(svn_io_remove_file2(
442                     svn_wc__adm_child(wcroot_abspath,
443                                       SVN_WC__ADM_ENTRIES,
444                                       scratch_pool),
445                     TRUE, scratch_pool));
446   svn_error_clear(svn_io_remove_file2(
447                     svn_wc__adm_child(wcroot_abspath,
448                                       ADM_EMPTY_FILE,
449                                       scratch_pool),
450                     TRUE, scratch_pool));
451   svn_error_clear(svn_io_remove_file2(
452                     svn_wc__adm_child(wcroot_abspath,
453                                       ADM_README,
454                                       scratch_pool),
455                     TRUE, scratch_pool));
456
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,
462                                       scratch_pool),
463                     TRUE, scratch_pool));
464   svn_error_clear(svn_io_remove_dir2(
465                     svn_wc__adm_child(wcroot_abspath,
466                                       WCPROPS_SUBDIR_FOR_FILES,
467                                       scratch_pool),
468                     FALSE, NULL, NULL, scratch_pool));
469
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,
473                                       WCPROPS_ALL_DATA,
474                                       scratch_pool),
475                     TRUE, scratch_pool));
476
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,
480                                       TEXT_BASE_SUBDIR,
481                                       scratch_pool),
482                     FALSE, NULL, NULL, scratch_pool));
483
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,
487                                       PROPS_SUBDIR,
488                                       scratch_pool),
489                     FALSE, NULL, NULL, scratch_pool));
490   svn_error_clear(svn_io_remove_dir2(
491                     svn_wc__adm_child(wcroot_abspath,
492                                       PROP_BASE_SUBDIR,
493                                       scratch_pool),
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,
498                                        scratch_pool),
499                      TRUE, scratch_pool));
500   svn_error_clear(svn_io_remove_file2(
501                      svn_wc__adm_child(wcroot_abspath,
502                                       PROP_BASE_FOR_DIR,
503                                       scratch_pool),
504                      TRUE, scratch_pool));
505   svn_error_clear(svn_io_remove_file2(
506                      svn_wc__adm_child(wcroot_abspath,
507                                       PROP_REVERT_FOR_DIR,
508                                       scratch_pool),
509                      TRUE, scratch_pool));
510
511 #if 0
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));
515 #endif
516
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));
521 }
522
523 svn_error_t *
524 svn_wc__wipe_postupgrade(const char *dir_abspath,
525                          svn_boolean_t whole_admin,
526                          svn_cancel_func_t cancel_func,
527                          void *cancel_baton,
528                          apr_pool_t *scratch_pool)
529 {
530   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
531   apr_array_header_t *subdirs;
532   svn_error_t *err;
533   svn_boolean_t delete_dir;
534   int i;
535
536   if (cancel_func)
537     SVN_ERR((*cancel_func)(cancel_baton));
538
539   err = get_versioned_subdirs(&subdirs, &delete_dir, dir_abspath, TRUE,
540                               scratch_pool, iterpool);
541   if (err)
542     {
543       if (APR_STATUS_IS_ENOENT(err->apr_err))
544         {
545           /* An unversioned dir is obstructing a versioned dir */
546           svn_error_clear(err);
547           err = NULL;
548         }
549       svn_pool_destroy(iterpool);
550       return svn_error_trace(err);
551     }
552   for (i = 0; i < subdirs->nelts; ++i)
553     {
554       const char *child_abspath = APR_ARRAY_IDX(subdirs, i, const char *);
555
556       svn_pool_clear(iterpool);
557       SVN_ERR(svn_wc__wipe_postupgrade(child_abspath, TRUE,
558                                        cancel_func, cancel_baton, iterpool));
559     }
560
561   /* ### Should we really be ignoring errors here? */
562   if (whole_admin)
563     svn_error_clear(svn_io_remove_dir2(svn_wc__adm_child(dir_abspath, "",
564                                                          iterpool),
565                                        TRUE, NULL, NULL, iterpool));
566   else
567     wipe_obsolete_files(dir_abspath, scratch_pool);
568
569   if (delete_dir)
570     {
571       /* If this was a WC-NG single database copy, this directory wouldn't
572          be here (unless it was deleted with --keep-local)
573
574          If the directory is empty, we can just delete it; if not we
575          keep it.
576        */
577       svn_error_clear(svn_io_dir_remove_nonrecursive(dir_abspath, iterpool));
578     }
579
580   svn_pool_destroy(iterpool);
581
582   return SVN_NO_ERROR;
583 }
584
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.
588
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.  */
594 static svn_error_t *
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)
602 {
603   /* Easy exit.  */
604   if (entry->repos != NULL && entry->uuid != NULL)
605     return SVN_NO_ERROR;
606
607   if ((entry->repos == NULL || entry->uuid == NULL)
608       && entry->url)
609     {
610       apr_hash_index_t *hi;
611
612       for (hi = apr_hash_first(scratch_pool, repos_cache);
613            hi; hi = apr_hash_next(hi))
614         {
615           if (svn_uri__is_ancestor(svn__apr_hash_index_key(hi), entry->url))
616             {
617               if (!entry->repos)
618                 entry->repos = svn__apr_hash_index_key(hi);
619
620               if (!entry->uuid)
621                 entry->uuid = svn__apr_hash_index_val(hi);
622
623               return SVN_NO_ERROR;
624             }
625         }
626     }
627
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));
634
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));
641
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));
647
648    return svn_error_trace((*repos_info_func)(&entry->repos, &entry->uuid,
649                                              repos_info_baton,
650                                              entry->url,
651                                              result_pool, scratch_pool));
652 }
653
654
655 /*
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.
662  *
663  * Note: There were some concerns about this function:
664  *
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)
669  *
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
672  * New Way. */
673 static svn_error_t *
674 read_tree_conflicts(apr_hash_t **conflicts,
675                     const char *conflict_data,
676                     const char *dir_path,
677                     apr_pool_t *pool)
678 {
679   const svn_skel_t *skel;
680   apr_pool_t *iterpool;
681
682   *conflicts = apr_hash_make(pool);
683
684   if (conflict_data == NULL)
685     return SVN_NO_ERROR;
686
687   skel = svn_skel__parse(conflict_data, strlen(conflict_data), pool);
688   if (skel == NULL)
689     return svn_error_create(SVN_ERR_WC_CORRUPT, NULL,
690                             _("Error parsing tree conflict skel"));
691
692   iterpool = svn_pool_create(pool);
693   for (skel = skel->children; skel != NULL; skel = skel->next)
694     {
695       const svn_wc_conflict_description2_t *conflict;
696
697       svn_pool_clear(iterpool);
698       SVN_ERR(svn_wc__deserialize_conflict(&conflict, skel, dir_path,
699                                            pool, iterpool));
700       if (conflict != NULL)
701         svn_hash_sets(*conflicts,
702                       svn_dirent_basename(conflict->local_abspath, pool),
703                       conflict);
704     }
705   svn_pool_destroy(iterpool);
706
707   return SVN_NO_ERROR;
708 }
709
710 /* */
711 static svn_error_t *
712 migrate_single_tree_conflict_data(svn_sqlite__db_t *sdb,
713                                   const char *tree_conflict_data,
714                                   apr_int64_t wc_id,
715                                   const char *local_relpath,
716                                   apr_pool_t *scratch_pool)
717 {
718   apr_hash_t *conflicts;
719   apr_hash_index_t *hi;
720   apr_pool_t *iterpool;
721
722   SVN_ERR(read_tree_conflicts(&conflicts, tree_conflict_data, local_relpath,
723                               scratch_pool));
724
725   iterpool = svn_pool_create(scratch_pool);
726   for (hi = apr_hash_first(scratch_pool, conflicts);
727        hi;
728        hi = apr_hash_next(hi))
729     {
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;
736       svn_skel_t *skel;
737
738       svn_pool_clear(iterpool);
739
740       conflict_relpath = svn_dirent_join(local_relpath,
741                                          svn_dirent_basename(
742                                            conflict->local_abspath, iterpool),
743                                          iterpool);
744
745       SVN_ERR(svn_wc__serialize_conflict(&skel, conflict, iterpool, iterpool));
746       conflict_data = svn_skel__unparse(skel, iterpool)->data;
747
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));
753
754       if (have_row)
755         {
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));
759         }
760       else
761         {
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));
765         }
766
767       SVN_ERR(svn_sqlite__bindf(stmt, "iss", wc_id, conflict_relpath,
768                                 conflict_data));
769       if (!have_row)
770         SVN_ERR(svn_sqlite__bind_text(stmt, 4, local_relpath));
771
772       SVN_ERR(svn_sqlite__step_done(stmt));
773     }
774
775   svn_pool_destroy(iterpool);
776
777   return SVN_NO_ERROR;
778 }
779
780
781 /* */
782 static svn_error_t *
783 migrate_tree_conflict_data(svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
784 {
785   svn_sqlite__stmt_t *stmt;
786   svn_boolean_t have_row;
787   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
788
789   /* Iterate over each node which has a set of tree conflicts, then insert
790      all of them into the new schema.  */
791
792   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
793                                     STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT));
794
795   /* Get all the existing tree conflict data. */
796   SVN_ERR(svn_sqlite__step(&have_row, stmt));
797   while (have_row)
798     {
799       apr_int64_t wc_id;
800       const char *local_relpath;
801       const char *tree_conflict_data;
802
803       svn_pool_clear(iterpool);
804
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);
808
809       SVN_ERR(migrate_single_tree_conflict_data(sdb, tree_conflict_data,
810                                                 wc_id, local_relpath,
811                                                 iterpool));
812
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));
816     }
817   SVN_ERR(svn_sqlite__reset(stmt));
818
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));
823
824   svn_pool_destroy(iterpool);
825   return SVN_NO_ERROR;
826 }
827
828
829 struct bump_baton {
830   const char *wcroot_abspath;
831 };
832
833 /* Migrate the properties for one node (LOCAL_ABSPATH).  */
834 static svn_error_t *
835 migrate_node_props(const char *dir_abspath,
836                    const char *new_wcroot_abspath,
837                    const char *name,
838                    svn_sqlite__db_t *sdb,
839                    int original_format,
840                    apr_int64_t wc_id,
841                    apr_pool_t *scratch_pool)
842 {
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,
851                                       scratch_pool);
852   const char *dir_relpath = svn_dirent_skip_ancestor(old_wcroot_abspath,
853                                                      dir_abspath);
854
855   if (*name == '\0')
856     {
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);
863     }
864   else
865     {
866       const char *basedir_abspath;
867       const char *propsdir_abspath;
868
869       propsdir_abspath = svn_wc__adm_child(dir_abspath, PROPS_SUBDIR,
870                                            scratch_pool);
871       basedir_abspath = svn_wc__adm_child(dir_abspath, PROP_BASE_SUBDIR,
872                                           scratch_pool);
873
874       base_abspath = svn_dirent_join(basedir_abspath,
875                                      apr_pstrcat(scratch_pool,
876                                                  name,
877                                                  SVN_WC__BASE_EXT,
878                                                  (char *)NULL),
879                                      scratch_pool);
880
881       revert_abspath = svn_dirent_join(basedir_abspath,
882                                        apr_pstrcat(scratch_pool,
883                                                    name,
884                                                    SVN_WC__REVERT_EXT,
885                                                    (char *)NULL),
886                                        scratch_pool);
887
888       working_abspath = svn_dirent_join(propsdir_abspath,
889                                         apr_pstrcat(scratch_pool,
890                                                     name,
891                                                     SVN_WC__WORK_EXT,
892                                                     (char *)NULL),
893                                         scratch_pool);
894     }
895
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));
902
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,
908                             scratch_pool));
909 }
910
911
912 /* */
913 static svn_error_t *
914 migrate_props(const char *dir_abspath,
915               const char *new_wcroot_abspath,
916               svn_sqlite__db_t *sdb,
917               int original_format,
918               apr_int64_t wc_id,
919               apr_pool_t *scratch_pool)
920 {
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:
924
925      if (revert props exist):
926        revert  -> BASE
927        base    -> WORKING
928        working -> ACTUAL
929      else if (prop pristine is working [as defined in props.c] ):
930        base    -> WORKING
931        working -> ACTUAL
932      else:
933        base    -> BASE
934        working -> ACTUAL
935
936      ### the middle "test" should simply look for a WORKING_NODE row
937
938      Note that it is legal for "working" props to be missing. That implies
939      no local changes to the properties.
940   */
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,
945                                       scratch_pool);
946   const char *dir_relpath = svn_dirent_skip_ancestor(old_wcroot_abspath,
947                                                      dir_abspath);
948   int i;
949
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));
953
954   /* Iterate over all the files in this SDB.  */
955   SVN_ERR(get_versioned_files(&children, dir_relpath, sdb, wc_id, scratch_pool,
956                               iterpool));
957   for (i = 0; i < children->nelts; i++)
958     {
959       const char *name = APR_ARRAY_IDX(children, i, const char *);
960
961       svn_pool_clear(iterpool);
962
963       SVN_ERR(migrate_node_props(dir_abspath, new_wcroot_abspath,
964                                  name, sdb, original_format, wc_id, iterpool));
965     }
966
967   svn_pool_destroy(iterpool);
968
969   return SVN_NO_ERROR;
970 }
971
972
973 /* If STR ends with SUFFIX and is longer than SUFFIX, return the part of
974  * STR that comes before SUFFIX; else return NULL. */
975 static char *
976 remove_suffix(const char *str, const char *suffix, apr_pool_t *result_pool)
977 {
978   size_t str_len = strlen(str);
979   size_t suffix_len = strlen(suffix);
980
981   if (str_len > suffix_len
982       && strcmp(str + str_len - suffix_len, suffix) == 0)
983     {
984       return apr_pstrmemdup(result_pool, str, str_len - suffix_len);
985     }
986
987   return NULL;
988 }
989
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
992    NEW_WCROOT_ABSPATH.
993
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. */
997 static svn_error_t *
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)
1004 {
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,
1009                                                 TEXT_BASE_SUBDIR,
1010                                                 scratch_pool);
1011
1012   *text_bases_info = apr_hash_make(result_pool);
1013
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))
1019     {
1020       const char *text_base_basename = svn__apr_hash_index_key(hi);
1021       svn_checksum_t *md5_checksum;
1022       svn_checksum_t *sha1_checksum;
1023
1024       svn_pool_clear(iterpool);
1025
1026       /* Calculate its checksums and copy it to the pristine store */
1027       {
1028         const char *pristine_path;
1029         const char *text_base_path;
1030         const char *temp_path;
1031         svn_sqlite__stmt_t *stmt;
1032         apr_finfo_t finfo;
1033         svn_stream_t *read_stream;
1034         svn_stream_t *result_stream;
1035
1036         text_base_path = svn_dirent_join(text_base_dir, text_base_basename,
1037                                          iterpool);
1038
1039         /* Create a copy and calculate a checksum in one step */
1040         SVN_ERR(svn_stream_open_unique(&result_stream, &temp_path,
1041                                        new_wcroot_abspath,
1042                                        svn_io_file_del_none,
1043                                        iterpool, iterpool));
1044
1045         SVN_ERR(svn_stream_open_readonly(&read_stream, text_base_path,
1046                                            iterpool, iterpool));
1047
1048         read_stream = svn_stream_checksummed2(read_stream, &md5_checksum,
1049                                               NULL, svn_checksum_md5,
1050                                               TRUE, iterpool);
1051
1052         read_stream = svn_stream_checksummed2(read_stream, &sha1_checksum,
1053                                               NULL, svn_checksum_sha1,
1054                                               TRUE, iterpool);
1055
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));
1059
1060         SVN_ERR(svn_io_stat(&finfo, text_base_path, APR_FINFO_SIZE, iterpool));
1061
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));
1069
1070         SVN_ERR(svn_wc__db_pristine_get_future_path(&pristine_path,
1071                                                     new_wcroot_abspath,
1072                                                     sha1_checksum,
1073                                                     iterpool, iterpool));
1074
1075         /* Ensure any sharding directories exist. */
1076         SVN_ERR(svn_wc__ensure_directory(svn_dirent_dirname(pristine_path,
1077                                                             iterpool),
1078                                          iterpool));
1079
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));
1083       }
1084
1085       /* Add the checksums for this text-base to *TEXT_BASES_INFO. */
1086       {
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;
1091
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)
1097           {
1098             is_revert_base = TRUE;
1099           }
1100         else
1101           {
1102             versioned_file_name = remove_suffix(text_base_basename,
1103                                                 SVN_WC__BASE_EXT, result_pool);
1104             is_revert_base = FALSE;
1105           }
1106
1107         if (! versioned_file_name)
1108           {
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.
1112
1113                 Note that we already copied this file in the pristine store,
1114                 but the next cleanup will take care of that.
1115               */
1116             continue;
1117           }
1118
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);
1122         if (info == NULL)
1123           info = apr_pcalloc(result_pool, sizeof (*info));
1124         file_info = (is_revert_base ? &info->revert_base : &info->normal_base);
1125
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);
1129       }
1130     }
1131
1132   svn_pool_destroy(iterpool);
1133
1134   return SVN_NO_ERROR;
1135 }
1136
1137 static svn_error_t *
1138 bump_to_20(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1139 {
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;
1143 }
1144
1145 static svn_error_t *
1146 bump_to_21(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1147 {
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;
1151 }
1152
1153 static svn_error_t *
1154 bump_to_22(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1155 {
1156   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_22));
1157   return SVN_NO_ERROR;
1158 }
1159
1160 static svn_error_t *
1161 bump_to_23(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1162 {
1163   const char *wcroot_abspath = ((struct bump_baton *)baton)->wcroot_abspath;
1164   svn_sqlite__stmt_t *stmt;
1165   svn_boolean_t have_row;
1166
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));
1171   if (have_row)
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"),
1176                              wcroot_abspath);
1177
1178   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_23));
1179   return SVN_NO_ERROR;
1180 }
1181
1182 static svn_error_t *
1183 bump_to_24(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1184 {
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;
1188 }
1189
1190 static svn_error_t *
1191 bump_to_25(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1192 {
1193   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_25));
1194   return SVN_NO_ERROR;
1195 }
1196
1197 static svn_error_t *
1198 bump_to_26(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1199 {
1200   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_26));
1201   return SVN_NO_ERROR;
1202 }
1203
1204 static svn_error_t *
1205 bump_to_27(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1206 {
1207   const char *wcroot_abspath = ((struct bump_baton *)baton)->wcroot_abspath;
1208   svn_sqlite__stmt_t *stmt;
1209   svn_boolean_t have_row;
1210
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));
1215   if (have_row)
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"),
1220                              wcroot_abspath);
1221   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_27));
1222   return SVN_NO_ERROR;
1223 }
1224
1225 static svn_error_t *
1226 bump_to_28(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1227 {
1228   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_28));
1229   return SVN_NO_ERROR;
1230 }
1231
1232 /* If FINFO indicates that ABSPATH names a file, rename it to
1233  * '<ABSPATH>.svn-base'.
1234  *
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.
1238  *
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,
1244                      apr_pool_t *pool)
1245 {
1246   if (finfo->filetype == APR_REG
1247       && (strlen(svn_dirent_basename(abspath, pool))
1248           == PRISTINE_BASENAME_OLD_LEN))
1249     {
1250       const char *new_abspath
1251         = apr_pstrcat(pool, abspath, PRISTINE_STORAGE_EXT, (char *)NULL);
1252
1253       SVN_ERR(svn_io_file_rename(abspath, new_abspath, pool));
1254     }
1255   return SVN_NO_ERROR;
1256 }
1257
1258 static svn_error_t *
1259 upgrade_externals(struct bump_baton *bb,
1260                   svn_sqlite__db_t *sdb,
1261                   apr_pool_t *scratch_pool)
1262 {
1263   svn_sqlite__stmt_t *stmt;
1264   svn_sqlite__stmt_t *stmt_add;
1265   svn_boolean_t have_row;
1266   apr_pool_t *iterpool;
1267
1268   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1269                                     STMT_SELECT_EXTERNAL_PROPERTIES));
1270
1271   SVN_ERR(svn_sqlite__get_statement(&stmt_add, sdb,
1272                                     STMT_INSERT_EXTERNAL));
1273
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, ""));
1278
1279   SVN_ERR(svn_sqlite__step(&have_row, stmt));
1280
1281   iterpool = svn_pool_create(scratch_pool);
1282   while (have_row)
1283     {
1284       apr_hash_t *props;
1285       const char *externals;
1286
1287       svn_pool_clear(iterpool);
1288
1289       SVN_ERR(svn_sqlite__column_properties(&props, stmt, 0,
1290                                             iterpool, iterpool));
1291
1292       externals = svn_prop_get_value(props, SVN_PROP_EXTERNALS);
1293
1294       if (externals)
1295         {
1296           apr_array_header_t *ext;
1297           const char *local_relpath;
1298           const char *local_abspath;
1299           int i;
1300
1301           local_relpath = svn_sqlite__column_text(stmt, 1, NULL);
1302           local_abspath = svn_dirent_join(bb->wcroot_abspath, local_relpath,
1303                                           iterpool);
1304
1305           SVN_ERR(svn_wc_parse_externals_description3(&ext, local_abspath,
1306                                                       externals, FALSE,
1307                                                       iterpool));
1308
1309           for (i = 0; i < ext->nelts; i++)
1310             {
1311               const svn_wc_external_item2_t *item;
1312               const char *item_relpath;
1313
1314               item = APR_ARRAY_IDX(ext, i, const svn_wc_external_item2_t *);
1315               item_relpath = svn_relpath_join(local_relpath, item->target_dir,
1316                                               iterpool);
1317
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 */
1323                                         item_relpath,
1324                                         svn_relpath_dirname(item_relpath,
1325                                                             iterpool),
1326                                         "normal",
1327                                         "unknown",
1328                                         local_relpath,
1329                                         (apr_int64_t)1, /* repos_id */
1330                                         "" /* repos_relpath */));
1331               SVN_ERR(svn_sqlite__insert(NULL, stmt_add));
1332             }
1333         }
1334
1335       SVN_ERR(svn_sqlite__step(&have_row, stmt));
1336     }
1337
1338   svn_pool_destroy(iterpool);
1339   return svn_error_trace(svn_sqlite__reset(stmt));
1340 }
1341
1342 static svn_error_t *
1343 bump_to_29(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1344 {
1345   struct bump_baton *bb = baton;
1346   const char *wcroot_abspath = bb->wcroot_abspath;
1347   const char *pristine_dir_abspath;
1348
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));
1355
1356   /* Externals */
1357   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_EXTERNALS));
1358
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;
1362 }
1363
1364 svn_error_t *
1365 svn_wc__upgrade_conflict_skel_from_raw(svn_skel_t **conflicts,
1366                                        svn_wc__db_t *db,
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)
1377 {
1378   svn_skel_t *conflict_data = NULL;
1379   const char *wcroot_abspath;
1380
1381   SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, db, wri_abspath,
1382                                 scratch_pool, scratch_pool));
1383
1384   if (conflict_old || conflict_new || conflict_wrk)
1385     {
1386       const char *old_abspath = NULL;
1387       const char *new_abspath = NULL;
1388       const char *wrk_abspath = NULL;
1389
1390       conflict_data = svn_wc__conflict_skel_create(result_pool);
1391
1392       if (conflict_old)
1393         old_abspath = svn_dirent_join(wcroot_abspath, conflict_old,
1394                                       scratch_pool);
1395
1396       if (conflict_new)
1397         new_abspath = svn_dirent_join(wcroot_abspath, conflict_new,
1398                                       scratch_pool);
1399
1400       if (conflict_wrk)
1401         wrk_abspath = svn_dirent_join(wcroot_abspath, conflict_wrk,
1402                                       scratch_pool);
1403
1404       SVN_ERR(svn_wc__conflict_skel_add_text_conflict(conflict_data,
1405                                                       db, wri_abspath,
1406                                                       wrk_abspath,
1407                                                       old_abspath,
1408                                                       new_abspath,
1409                                                       scratch_pool,
1410                                                       scratch_pool));
1411     }
1412
1413   if (prej_file)
1414     {
1415       const char *prej_abspath;
1416
1417       if (!conflict_data)
1418         conflict_data = svn_wc__conflict_skel_create(result_pool);
1419
1420       prej_abspath = svn_dirent_join(wcroot_abspath, prej_file, scratch_pool);
1421
1422       SVN_ERR(svn_wc__conflict_skel_add_prop_conflict(conflict_data,
1423                                                       db, wri_abspath,
1424                                                       prej_abspath,
1425                                                       NULL, NULL, NULL,
1426                                                 apr_hash_make(scratch_pool),
1427                                                       scratch_pool,
1428                                                       scratch_pool));
1429     }
1430
1431   if (tree_conflict_data)
1432     {
1433       svn_skel_t *tc_skel;
1434       const svn_wc_conflict_description2_t *tc;
1435       const char *local_abspath;
1436
1437       if (!conflict_data)
1438         conflict_data = svn_wc__conflict_skel_create(scratch_pool);
1439
1440       tc_skel = svn_skel__parse(tree_conflict_data, tree_conflict_len,
1441                                 scratch_pool);
1442
1443       local_abspath = svn_dirent_join(wcroot_abspath, local_relpath,
1444                                       scratch_pool);
1445
1446       SVN_ERR(svn_wc__deserialize_conflict(&tc, tc_skel,
1447                                            svn_dirent_dirname(local_abspath,
1448                                                               scratch_pool),
1449                                            scratch_pool, scratch_pool));
1450
1451       SVN_ERR(svn_wc__conflict_skel_add_tree_conflict(conflict_data,
1452                                                       db, wri_abspath,
1453                                                       tc->reason,
1454                                                       tc->action,
1455                                                       NULL,
1456                                                       scratch_pool,
1457                                                       scratch_pool));
1458
1459       switch (tc->operation)
1460         {
1461           case svn_wc_operation_update:
1462           default:
1463             SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_data,
1464                                                        tc->src_left_version,
1465                                                        tc->src_right_version,
1466                                                        scratch_pool,
1467                                                        scratch_pool));
1468             break;
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,
1473                                                         scratch_pool,
1474                                                         scratch_pool));
1475             break;
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,
1480                                                        scratch_pool,
1481                                                        scratch_pool));
1482             break;
1483         }
1484     }
1485   else if (conflict_data)
1486     {
1487       SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_data, NULL, NULL,
1488                                                   scratch_pool,
1489                                                   scratch_pool));
1490     }
1491
1492   *conflicts = conflict_data;
1493   return SVN_NO_ERROR;
1494 }
1495
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)
1503 {
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);
1516
1517   SVN_ERR(svn_wc__upgrade_conflict_skel_from_raw(&conflict_data,
1518                                                  wc_db, wcroot_abspath,
1519                                                  local_relpath,
1520                                                  conflict_old,
1521                                                  conflict_wrk,
1522                                                  conflict_new,
1523                                                  prop_reject,
1524                                                  tree_conflict_data,
1525                                                  tree_conflict_size,
1526                                                  scratch_pool, scratch_pool));
1527
1528   SVN_ERR_ASSERT(conflict_data != NULL);
1529
1530   skel_data = svn_skel__unparse(conflict_data, scratch_pool);
1531
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));
1537
1538   return SVN_NO_ERROR;
1539 }
1540
1541 static svn_error_t *
1542 bump_to_30(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1543 {
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 */
1549
1550   SVN_ERR(svn_wc__db_open(&db, NULL, TRUE /* open_without_upgrade */, FALSE,
1551                           scratch_pool, scratch_pool));
1552
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));
1556
1557   while (have_row)
1558     {
1559       svn_error_t *err;
1560       svn_pool_clear(iterpool);
1561
1562       err = bump_30_upgrade_one_conflict(db, bb->wcroot_abspath, stmt, sdb,
1563                                          iterpool);
1564
1565       if (err)
1566         {
1567           return svn_error_trace(
1568                     svn_error_compose_create(
1569                             err,
1570                             svn_sqlite__reset(stmt)));
1571         }
1572
1573       SVN_ERR(svn_sqlite__step(&have_row, stmt));
1574     }
1575   SVN_ERR(svn_sqlite__reset(stmt));
1576
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;
1580 }
1581
1582 static svn_error_t *
1583 bump_to_31(void *baton,
1584            svn_sqlite__db_t *sdb,
1585            apr_pool_t *scratch_pool)
1586 {
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;
1593   svn_error_t *err;
1594
1595   /* Add the inherited_props column to NODES if it does not yet exist.
1596    *
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.
1602    *
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.
1606    */
1607   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_PRAGMA_TABLE_INFO_NODES));
1608   SVN_ERR(svn_sqlite__step(&have_row, stmt));
1609   while (have_row)
1610     {
1611       const char *column_name = svn_sqlite__column_text(stmt, 1, NULL);
1612
1613       if (strcmp(column_name, "inherited_props") == 0)
1614         {
1615           iprops_column_exists = TRUE;
1616           break;
1617         }
1618
1619       SVN_ERR(svn_sqlite__step(&have_row, stmt));
1620     }
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));
1624
1625   /* Run additional statements to finalize the upgrade to format 31. */
1626   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_31_FINALIZE));
1627
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));
1634
1635   err = svn_sqlite__get_statement(&stmt_mark_switch_roots, sdb,
1636                                   STMT_UPDATE_IPROP);
1637   if (err)
1638     return svn_error_compose_create(err, svn_sqlite__reset(stmt));
1639
1640   while (have_row)
1641     {
1642       const char *switched_relpath = svn_sqlite__column_text(stmt, 1, NULL);
1643       apr_int64_t wc_id = svn_sqlite__column_int64(stmt, 0);
1644
1645       err = svn_sqlite__bindf(stmt_mark_switch_roots, "is", wc_id,
1646                               switched_relpath);
1647       if (!err)
1648         err = svn_sqlite__bind_iprops(stmt_mark_switch_roots, 3,
1649                                       empty_iprops, iterpool);
1650       if (!err)
1651         err = svn_sqlite__step_done(stmt_mark_switch_roots);
1652       if (!err)
1653         err = svn_sqlite__step(&have_row, stmt);
1654
1655       if (err)
1656         return svn_error_compose_create(
1657                 err,
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)));
1662     }
1663
1664   err = svn_sqlite__reset(stmt_mark_switch_roots);
1665   if (err)
1666     return svn_error_compose_create(err, svn_sqlite__reset(stmt));
1667   SVN_ERR(svn_sqlite__reset(stmt));
1668
1669   svn_pool_destroy(iterpool);
1670
1671   return SVN_NO_ERROR;
1672 }
1673
1674
1675 struct upgrade_data_t {
1676   svn_sqlite__db_t *sdb;
1677   const char *root_abspath;
1678   apr_int64_t repos_id;
1679   apr_int64_t wc_id;
1680 };
1681
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)'.
1684
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
1688    repository.
1689
1690    *DATA refers to the single root db.
1691
1692    Uses SCRATCH_POOL for all temporary allocation.  */
1693 static svn_error_t *
1694 upgrade_to_wcng(void **dir_baton,
1695                 void *parent_baton,
1696                 svn_wc__db_t *db,
1697                 const char *dir_abspath,
1698                 int old_format,
1699                 apr_int64_t wc_id,
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)
1706 {
1707   const char *logfile_path = svn_wc__adm_child(dir_abspath, ADM_LOG,
1708                                                scratch_pool);
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;
1714   svn_error_t *err;
1715
1716   /* Don't try to mess with the WC if there are old log files left. */
1717
1718   /* Is the (first) log file present?  */
1719   SVN_ERR(svn_io_check_path(logfile_path, &logfile_on_disk_kind,
1720                             scratch_pool));
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"));
1729
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));
1734
1735   /* What's going on here?
1736    *
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:
1740    *
1741    * 1) Read the old 'entries' using the old-format reader.
1742    *
1743    * 2) Create the new DB if it hasn't already been created.
1744    *
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
1748    *    even have that.
1749    *
1750    * 4) Convert wcprop to the wc-ng format
1751    *
1752    * 5) Migrate regular properties to the WC-NG DB.
1753    */
1754
1755   /***** ENTRIES - READ *****/
1756   SVN_ERR(svn_wc__read_entries_old(&entries, dir_abspath,
1757                                    scratch_pool, scratch_pool));
1758
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,
1762                             repos_cache,
1763                             scratch_pool, scratch_pool));
1764
1765   /* Cache repos UUID pairs for when a subdir doesn't have this information */
1766   if (!svn_hash_gets(repos_cache, this_dir->repos))
1767     {
1768       apr_pool_t *hash_pool = apr_hash_pool_get(repos_cache);
1769
1770       svn_hash_sets(repos_cache,
1771                     apr_pstrdup(hash_pool, this_dir->repos),
1772                     apr_pstrdup(hash_pool, this_dir->uuid));
1773     }
1774
1775   old_wcroot_abspath = svn_dirent_get_longest_ancestor(dir_abspath,
1776                                                        data->root_abspath,
1777                                                        scratch_pool);
1778   dir_relpath = svn_dirent_skip_ancestor(old_wcroot_abspath, dir_abspath);
1779
1780   /***** TEXT BASES *****/
1781   SVN_ERR(migrate_text_bases(&text_bases_info, dir_abspath, data->root_abspath,
1782                              data->sdb, scratch_pool, scratch_pool));
1783
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."));
1795   else
1796     SVN_ERR(err);
1797
1798   /***** WC PROPS *****/
1799   /* If we don't know precisely where the wcprops are, ignore them.  */
1800   if (old_format != SVN_WC__WCPROPS_LOST)
1801     {
1802       apr_hash_t *all_wcprops;
1803
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));
1807       else
1808         SVN_ERR(read_wcprops(&all_wcprops, dir_abspath,
1809                              scratch_pool, scratch_pool));
1810
1811       SVN_ERR(svn_wc__db_upgrade_apply_dav_cache(data->sdb, dir_relpath,
1812                                                  all_wcprops, scratch_pool));
1813     }
1814
1815   /* Upgrade all the properties (including "this dir").
1816
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));
1822
1823   return SVN_NO_ERROR;
1824 }
1825
1826 const char *
1827 svn_wc__version_string_from_format(int wc_format)
1828 {
1829   switch (wc_format)
1830     {
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";
1836     }
1837   return _("(unreleased development version)");
1838 }
1839
1840 svn_error_t *
1841 svn_wc__upgrade_sdb(int *result_format,
1842                     const char *wcroot_abspath,
1843                     svn_sqlite__db_t *sdb,
1844                     int start_format,
1845                     apr_pool_t *scratch_pool)
1846 {
1847   struct bump_baton bb;
1848
1849   bb.wcroot_abspath = wcroot_abspath;
1850
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,
1856                                                     scratch_pool),
1857                              start_format,
1858                              svn_wc__version_string_from_format(start_format));
1859
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,
1869                                                     scratch_pool),
1870                              start_format);
1871
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.  */
1874
1875   /* Note: none of these have "break" statements; the fall-through is
1876      intentional. */
1877   switch (start_format)
1878     {
1879       case 19:
1880         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_20, &bb,
1881                                              scratch_pool));
1882         *result_format = 20;
1883         /* FALLTHROUGH  */
1884
1885       case 20:
1886         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_21, &bb,
1887                                              scratch_pool));
1888         *result_format = 21;
1889         /* FALLTHROUGH  */
1890
1891       case 21:
1892         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_22, &bb,
1893                                              scratch_pool));
1894         *result_format = 22;
1895         /* FALLTHROUGH  */
1896
1897       case 22:
1898         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_23, &bb,
1899                                              scratch_pool));
1900         *result_format = 23;
1901         /* FALLTHROUGH  */
1902
1903       case 23:
1904         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_24, &bb,
1905                                              scratch_pool));
1906         *result_format = 24;
1907         /* FALLTHROUGH  */
1908
1909       case 24:
1910         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_25, &bb,
1911                                              scratch_pool));
1912         *result_format = 25;
1913         /* FALLTHROUGH  */
1914
1915       case 25:
1916         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_26, &bb,
1917                                              scratch_pool));
1918         *result_format = 26;
1919         /* FALLTHROUGH  */
1920
1921       case 26:
1922         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_27, &bb,
1923                                              scratch_pool));
1924         *result_format = 27;
1925         /* FALLTHROUGH  */
1926
1927       case 27:
1928         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_28, &bb,
1929                                              scratch_pool));
1930         *result_format = 28;
1931         /* FALLTHROUGH  */
1932
1933       case 28:
1934         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_29, &bb,
1935                                              scratch_pool));
1936         *result_format = 29;
1937         /* FALLTHROUGH  */
1938
1939       case 29:
1940         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_30, &bb,
1941                                              scratch_pool));
1942         *result_format = 30;
1943
1944       case 30:
1945         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_31, &bb,
1946                                              scratch_pool));
1947         *result_format = 31;
1948         /* FALLTHROUGH  */
1949       /* ### future bumps go here.  */
1950 #if 0
1951       case XXX-1:
1952         /* Revamp the recording of tree conflicts.  */
1953         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_XXX, &bb,
1954                                              scratch_pool));
1955         *result_format = XXX;
1956         /* FALLTHROUGH  */
1957 #endif
1958       case SVN_WC__VERSION:
1959         /* already upgraded */
1960         *result_format = SVN_WC__VERSION;
1961
1962         SVN_SQLITE__WITH_LOCK(
1963             svn_wc__db_install_schema_statistics(sdb, scratch_pool),
1964             sdb);
1965     }
1966
1967 #ifdef SVN_DEBUG
1968   if (*result_format != start_format)
1969     {
1970       int schema_version;
1971       SVN_ERR(svn_sqlite__read_schema_version(&schema_version, sdb, scratch_pool));
1972
1973       /* If this assertion fails the schema isn't updated correctly */
1974       SVN_ERR_ASSERT(schema_version == *result_format);
1975     }
1976 #endif
1977
1978   /* Zap anything that might be remaining or escaped our notice.  */
1979   wipe_obsolete_files(wcroot_abspath, scratch_pool);
1980
1981   return SVN_NO_ERROR;
1982 }
1983
1984
1985 /* */
1986 static svn_error_t *
1987 upgrade_working_copy(void *parent_baton,
1988                      svn_wc__db_t *db,
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,
1995                      void *cancel_baton,
1996                      svn_wc_notify_func2_t notify_func,
1997                      void *notify_baton,
1998                      apr_pool_t *result_pool,
1999                      apr_pool_t *scratch_pool)
2000 {
2001   void *dir_baton;
2002   int old_format;
2003   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
2004   apr_array_header_t *subdirs;
2005   svn_error_t *err;
2006   int i;
2007
2008   if (cancel_func)
2009     SVN_ERR(cancel_func(cancel_baton));
2010
2011   SVN_ERR(svn_wc__db_temp_get_format(&old_format, db, dir_abspath,
2012                                      iterpool));
2013
2014   if (old_format >= SVN_WC__WC_NG_VERSION)
2015     {
2016       if (notify_func)
2017         notify_func(notify_baton,
2018                     svn_wc_create_notify(dir_abspath, svn_wc_notify_skip,
2019                                          iterpool),
2020                 iterpool);
2021       svn_pool_destroy(iterpool);
2022       return SVN_NO_ERROR;
2023     }
2024
2025   err = get_versioned_subdirs(&subdirs, NULL, dir_abspath, FALSE,
2026                               scratch_pool, iterpool);
2027   if (err)
2028     {
2029       if (APR_STATUS_IS_ENOENT(err->apr_err)
2030           || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err))
2031         {
2032           /* An unversioned dir is obstructing a versioned dir */
2033           svn_error_clear(err);
2034           err = NULL;
2035           if (notify_func)
2036             notify_func(notify_baton,
2037                         svn_wc_create_notify(dir_abspath, svn_wc_notify_skip,
2038                                              iterpool),
2039                         iterpool);
2040         }
2041       svn_pool_destroy(iterpool);
2042       return err;
2043     }
2044
2045
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));
2050
2051   if (notify_func)
2052     notify_func(notify_baton,
2053                 svn_wc_create_notify(dir_abspath, svn_wc_notify_upgraded_path,
2054                                      iterpool),
2055                 iterpool);
2056
2057   for (i = 0; i < subdirs->nelts; ++i)
2058     {
2059       const char *child_abspath = APR_ARRAY_IDX(subdirs, i, const char *);
2060
2061       svn_pool_clear(iterpool);
2062
2063       SVN_ERR(upgrade_working_copy(dir_baton, db, child_abspath,
2064                                    repos_info_func, repos_info_baton,
2065                                    repos_cache, data,
2066                                    cancel_func, cancel_baton,
2067                                    notify_func, notify_baton,
2068                                    iterpool, iterpool));
2069     }
2070
2071   svn_pool_destroy(iterpool);
2072
2073   return SVN_NO_ERROR;
2074 }
2075
2076
2077 /* Return a verbose error if LOCAL_ABSPATH is a not a pre-1.7 working
2078    copy root */
2079 static svn_error_t *
2080 is_old_wcroot(const char *local_abspath,
2081               apr_pool_t *scratch_pool)
2082 {
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);
2088   if (err)
2089     {
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));
2094     }
2095   else if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
2096     return SVN_NO_ERROR;
2097
2098   svn_dirent_split(&parent_abspath, &name, local_abspath, scratch_pool);
2099
2100   err = svn_wc__read_entries_old(&entries, parent_abspath,
2101                                  scratch_pool, scratch_pool);
2102   if (err)
2103     {
2104       svn_error_clear(err);
2105       return SVN_NO_ERROR;
2106     }
2107
2108   entry = svn_hash_gets(entries, name);
2109   if (!entry
2110       || entry->absent
2111       || (entry->deleted && entry->schedule != svn_wc_schedule_add)
2112       || entry->depth == svn_depth_exclude)
2113     {
2114       return SVN_NO_ERROR;
2115     }
2116
2117   while (!svn_dirent_is_root(parent_abspath, strlen(parent_abspath)))
2118     {
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);
2122       if (err)
2123         {
2124           svn_error_clear(err);
2125           parent_abspath = svn_dirent_join(parent_abspath, name, scratch_pool);
2126           break;
2127         }
2128       entry = svn_hash_gets(entries, name);
2129       if (!entry
2130           || entry->absent
2131           || (entry->deleted && entry->schedule != svn_wc_schedule_add)
2132           || entry->depth == svn_depth_exclude)
2133         {
2134           parent_abspath = svn_dirent_join(parent_abspath, name, scratch_pool);
2135           break;
2136         }
2137     }
2138
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));
2145 }
2146
2147 /* Data for upgrade_working_copy_txn(). */
2148 typedef struct upgrade_working_copy_baton_t
2149 {
2150   svn_wc__db_t *db;
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;
2157   void *cancel_baton;
2158   svn_wc_notify_func2_t notify_func;
2159   void *notify_baton;
2160   apr_pool_t *result_pool;
2161 } upgrade_working_copy_baton_t;
2162
2163
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)
2169 {
2170   upgrade_working_copy_baton_t *b = baton;
2171
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));
2179 }
2180
2181 svn_error_t *
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,
2187                void *cancel_baton,
2188                svn_wc_notify_func2_t notify_func,
2189                void *notify_baton,
2190                apr_pool_t *scratch_pool)
2191 {
2192   svn_wc__db_t *db;
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;
2201   svn_error_t *err;
2202   int result_format;
2203   svn_boolean_t bumped_format;
2204
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));
2208
2209
2210   err = svn_wc__db_bump_format(&result_format, &bumped_format,
2211                                db, local_abspath,
2212                                scratch_pool);
2213   if (err)
2214     {
2215       if (err->apr_err != SVN_ERR_WC_UPGRADE_REQUIRED)
2216         {
2217           return svn_error_trace(
2218                     svn_error_compose_create(
2219                             err,
2220                             svn_wc__db_close(db)));
2221         }
2222
2223       svn_error_clear(err);
2224       /* Pre 1.7: Fall through */
2225     }
2226   else
2227     {
2228       /* Auto-upgrade worked! */
2229       SVN_ERR(svn_wc__db_close(db));
2230
2231       SVN_ERR_ASSERT(result_format == SVN_WC__VERSION);
2232
2233       if (bumped_format && notify_func)
2234         {
2235           svn_wc_notify_t *notify;
2236
2237           notify = svn_wc_create_notify(local_abspath,
2238                                         svn_wc_notify_upgraded_path,
2239                                         scratch_pool);
2240
2241           notify_func(notify_baton, notify, scratch_pool);
2242         }
2243
2244       return SVN_NO_ERROR;
2245     }
2246
2247   SVN_ERR(is_old_wcroot(local_abspath, scratch_pool));
2248
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
2256      upgrade. */
2257
2258   SVN_ERR(svn_wc__read_entries_old(&entries, local_abspath,
2259                                    scratch_pool, scratch_pool));
2260
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));
2265
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));
2271
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",
2274                                                         scratch_pool),
2275                                        "wcng", scratch_pool);
2276   root_adm_abspath = svn_wc__adm_child(data.root_abspath, "",
2277                                        scratch_pool);
2278   SVN_ERR(svn_io_remove_dir2(root_adm_abspath, TRUE, NULL, NULL,
2279                              scratch_pool));
2280   SVN_ERR(svn_wc__ensure_directory(root_adm_abspath, scratch_pool));
2281
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,
2287                                    scratch_pool));
2288
2289   /* Migrate the entries over to the new database.
2290    ### We need to think about atomicity here.
2291
2292    entries_write_new() writes in current format rather than
2293    f12. Thus, this function bumps a working copy all the way to
2294    current.  */
2295   SVN_ERR(svn_wc__db_wclock_obtain(db, data.root_abspath, 0, FALSE,
2296                                    scratch_pool));
2297
2298   cb_baton.db = db;
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;
2309
2310   SVN_ERR(svn_sqlite__with_lock(data.sdb,
2311                                 upgrade_working_copy_txn,
2312                                 &cb_baton,
2313                                 scratch_pool));
2314
2315   /* A workqueue item to move the pristine dir into place */
2316   pristine_from = svn_wc__adm_child(data.root_abspath, PRISTINE_STORAGE_RELPATH,
2317                                     scratch_pool);
2318   pristine_to = svn_wc__adm_child(local_abspath, PRISTINE_STORAGE_RELPATH,
2319                                   scratch_pool);
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);
2325
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));
2330
2331   SVN_ERR(svn_wc__db_wclock_release(db, data.root_abspath, scratch_pool));
2332   SVN_ERR(svn_wc__db_close(db));
2333
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));
2338
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,
2343                          scratch_pool));
2344   SVN_ERR(svn_wc__db_close(db));
2345
2346   /* Should we have the workqueue remove this empty dir? */
2347   SVN_ERR(svn_io_remove_dir2(data.root_abspath, FALSE, NULL, NULL,
2348                              scratch_pool));
2349
2350   return SVN_NO_ERROR;
2351 }
2352
2353 svn_error_t *
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)
2364 {
2365   svn_node_kind_t db_kind;
2366   switch (kind)
2367     {
2368       case svn_node_dir:
2369         db_kind = svn_node_dir;
2370         break;
2371
2372       case svn_node_file:
2373         db_kind = svn_node_file;
2374         break;
2375
2376       case svn_node_unknown:
2377         db_kind = svn_node_unknown;
2378         break;
2379
2380       default:
2381         SVN_ERR_MALFUNCTION();
2382     }
2383
2384   SVN_ERR(svn_wc__db_upgrade_insert_external(wc_ctx->db, local_abspath,
2385                                              db_kind,
2386                                              svn_dirent_dirname(local_abspath,
2387                                                                 scratch_pool),
2388                                              def_local_abspath, repos_relpath,
2389                                              repos_root_url, repos_uuid,
2390                                              def_peg_revision, def_revision,
2391                                              scratch_pool));
2392   return SVN_NO_ERROR;
2393 }