]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/libsvn_wc/upgrade.c
MFC r275385 (by bapt):
[FreeBSD/stable/10.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 #include "token-map.h"
41
42 #include "svn_private_config.h"
43 #include "private/svn_wc_private.h"
44 #include "private/svn_sqlite.h"
45 #include "private/svn_token.h"
46
47 /* WC-1.0 administrative area extensions */
48 #define SVN_WC__BASE_EXT      ".svn-base" /* for text and prop bases */
49 #define SVN_WC__WORK_EXT      ".svn-work" /* for working propfiles */
50 #define SVN_WC__REVERT_EXT    ".svn-revert" /* for reverting a replaced
51                                                file */
52
53 /* Old locations for storing "wcprops" (aka "dav cache").  */
54 #define WCPROPS_SUBDIR_FOR_FILES "wcprops"
55 #define WCPROPS_FNAME_FOR_DIR "dir-wcprops"
56 #define WCPROPS_ALL_DATA "all-wcprops"
57
58 /* Old property locations. */
59 #define PROPS_SUBDIR "props"
60 #define PROP_BASE_SUBDIR "prop-base"
61 #define PROP_BASE_FOR_DIR "dir-prop-base"
62 #define PROP_REVERT_FOR_DIR "dir-prop-revert"
63 #define PROP_WORKING_FOR_DIR "dir-props"
64
65 /* Old textbase location. */
66 #define TEXT_BASE_SUBDIR "text-base"
67
68 #define TEMP_DIR "tmp"
69
70 /* Old data files that we no longer need/use.  */
71 #define ADM_README "README.txt"
72 #define ADM_EMPTY_FILE "empty-file"
73 #define ADM_LOG "log"
74 #define ADM_LOCK "lock"
75
76 /* New pristine location */
77 #define PRISTINE_STORAGE_RELPATH "pristine"
78 #define PRISTINE_STORAGE_EXT ".svn-base"
79 /* Number of characters in a pristine file basename, in WC format <= 28. */
80 #define PRISTINE_BASENAME_OLD_LEN 40
81 #define SDB_FILE  "wc.db"
82
83
84 /* Read the properties from the file at PROPFILE_ABSPATH, returning them
85    as a hash in *PROPS. If the propfile is NOT present, then NULL will
86    be returned in *PROPS.  */
87 static svn_error_t *
88 read_propfile(apr_hash_t **props,
89               const char *propfile_abspath,
90               apr_pool_t *result_pool,
91               apr_pool_t *scratch_pool)
92 {
93   svn_error_t *err;
94   svn_stream_t *stream;
95   apr_finfo_t finfo;
96
97   err = svn_io_stat(&finfo, propfile_abspath, APR_FINFO_SIZE, scratch_pool);
98
99   if (err
100       && (APR_STATUS_IS_ENOENT(err->apr_err)
101           || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)))
102     {
103       svn_error_clear(err);
104
105       /* The propfile was not there. Signal with a NULL.  */
106       *props = NULL;
107       return SVN_NO_ERROR;
108     }
109   else
110     SVN_ERR(err);
111
112   /* A 0-bytes file signals an empty property list.
113      (mostly used for revert-props) */
114   if (finfo.size == 0)
115     {
116       *props = apr_hash_make(result_pool);
117       return SVN_NO_ERROR;
118     }
119
120   SVN_ERR(svn_stream_open_readonly(&stream, propfile_abspath,
121                                    scratch_pool, scratch_pool));
122
123   /* ### does this function need to be smarter? will we see zero-length
124      ### files? see props.c::load_props(). there may be more work here.
125      ### need a historic analysis of 1.x property storage. what will we
126      ### actually run into?  */
127
128   /* ### loggy_write_properties() and immediate_install_props() write
129      ### zero-length files for "no props", so we should be a bit smarter
130      ### in here.  */
131
132   /* ### should we be forgiving in here? I say "no". if we can't be sure,
133      ### then we could effectively corrupt the local working copy.  */
134
135   *props = apr_hash_make(result_pool);
136   SVN_ERR(svn_hash_read2(*props, stream, SVN_HASH_TERMINATOR, result_pool));
137
138   return svn_error_trace(svn_stream_close(stream));
139 }
140
141
142 /* Read one proplist (allocated from RESULT_POOL) from STREAM, and place it
143    into ALL_WCPROPS at NAME.  */
144 static svn_error_t *
145 read_one_proplist(apr_hash_t *all_wcprops,
146                   const char *name,
147                   svn_stream_t *stream,
148                   apr_pool_t *result_pool,
149                   apr_pool_t *scratch_pool)
150 {
151   apr_hash_t *proplist;
152
153   proplist = apr_hash_make(result_pool);
154   SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, result_pool));
155   svn_hash_sets(all_wcprops, name, proplist);
156
157   return SVN_NO_ERROR;
158 }
159
160
161 /* Read the wcprops from all the files in the admin area of DIR_ABSPATH,
162    returning them in *ALL_WCPROPS. Results are allocated in RESULT_POOL,
163    and temporary allocations are performed in SCRATCH_POOL.  */
164 static svn_error_t *
165 read_many_wcprops(apr_hash_t **all_wcprops,
166                   const char *dir_abspath,
167                   apr_pool_t *result_pool,
168                   apr_pool_t *scratch_pool)
169 {
170   const char *propfile_abspath;
171   apr_hash_t *wcprops;
172   apr_hash_t *dirents;
173   const char *props_dir_abspath;
174   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
175   apr_hash_index_t *hi;
176
177   *all_wcprops = apr_hash_make(result_pool);
178
179   /* First, look at dir-wcprops. */
180   propfile_abspath = svn_wc__adm_child(dir_abspath, WCPROPS_FNAME_FOR_DIR,
181                                        scratch_pool);
182   SVN_ERR(read_propfile(&wcprops, propfile_abspath, result_pool, iterpool));
183   if (wcprops != NULL)
184     svn_hash_sets(*all_wcprops, SVN_WC_ENTRY_THIS_DIR, wcprops);
185
186   props_dir_abspath = svn_wc__adm_child(dir_abspath, WCPROPS_SUBDIR_FOR_FILES,
187                                         scratch_pool);
188
189   /* Now walk the wcprops directory. */
190   SVN_ERR(svn_io_get_dirents3(&dirents, props_dir_abspath, TRUE,
191                               scratch_pool, scratch_pool));
192
193   for (hi = apr_hash_first(scratch_pool, dirents);
194        hi;
195        hi = apr_hash_next(hi))
196     {
197       const char *name = apr_hash_this_key(hi);
198
199       svn_pool_clear(iterpool);
200
201       propfile_abspath = svn_dirent_join(props_dir_abspath, name, iterpool);
202
203       SVN_ERR(read_propfile(&wcprops, propfile_abspath,
204                             result_pool, iterpool));
205       SVN_ERR_ASSERT(wcprops != NULL);
206       svn_hash_sets(*all_wcprops, apr_pstrdup(result_pool, name), wcprops);
207     }
208
209   svn_pool_destroy(iterpool);
210   return SVN_NO_ERROR;
211 }
212
213
214 /* For wcprops stored in a single file in this working copy, read that
215    file and return it in *ALL_WCPROPS, allocated in RESULT_POOL.   Use
216    SCRATCH_POOL for temporary allocations. */
217 static svn_error_t *
218 read_wcprops(apr_hash_t **all_wcprops,
219              const char *dir_abspath,
220              apr_pool_t *result_pool,
221              apr_pool_t *scratch_pool)
222 {
223   svn_stream_t *stream;
224   svn_error_t *err;
225
226   *all_wcprops = apr_hash_make(result_pool);
227
228   err = svn_wc__open_adm_stream(&stream, dir_abspath,
229                                 WCPROPS_ALL_DATA,
230                                 scratch_pool, scratch_pool);
231
232   /* A non-existent file means there are no props. */
233   if (err && APR_STATUS_IS_ENOENT(err->apr_err))
234     {
235       svn_error_clear(err);
236       return SVN_NO_ERROR;
237     }
238   SVN_ERR(err);
239
240   /* Read the proplist for THIS_DIR. */
241   SVN_ERR(read_one_proplist(*all_wcprops, SVN_WC_ENTRY_THIS_DIR, stream,
242                             result_pool, scratch_pool));
243
244   /* And now, the children. */
245   while (1729)
246     {
247       svn_stringbuf_t *line;
248       svn_boolean_t eof;
249
250       SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, result_pool));
251       if (eof)
252         {
253           if (line->len > 0)
254             return svn_error_createf
255               (SVN_ERR_WC_CORRUPT, NULL,
256                _("Missing end of line in wcprops file for '%s'"),
257                svn_dirent_local_style(dir_abspath, scratch_pool));
258           break;
259         }
260       SVN_ERR(read_one_proplist(*all_wcprops, line->data, stream,
261                                 result_pool, scratch_pool));
262     }
263
264   return svn_error_trace(svn_stream_close(stream));
265 }
266
267 /* Return in CHILDREN, the list of all 1.6 versioned subdirectories
268    which also exist on disk as directories.
269
270    If DELETE_DIR is not NULL set *DELETE_DIR to TRUE if the directory
271    should be deleted after migrating to WC-NG, otherwise to FALSE.
272
273    If SKIP_MISSING is TRUE, don't add missing or obstructed subdirectories
274    to the list of children.
275    */
276 static svn_error_t *
277 get_versioned_subdirs(apr_array_header_t **children,
278                       svn_boolean_t *delete_dir,
279                       const char *dir_abspath,
280                       svn_boolean_t skip_missing,
281                       apr_pool_t *result_pool,
282                       apr_pool_t *scratch_pool)
283 {
284   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
285   apr_hash_t *entries;
286   apr_hash_index_t *hi;
287   svn_wc_entry_t *this_dir = NULL;
288
289   *children = apr_array_make(result_pool, 10, sizeof(const char *));
290
291   SVN_ERR(svn_wc__read_entries_old(&entries, dir_abspath,
292                                    scratch_pool, iterpool));
293   for (hi = apr_hash_first(scratch_pool, entries);
294        hi;
295        hi = apr_hash_next(hi))
296     {
297       const char *name = apr_hash_this_key(hi);
298       const svn_wc_entry_t *entry = apr_hash_this_val(hi);
299       const char *child_abspath;
300       svn_boolean_t hidden;
301
302       /* skip "this dir"  */
303       if (*name == '\0')
304         {
305           this_dir = apr_hash_this_val(hi);
306           continue;
307         }
308       else if (entry->kind != svn_node_dir)
309         continue;
310
311       svn_pool_clear(iterpool);
312
313       /* If a directory is 'hidden' skip it as subdir */
314       SVN_ERR(svn_wc__entry_is_hidden(&hidden, entry));
315       if (hidden)
316         continue;
317
318       child_abspath = svn_dirent_join(dir_abspath, name, scratch_pool);
319
320       if (skip_missing)
321         {
322           svn_node_kind_t kind;
323           SVN_ERR(svn_io_check_path(child_abspath, &kind, scratch_pool));
324
325           if (kind != svn_node_dir)
326             continue;
327         }
328
329       APR_ARRAY_PUSH(*children, const char *) = apr_pstrdup(result_pool,
330                                                             child_abspath);
331     }
332
333   svn_pool_destroy(iterpool);
334
335   if (delete_dir != NULL)
336     {
337       *delete_dir = (this_dir != NULL)
338                      && (this_dir->schedule == svn_wc_schedule_delete)
339                      && ! this_dir->keep_local;
340     }
341
342   return SVN_NO_ERROR;
343 }
344
345
346 /* Return in CHILDREN the names of all versioned *files* in SDB that
347    are children of PARENT_RELPATH.  These files' existence on disk is
348    not tested.
349
350    This set of children is intended for property upgrades.
351    Subdirectory's properties exist in the subdirs.
352
353    Note that this uses just the SDB to locate children, which means
354    that the children must have been upgraded to wc-ng format. */
355 static svn_error_t *
356 get_versioned_files(const apr_array_header_t **children,
357                     const char *parent_relpath,
358                     svn_sqlite__db_t *sdb,
359                     apr_int64_t wc_id,
360                     apr_pool_t *result_pool,
361                     apr_pool_t *scratch_pool)
362 {
363   svn_sqlite__stmt_t *stmt;
364   apr_array_header_t *child_names;
365   svn_boolean_t have_row;
366
367   /* ### just select 'file' children. do we need 'symlink' in the future?  */
368   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_ALL_FILES));
369   SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, parent_relpath));
370
371   /* ### 10 is based on Subversion's average of 8.5 files per versioned
372      ### directory in its repository. maybe use a different value? or
373      ### count rows first?  */
374   child_names = apr_array_make(result_pool, 10, sizeof(const char *));
375
376   SVN_ERR(svn_sqlite__step(&have_row, stmt));
377   while (have_row)
378     {
379       const char *local_relpath = svn_sqlite__column_text(stmt, 0,
380                                                           result_pool);
381
382       APR_ARRAY_PUSH(child_names, const char *)
383         = svn_relpath_basename(local_relpath, result_pool);
384
385       SVN_ERR(svn_sqlite__step(&have_row, stmt));
386     }
387
388   *children = child_names;
389
390   return svn_error_trace(svn_sqlite__reset(stmt));
391 }
392
393
394 /* Return the path of the old-school administrative lock file
395    associated with LOCAL_DIR_ABSPATH, allocated from RESULT_POOL. */
396 static const char *
397 build_lockfile_path(const char *local_dir_abspath,
398                     apr_pool_t *result_pool)
399 {
400   return svn_dirent_join_many(result_pool,
401                               local_dir_abspath,
402                               svn_wc_get_adm_dir(result_pool),
403                               ADM_LOCK,
404                               SVN_VA_NULL);
405 }
406
407
408 /* Create a physical lock file in the admin directory for ABSPATH.  */
409 static svn_error_t *
410 create_physical_lock(const char *abspath, apr_pool_t *scratch_pool)
411 {
412   const char *lock_abspath = build_lockfile_path(abspath, scratch_pool);
413   svn_error_t *err;
414   apr_file_t *file;
415
416   err = svn_io_file_open(&file, lock_abspath,
417                          APR_WRITE | APR_CREATE | APR_EXCL,
418                          APR_OS_DEFAULT,
419                          scratch_pool);
420
421   if (err && APR_STATUS_IS_EEXIST(err->apr_err))
422     {
423       /* Congratulations, we just stole a physical lock from somebody */
424       svn_error_clear(err);
425       return SVN_NO_ERROR;
426     }
427
428   return svn_error_trace(err);
429 }
430
431
432 /* Wipe out all the obsolete files/dirs from the administrative area.  */
433 static void
434 wipe_obsolete_files(const char *wcroot_abspath, apr_pool_t *scratch_pool)
435 {
436   /* Zap unused files.  */
437   svn_error_clear(svn_io_remove_file2(
438                     svn_wc__adm_child(wcroot_abspath,
439                                       SVN_WC__ADM_FORMAT,
440                                       scratch_pool),
441                     TRUE, scratch_pool));
442   svn_error_clear(svn_io_remove_file2(
443                     svn_wc__adm_child(wcroot_abspath,
444                                       SVN_WC__ADM_ENTRIES,
445                                       scratch_pool),
446                     TRUE, scratch_pool));
447   svn_error_clear(svn_io_remove_file2(
448                     svn_wc__adm_child(wcroot_abspath,
449                                       ADM_EMPTY_FILE,
450                                       scratch_pool),
451                     TRUE, scratch_pool));
452   svn_error_clear(svn_io_remove_file2(
453                     svn_wc__adm_child(wcroot_abspath,
454                                       ADM_README,
455                                       scratch_pool),
456                     TRUE, scratch_pool));
457
458   /* For formats <= SVN_WC__WCPROPS_MANY_FILES_VERSION, we toss the wcprops
459      for the directory itself, and then all the wcprops for the files.  */
460   svn_error_clear(svn_io_remove_file2(
461                     svn_wc__adm_child(wcroot_abspath,
462                                       WCPROPS_FNAME_FOR_DIR,
463                                       scratch_pool),
464                     TRUE, scratch_pool));
465   svn_error_clear(svn_io_remove_dir2(
466                     svn_wc__adm_child(wcroot_abspath,
467                                       WCPROPS_SUBDIR_FOR_FILES,
468                                       scratch_pool),
469                     FALSE, NULL, NULL, scratch_pool));
470
471   /* And for later formats, they are aggregated into one file.  */
472   svn_error_clear(svn_io_remove_file2(
473                     svn_wc__adm_child(wcroot_abspath,
474                                       WCPROPS_ALL_DATA,
475                                       scratch_pool),
476                     TRUE, scratch_pool));
477
478   /* Remove the old text-base directory and the old text-base files. */
479   svn_error_clear(svn_io_remove_dir2(
480                     svn_wc__adm_child(wcroot_abspath,
481                                       TEXT_BASE_SUBDIR,
482                                       scratch_pool),
483                     FALSE, NULL, NULL, scratch_pool));
484
485   /* Remove the old properties files... whole directories at a time.  */
486   svn_error_clear(svn_io_remove_dir2(
487                     svn_wc__adm_child(wcroot_abspath,
488                                       PROPS_SUBDIR,
489                                       scratch_pool),
490                     FALSE, NULL, NULL, scratch_pool));
491   svn_error_clear(svn_io_remove_dir2(
492                     svn_wc__adm_child(wcroot_abspath,
493                                       PROP_BASE_SUBDIR,
494                                       scratch_pool),
495                     FALSE, NULL, NULL, scratch_pool));
496   svn_error_clear(svn_io_remove_file2(
497                      svn_wc__adm_child(wcroot_abspath,
498                                        PROP_WORKING_FOR_DIR,
499                                        scratch_pool),
500                      TRUE, scratch_pool));
501   svn_error_clear(svn_io_remove_file2(
502                      svn_wc__adm_child(wcroot_abspath,
503                                       PROP_BASE_FOR_DIR,
504                                       scratch_pool),
505                      TRUE, scratch_pool));
506   svn_error_clear(svn_io_remove_file2(
507                      svn_wc__adm_child(wcroot_abspath,
508                                       PROP_REVERT_FOR_DIR,
509                                       scratch_pool),
510                      TRUE, scratch_pool));
511
512 #if 0
513   /* ### this checks for a write-lock, and we are not (always) taking out
514      ### a write lock in all callers.  */
515   SVN_ERR(svn_wc__adm_cleanup_tmp_area(db, wcroot_abspath, iterpool));
516 #endif
517
518   /* Remove the old-style lock file LAST.  */
519   svn_error_clear(svn_io_remove_file2(
520                     build_lockfile_path(wcroot_abspath, scratch_pool),
521                     TRUE, scratch_pool));
522 }
523
524 svn_error_t *
525 svn_wc__wipe_postupgrade(const char *dir_abspath,
526                          svn_boolean_t whole_admin,
527                          svn_cancel_func_t cancel_func,
528                          void *cancel_baton,
529                          apr_pool_t *scratch_pool)
530 {
531   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
532   apr_array_header_t *subdirs;
533   svn_error_t *err;
534   svn_boolean_t delete_dir;
535   int i;
536
537   if (cancel_func)
538     SVN_ERR((*cancel_func)(cancel_baton));
539
540   err = get_versioned_subdirs(&subdirs, &delete_dir, dir_abspath, TRUE,
541                               scratch_pool, iterpool);
542   if (err)
543     {
544       if (APR_STATUS_IS_ENOENT(err->apr_err))
545         {
546           /* An unversioned dir is obstructing a versioned dir */
547           svn_error_clear(err);
548           err = NULL;
549         }
550       svn_pool_destroy(iterpool);
551       return svn_error_trace(err);
552     }
553   for (i = 0; i < subdirs->nelts; ++i)
554     {
555       const char *child_abspath = APR_ARRAY_IDX(subdirs, i, const char *);
556
557       svn_pool_clear(iterpool);
558       SVN_ERR(svn_wc__wipe_postupgrade(child_abspath, TRUE,
559                                        cancel_func, cancel_baton, iterpool));
560     }
561
562   /* ### Should we really be ignoring errors here? */
563   if (whole_admin)
564     svn_error_clear(svn_io_remove_dir2(svn_wc__adm_child(dir_abspath, "",
565                                                          iterpool),
566                                        TRUE, NULL, NULL, iterpool));
567   else
568     wipe_obsolete_files(dir_abspath, scratch_pool);
569
570   if (delete_dir)
571     {
572       /* If this was a WC-NG single database copy, this directory wouldn't
573          be here (unless it was deleted with --keep-local)
574
575          If the directory is empty, we can just delete it; if not we
576          keep it.
577        */
578       svn_error_clear(svn_io_dir_remove_nonrecursive(dir_abspath, iterpool));
579     }
580
581   svn_pool_destroy(iterpool);
582
583   return SVN_NO_ERROR;
584 }
585
586 /* Ensure that ENTRY has its REPOS and UUID fields set. These will be
587    used to establish the REPOSITORY row in the new database, and then
588    used within the upgraded entries as they are written into the database.
589
590    If one or both are not available, then it attempts to retrieve this
591    information from REPOS_CACHE. And if that fails from REPOS_INFO_FUNC,
592    passing REPOS_INFO_BATON.
593    Returns a user understandable error using LOCAL_ABSPATH if the
594    information cannot be obtained.  */
595 static svn_error_t *
596 ensure_repos_info(svn_wc_entry_t *entry,
597                   const char *local_abspath,
598                   svn_wc_upgrade_get_repos_info_t repos_info_func,
599                   void *repos_info_baton,
600                   apr_hash_t *repos_cache,
601                   apr_pool_t *result_pool,
602                   apr_pool_t *scratch_pool)
603 {
604   /* Easy exit.  */
605   if (entry->repos != NULL && entry->uuid != NULL)
606     return SVN_NO_ERROR;
607
608   if ((entry->repos == NULL || entry->uuid == NULL)
609       && entry->url)
610     {
611       apr_hash_index_t *hi;
612
613       for (hi = apr_hash_first(scratch_pool, repos_cache);
614            hi; hi = apr_hash_next(hi))
615         {
616           if (svn_uri__is_ancestor(apr_hash_this_key(hi), entry->url))
617             {
618               if (!entry->repos)
619                 entry->repos = apr_hash_this_key(hi);
620
621               if (!entry->uuid)
622                 entry->uuid = apr_hash_this_val(hi);
623
624               return SVN_NO_ERROR;
625             }
626         }
627     }
628
629   if (entry->repos == NULL && repos_info_func == NULL)
630     return svn_error_createf(
631         SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
632         _("Working copy '%s' can't be upgraded because the repository root is "
633           "not available and can't be retrieved"),
634         svn_dirent_local_style(local_abspath, scratch_pool));
635
636   if (entry->uuid == NULL && repos_info_func == NULL)
637     return svn_error_createf(
638         SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
639         _("Working copy '%s' can't be upgraded because the repository uuid is "
640           "not available and can't be retrieved"),
641         svn_dirent_local_style(local_abspath, scratch_pool));
642
643    if (entry->url == NULL)
644      return svn_error_createf(
645         SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
646         _("Working copy '%s' can't be upgraded because it doesn't have a url"),
647         svn_dirent_local_style(local_abspath, scratch_pool));
648
649    return svn_error_trace((*repos_info_func)(&entry->repos, &entry->uuid,
650                                              repos_info_baton,
651                                              entry->url,
652                                              result_pool, scratch_pool));
653 }
654
655
656 /*
657  * Read tree conflict descriptions from @a conflict_data.  Set @a *conflicts
658  * to a hash of pointers to svn_wc_conflict_description2_t objects indexed by
659  * svn_wc_conflict_description2_t.local_abspath, all newly allocated in @a
660  * pool.  @a dir_path is the path to the working copy directory whose conflicts
661  * are being read.  The conflicts read are the tree conflicts on the immediate
662  * child nodes of @a dir_path.  Do all allocations in @a pool.
663  *
664  * Note: There were some concerns about this function:
665  *
666  * ### this is BAD. the CONFLICTS structure should not be dependent upon
667  * ### DIR_PATH. each conflict should be labeled with an entry name, not
668  * ### a whole path. (and a path which happens to vary based upon invocation
669  * ### of the user client and these APIs)
670  *
671  * those assumptions were baked into former versions of the data model, so
672  * they have to stick around here.  But they have been removed from the
673  * New Way. */
674 static svn_error_t *
675 read_tree_conflicts(apr_hash_t **conflicts,
676                     const char *conflict_data,
677                     const char *dir_path,
678                     apr_pool_t *pool)
679 {
680   const svn_skel_t *skel;
681   apr_pool_t *iterpool;
682
683   *conflicts = apr_hash_make(pool);
684
685   if (conflict_data == NULL)
686     return SVN_NO_ERROR;
687
688   skel = svn_skel__parse(conflict_data, strlen(conflict_data), pool);
689   if (skel == NULL)
690     return svn_error_create(SVN_ERR_WC_CORRUPT, NULL,
691                             _("Error parsing tree conflict skel"));
692
693   iterpool = svn_pool_create(pool);
694   for (skel = skel->children; skel != NULL; skel = skel->next)
695     {
696       const svn_wc_conflict_description2_t *conflict;
697
698       svn_pool_clear(iterpool);
699       SVN_ERR(svn_wc__deserialize_conflict(&conflict, skel, dir_path,
700                                            pool, iterpool));
701       if (conflict != NULL)
702         svn_hash_sets(*conflicts,
703                       svn_dirent_basename(conflict->local_abspath, pool),
704                       conflict);
705     }
706   svn_pool_destroy(iterpool);
707
708   return SVN_NO_ERROR;
709 }
710
711 /* */
712 static svn_error_t *
713 migrate_single_tree_conflict_data(svn_sqlite__db_t *sdb,
714                                   const char *tree_conflict_data,
715                                   apr_int64_t wc_id,
716                                   const char *local_relpath,
717                                   apr_pool_t *scratch_pool)
718 {
719   apr_hash_t *conflicts;
720   apr_hash_index_t *hi;
721   apr_pool_t *iterpool;
722
723   SVN_ERR(read_tree_conflicts(&conflicts, tree_conflict_data, local_relpath,
724                               scratch_pool));
725
726   iterpool = svn_pool_create(scratch_pool);
727   for (hi = apr_hash_first(scratch_pool, conflicts);
728        hi;
729        hi = apr_hash_next(hi))
730     {
731       const svn_wc_conflict_description2_t *conflict = apr_hash_this_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));
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));
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 /* ### need much more docco
829
830    ### this function should be called within a sqlite transaction. it makes
831    ### assumptions around this fact.
832
833    Apply the various sets of properties to the database nodes based on
834    their existence/presence, the current state of the node, and the original
835    format of the working copy which provided these property sets.
836 */
837 static svn_error_t *
838 upgrade_apply_props(svn_sqlite__db_t *sdb,
839                     const char *dir_abspath,
840                     const char *local_relpath,
841                     apr_hash_t *base_props,
842                     apr_hash_t *revert_props,
843                     apr_hash_t *working_props,
844                     int original_format,
845                     apr_int64_t wc_id,
846                     apr_pool_t *scratch_pool)
847 {
848   svn_sqlite__stmt_t *stmt;
849   svn_boolean_t have_row;
850   int top_op_depth = -1;
851   int below_op_depth = -1;
852   svn_wc__db_status_t top_presence;
853   svn_wc__db_status_t below_presence;
854   int affected_rows;
855
856   /* ### working_props: use set_props_txn.
857      ### if working_props == NULL, then skip. what if they equal the
858      ### pristine props? we should probably do the compare here.
859      ###
860      ### base props go into WORKING_NODE if avail, otherwise BASE.
861      ###
862      ### revert only goes into BASE. (and WORKING better be there!)
863
864      Prior to 1.4.0 (ORIGINAL_FORMAT < 8), REVERT_PROPS did not exist. If a
865      file was deleted, then a copy (potentially with props) was disallowed
866      and could not replace the deletion. An addition *could* be performed,
867      but that would never bring its own props.
868
869      1.4.0 through 1.4.5 created the concept of REVERT_PROPS, but had a
870      bug in svn_wc_add_repos_file2() whereby a copy-with-props did NOT
871      construct a REVERT_PROPS if the target had no props. Thus, reverting
872      the delete/copy would see no REVERT_PROPS to restore, leaving the
873      props from the copy source intact, and appearing as if they are (now)
874      the base props for the previously-deleted file. (wc corruption)
875
876      1.4.6 ensured that an empty REVERT_PROPS would be established at all
877      times. See issue 2530, and r861670 as starting points.
878
879      We will use ORIGINAL_FORMAT and SVN_WC__NO_REVERT_FILES to determine
880      the handling of our inputs, relative to the state of this node.
881   */
882
883   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_NODE_INFO));
884   SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
885   SVN_ERR(svn_sqlite__step(&have_row, stmt));
886   if (have_row)
887     {
888       top_op_depth = svn_sqlite__column_int(stmt, 0);
889       top_presence = svn_sqlite__column_token(stmt, 3, presence_map);
890       SVN_ERR(svn_sqlite__step(&have_row, stmt));
891       if (have_row)
892         {
893           below_presence = svn_sqlite__column_token(stmt, 3, presence_map);
894
895           /* There might be an intermediate layer on mixed-revision copies,
896              or when BASE is shadowed */
897           if (below_presence == svn_wc__db_status_not_present
898               || below_presence == svn_wc__db_status_deleted)
899             SVN_ERR(svn_sqlite__step(&have_row, stmt));
900
901           if (have_row)
902             {
903               below_presence = svn_sqlite__column_token(stmt, 3, presence_map);
904               below_op_depth = svn_sqlite__column_int(stmt, 0);
905             }
906         }
907     }
908   SVN_ERR(svn_sqlite__reset(stmt));
909
910   /* Detect the buggy scenario described above. We cannot upgrade this
911      working copy if we have no idea where BASE_PROPS should go.  */
912   if (original_format > SVN_WC__NO_REVERT_FILES
913       && revert_props == NULL
914       && top_op_depth != -1
915       && top_presence == svn_wc__db_status_normal
916       && below_op_depth != -1
917       && below_presence != svn_wc__db_status_not_present)
918     {
919       /* There should be REVERT_PROPS, so it appears that we just ran into
920          the described bug. Sigh.  */
921       return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
922                                _("The properties of '%s' are in an "
923                                  "indeterminate state and cannot be "
924                                  "upgraded. See issue #2530."),
925                                svn_dirent_local_style(
926                                  svn_dirent_join(dir_abspath, local_relpath,
927                                                  scratch_pool), scratch_pool));
928     }
929
930   /* Need at least one row, or two rows if there are revert props */
931   if (top_op_depth == -1
932       || (below_op_depth == -1 && revert_props))
933     return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
934                              _("Insufficient NODES rows for '%s'"),
935                              svn_dirent_local_style(
936                                svn_dirent_join(dir_abspath, local_relpath,
937                                                scratch_pool), scratch_pool));
938
939   /* one row, base props only: upper row gets base props
940      two rows, base props only: lower row gets base props
941      two rows, revert props only: lower row gets revert props
942      two rows, base and revert props: upper row gets base, lower gets revert */
943
944
945   if (revert_props || below_op_depth == -1)
946     {
947       SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
948                                         STMT_UPDATE_NODE_PROPS));
949       SVN_ERR(svn_sqlite__bindf(stmt, "isd",
950                                 wc_id, local_relpath, top_op_depth));
951       SVN_ERR(svn_sqlite__bind_properties(stmt, 4, base_props, scratch_pool));
952       SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
953
954       SVN_ERR_ASSERT(affected_rows == 1);
955     }
956
957   if (below_op_depth != -1)
958     {
959       apr_hash_t *props = revert_props ? revert_props : base_props;
960
961       SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
962                                         STMT_UPDATE_NODE_PROPS));
963       SVN_ERR(svn_sqlite__bindf(stmt, "isd",
964                                 wc_id, local_relpath, below_op_depth));
965       SVN_ERR(svn_sqlite__bind_properties(stmt, 4, props, scratch_pool));
966       SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
967
968       SVN_ERR_ASSERT(affected_rows == 1);
969     }
970
971   /* If there are WORKING_PROPS, then they always go into ACTUAL_NODE.  */
972   if (working_props != NULL
973       && base_props != NULL)
974     {
975       apr_array_header_t *diffs;
976
977       SVN_ERR(svn_prop_diffs(&diffs, working_props, base_props, scratch_pool));
978
979       if (diffs->nelts == 0)
980         working_props = NULL; /* No differences */
981     }
982
983   if (working_props != NULL)
984     {
985       SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
986                                   STMT_UPDATE_ACTUAL_PROPS));
987       SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
988       SVN_ERR(svn_sqlite__bind_properties(stmt, 3, working_props,
989                                           scratch_pool));
990       SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
991
992       if (affected_rows == 0)
993         {
994           /* We have to insert a row in ACTUAL */
995
996           SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
997                                             STMT_INSERT_ACTUAL_PROPS));
998           SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
999           if (*local_relpath != '\0')
1000             SVN_ERR(svn_sqlite__bind_text(stmt, 3,
1001                                           svn_relpath_dirname(local_relpath,
1002                                                               scratch_pool)));
1003           SVN_ERR(svn_sqlite__bind_properties(stmt, 4, working_props,
1004                                               scratch_pool));
1005           return svn_error_trace(svn_sqlite__step_done(stmt));
1006         }
1007     }
1008
1009   return SVN_NO_ERROR;
1010 }
1011
1012
1013 struct bump_baton {
1014   const char *wcroot_abspath;
1015 };
1016
1017 /* Migrate the properties for one node (LOCAL_ABSPATH).  */
1018 static svn_error_t *
1019 migrate_node_props(const char *dir_abspath,
1020                    const char *new_wcroot_abspath,
1021                    const char *name,
1022                    svn_sqlite__db_t *sdb,
1023                    int original_format,
1024                    apr_int64_t wc_id,
1025                    apr_pool_t *scratch_pool)
1026 {
1027   const char *base_abspath;  /* old name. nowadays: "pristine"  */
1028   const char *revert_abspath;  /* old name. nowadays: "BASE"  */
1029   const char *working_abspath;  /* old name. nowadays: "ACTUAL"  */
1030   apr_hash_t *base_props;
1031   apr_hash_t *revert_props;
1032   apr_hash_t *working_props;
1033   const char *old_wcroot_abspath
1034     = svn_dirent_get_longest_ancestor(dir_abspath, new_wcroot_abspath,
1035                                       scratch_pool);
1036   const char *dir_relpath = svn_dirent_skip_ancestor(old_wcroot_abspath,
1037                                                      dir_abspath);
1038
1039   if (*name == '\0')
1040     {
1041       base_abspath = svn_wc__adm_child(dir_abspath,
1042                                        PROP_BASE_FOR_DIR, scratch_pool);
1043       revert_abspath = svn_wc__adm_child(dir_abspath,
1044                                          PROP_REVERT_FOR_DIR, scratch_pool);
1045       working_abspath = svn_wc__adm_child(dir_abspath,
1046                                           PROP_WORKING_FOR_DIR, scratch_pool);
1047     }
1048   else
1049     {
1050       const char *basedir_abspath;
1051       const char *propsdir_abspath;
1052
1053       propsdir_abspath = svn_wc__adm_child(dir_abspath, PROPS_SUBDIR,
1054                                            scratch_pool);
1055       basedir_abspath = svn_wc__adm_child(dir_abspath, PROP_BASE_SUBDIR,
1056                                           scratch_pool);
1057
1058       base_abspath = svn_dirent_join(basedir_abspath,
1059                                      apr_pstrcat(scratch_pool,
1060                                                  name,
1061                                                  SVN_WC__BASE_EXT,
1062                                                  SVN_VA_NULL),
1063                                      scratch_pool);
1064
1065       revert_abspath = svn_dirent_join(basedir_abspath,
1066                                        apr_pstrcat(scratch_pool,
1067                                                    name,
1068                                                    SVN_WC__REVERT_EXT,
1069                                                    SVN_VA_NULL),
1070                                        scratch_pool);
1071
1072       working_abspath = svn_dirent_join(propsdir_abspath,
1073                                         apr_pstrcat(scratch_pool,
1074                                                     name,
1075                                                     SVN_WC__WORK_EXT,
1076                                                     SVN_VA_NULL),
1077                                         scratch_pool);
1078     }
1079
1080   SVN_ERR(read_propfile(&base_props, base_abspath,
1081                         scratch_pool, scratch_pool));
1082   SVN_ERR(read_propfile(&revert_props, revert_abspath,
1083                         scratch_pool, scratch_pool));
1084   SVN_ERR(read_propfile(&working_props, working_abspath,
1085                         scratch_pool, scratch_pool));
1086
1087   return svn_error_trace(upgrade_apply_props(
1088                             sdb, new_wcroot_abspath,
1089                             svn_relpath_join(dir_relpath, name, scratch_pool),
1090                             base_props, revert_props, working_props,
1091                             original_format, wc_id,
1092                             scratch_pool));
1093 }
1094
1095
1096 /* */
1097 static svn_error_t *
1098 migrate_props(const char *dir_abspath,
1099               const char *new_wcroot_abspath,
1100               svn_sqlite__db_t *sdb,
1101               int original_format,
1102               apr_int64_t wc_id,
1103               apr_pool_t *scratch_pool)
1104 {
1105   /* General logic here: iterate over all the immediate children of the root
1106      (since we aren't yet in a centralized system), and for any properties that
1107      exist, map them as follows:
1108
1109      if (revert props exist):
1110        revert  -> BASE
1111        base    -> WORKING
1112        working -> ACTUAL
1113      else if (prop pristine is working [as defined in props.c] ):
1114        base    -> WORKING
1115        working -> ACTUAL
1116      else:
1117        base    -> BASE
1118        working -> ACTUAL
1119
1120      ### the middle "test" should simply look for a WORKING_NODE row
1121
1122      Note that it is legal for "working" props to be missing. That implies
1123      no local changes to the properties.
1124   */
1125   const apr_array_header_t *children;
1126   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
1127   const char *old_wcroot_abspath
1128     = svn_dirent_get_longest_ancestor(dir_abspath, new_wcroot_abspath,
1129                                       scratch_pool);
1130   const char *dir_relpath = svn_dirent_skip_ancestor(old_wcroot_abspath,
1131                                                      dir_abspath);
1132   int i;
1133
1134   /* Migrate the props for "this dir".  */
1135   SVN_ERR(migrate_node_props(dir_abspath, new_wcroot_abspath, "", sdb,
1136                              original_format, wc_id, iterpool));
1137
1138   /* Iterate over all the files in this SDB.  */
1139   SVN_ERR(get_versioned_files(&children, dir_relpath, sdb, wc_id, scratch_pool,
1140                               iterpool));
1141   for (i = 0; i < children->nelts; i++)
1142     {
1143       const char *name = APR_ARRAY_IDX(children, i, const char *);
1144
1145       svn_pool_clear(iterpool);
1146
1147       SVN_ERR(migrate_node_props(dir_abspath, new_wcroot_abspath,
1148                                  name, sdb, original_format, wc_id, iterpool));
1149     }
1150
1151   svn_pool_destroy(iterpool);
1152
1153   return SVN_NO_ERROR;
1154 }
1155
1156
1157 /* If STR ends with SUFFIX and is longer than SUFFIX, return the part of
1158  * STR that comes before SUFFIX; else return NULL. */
1159 static char *
1160 remove_suffix(const char *str, const char *suffix, apr_pool_t *result_pool)
1161 {
1162   size_t str_len = strlen(str);
1163   size_t suffix_len = strlen(suffix);
1164
1165   if (str_len > suffix_len
1166       && strcmp(str + str_len - suffix_len, suffix) == 0)
1167     {
1168       return apr_pstrmemdup(result_pool, str, str_len - suffix_len);
1169     }
1170
1171   return NULL;
1172 }
1173
1174 /* Copy all the text-base files from the administrative area of WC directory
1175    DIR_ABSPATH into the pristine store of SDB which is located in directory
1176    NEW_WCROOT_ABSPATH.
1177
1178    Set *TEXT_BASES_INFO to a new hash, allocated in RESULT_POOL, that maps
1179    (const char *) name of the versioned file to (svn_wc__text_base_info_t *)
1180    information about the pristine text. */
1181 static svn_error_t *
1182 migrate_text_bases(apr_hash_t **text_bases_info,
1183                    const char *dir_abspath,
1184                    const char *new_wcroot_abspath,
1185                    svn_sqlite__db_t *sdb,
1186                    apr_pool_t *result_pool,
1187                    apr_pool_t *scratch_pool)
1188 {
1189   apr_hash_t *dirents;
1190   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
1191   apr_hash_index_t *hi;
1192   const char *text_base_dir = svn_wc__adm_child(dir_abspath,
1193                                                 TEXT_BASE_SUBDIR,
1194                                                 scratch_pool);
1195
1196   *text_bases_info = apr_hash_make(result_pool);
1197
1198   /* Iterate over the text-base files */
1199   SVN_ERR(svn_io_get_dirents3(&dirents, text_base_dir, TRUE,
1200                               scratch_pool, scratch_pool));
1201   for (hi = apr_hash_first(scratch_pool, dirents); hi;
1202        hi = apr_hash_next(hi))
1203     {
1204       const char *text_base_basename = apr_hash_this_key(hi);
1205       svn_checksum_t *md5_checksum;
1206       svn_checksum_t *sha1_checksum;
1207
1208       svn_pool_clear(iterpool);
1209
1210       /* Calculate its checksums and copy it to the pristine store */
1211       {
1212         const char *pristine_path;
1213         const char *text_base_path;
1214         const char *temp_path;
1215         svn_sqlite__stmt_t *stmt;
1216         apr_finfo_t finfo;
1217         svn_stream_t *read_stream;
1218         svn_stream_t *result_stream;
1219
1220         text_base_path = svn_dirent_join(text_base_dir, text_base_basename,
1221                                          iterpool);
1222
1223         /* Create a copy and calculate a checksum in one step */
1224         SVN_ERR(svn_stream_open_unique(&result_stream, &temp_path,
1225                                        new_wcroot_abspath,
1226                                        svn_io_file_del_none,
1227                                        iterpool, iterpool));
1228
1229         SVN_ERR(svn_stream_open_readonly(&read_stream, text_base_path,
1230                                            iterpool, iterpool));
1231
1232         read_stream = svn_stream_checksummed2(read_stream, &md5_checksum,
1233                                               NULL, svn_checksum_md5,
1234                                               TRUE, iterpool);
1235
1236         read_stream = svn_stream_checksummed2(read_stream, &sha1_checksum,
1237                                               NULL, svn_checksum_sha1,
1238                                               TRUE, iterpool);
1239
1240         /* This calculates the hash, creates a copy and closes the stream */
1241         SVN_ERR(svn_stream_copy3(read_stream, result_stream,
1242                                  NULL, NULL, iterpool));
1243
1244         SVN_ERR(svn_io_stat(&finfo, text_base_path, APR_FINFO_SIZE, iterpool));
1245
1246         /* Insert a row into the pristine table. */
1247         SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1248                                           STMT_INSERT_OR_IGNORE_PRISTINE));
1249         SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, iterpool));
1250         SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, iterpool));
1251         SVN_ERR(svn_sqlite__bind_int64(stmt, 3, finfo.size));
1252         SVN_ERR(svn_sqlite__insert(NULL, stmt));
1253
1254         SVN_ERR(svn_wc__db_pristine_get_future_path(&pristine_path,
1255                                                     new_wcroot_abspath,
1256                                                     sha1_checksum,
1257                                                     iterpool, iterpool));
1258
1259         /* Ensure any sharding directories exist. */
1260         SVN_ERR(svn_wc__ensure_directory(svn_dirent_dirname(pristine_path,
1261                                                             iterpool),
1262                                          iterpool));
1263
1264         /* Now move the file into the pristine store, overwriting
1265            existing files with the same checksum. */
1266         SVN_ERR(svn_io_file_move(temp_path, pristine_path, iterpool));
1267       }
1268
1269       /* Add the checksums for this text-base to *TEXT_BASES_INFO. */
1270       {
1271         const char *versioned_file_name;
1272         svn_boolean_t is_revert_base;
1273         svn_wc__text_base_info_t *info;
1274         svn_wc__text_base_file_info_t *file_info;
1275
1276         /* Determine the versioned file name and whether this is a normal base
1277          * or a revert base. */
1278         versioned_file_name = remove_suffix(text_base_basename,
1279                                             SVN_WC__REVERT_EXT, result_pool);
1280         if (versioned_file_name)
1281           {
1282             is_revert_base = TRUE;
1283           }
1284         else
1285           {
1286             versioned_file_name = remove_suffix(text_base_basename,
1287                                                 SVN_WC__BASE_EXT, result_pool);
1288             is_revert_base = FALSE;
1289           }
1290
1291         if (! versioned_file_name)
1292           {
1293              /* Some file that doesn't end with .svn-base or .svn-revert.
1294                 No idea why that would be in our administrative area, but
1295                 we shouldn't segfault on this case.
1296
1297                 Note that we already copied this file in the pristine store,
1298                 but the next cleanup will take care of that.
1299               */
1300             continue;
1301           }
1302
1303         /* Create a new info struct for this versioned file, or fill in the
1304          * existing one if this is the second text-base we've found for it. */
1305         info = svn_hash_gets(*text_bases_info, versioned_file_name);
1306         if (info == NULL)
1307           info = apr_pcalloc(result_pool, sizeof (*info));
1308         file_info = (is_revert_base ? &info->revert_base : &info->normal_base);
1309
1310         file_info->sha1_checksum = svn_checksum_dup(sha1_checksum, result_pool);
1311         file_info->md5_checksum = svn_checksum_dup(md5_checksum, result_pool);
1312         svn_hash_sets(*text_bases_info, versioned_file_name, info);
1313       }
1314     }
1315
1316   svn_pool_destroy(iterpool);
1317
1318   return SVN_NO_ERROR;
1319 }
1320
1321 static svn_error_t *
1322 bump_to_20(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1323 {
1324   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_NODES));
1325   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_20));
1326   return SVN_NO_ERROR;
1327 }
1328
1329 static svn_error_t *
1330 bump_to_21(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1331 {
1332   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_21));
1333   SVN_ERR(migrate_tree_conflict_data(sdb, scratch_pool));
1334   return SVN_NO_ERROR;
1335 }
1336
1337 static svn_error_t *
1338 bump_to_22(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1339 {
1340   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_22));
1341   return SVN_NO_ERROR;
1342 }
1343
1344 static svn_error_t *
1345 bump_to_23(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1346 {
1347   const char *wcroot_abspath = ((struct bump_baton *)baton)->wcroot_abspath;
1348   svn_sqlite__stmt_t *stmt;
1349   svn_boolean_t have_row;
1350
1351   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1352                                     STMT_UPGRADE_23_HAS_WORKING_NODES));
1353   SVN_ERR(svn_sqlite__step(&have_row, stmt));
1354   SVN_ERR(svn_sqlite__reset(stmt));
1355   if (have_row)
1356     return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
1357                              _("The working copy at '%s' is format 22 with "
1358                                "WORKING nodes; use a format 22 client to "
1359                                "diff/revert before using this client"),
1360                              wcroot_abspath);
1361
1362   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_23));
1363   return SVN_NO_ERROR;
1364 }
1365
1366 static svn_error_t *
1367 bump_to_24(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1368 {
1369   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_24));
1370   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_NODES_TRIGGERS));
1371   return SVN_NO_ERROR;
1372 }
1373
1374 static svn_error_t *
1375 bump_to_25(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1376 {
1377   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_25));
1378   return SVN_NO_ERROR;
1379 }
1380
1381 static svn_error_t *
1382 bump_to_26(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1383 {
1384   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_26));
1385   return SVN_NO_ERROR;
1386 }
1387
1388 static svn_error_t *
1389 bump_to_27(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1390 {
1391   const char *wcroot_abspath = ((struct bump_baton *)baton)->wcroot_abspath;
1392   svn_sqlite__stmt_t *stmt;
1393   svn_boolean_t have_row;
1394
1395   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1396                                   STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS));
1397   SVN_ERR(svn_sqlite__step(&have_row, stmt));
1398   SVN_ERR(svn_sqlite__reset(stmt));
1399   if (have_row)
1400     return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
1401                              _("The working copy at '%s' is format 26 with "
1402                                "conflicts; use a format 26 client to resolve "
1403                                "before using this client"),
1404                              wcroot_abspath);
1405   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_27));
1406   return SVN_NO_ERROR;
1407 }
1408
1409 static svn_error_t *
1410 bump_to_28(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1411 {
1412   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_28));
1413   return SVN_NO_ERROR;
1414 }
1415
1416 /* If FINFO indicates that ABSPATH names a file, rename it to
1417  * '<ABSPATH>.svn-base'.
1418  *
1419  * Ignore any file whose name is not the expected length, in order to make
1420  * life easier for any developer who runs this code twice or has some
1421  * non-standard files in the pristine directory.
1422  *
1423  * A callback for bump_to_29(), implementing #svn_io_walk_func_t. */
1424 static svn_error_t *
1425 rename_pristine_file(void *baton,
1426                      const char *abspath,
1427                      const apr_finfo_t *finfo,
1428                      apr_pool_t *pool)
1429 {
1430   if (finfo->filetype == APR_REG
1431       && (strlen(svn_dirent_basename(abspath, pool))
1432           == PRISTINE_BASENAME_OLD_LEN))
1433     {
1434       const char *new_abspath
1435         = apr_pstrcat(pool, abspath, PRISTINE_STORAGE_EXT, SVN_VA_NULL);
1436
1437       SVN_ERR(svn_io_file_rename(abspath, new_abspath, pool));
1438     }
1439   return SVN_NO_ERROR;
1440 }
1441
1442 static svn_error_t *
1443 upgrade_externals(struct bump_baton *bb,
1444                   svn_sqlite__db_t *sdb,
1445                   apr_pool_t *scratch_pool)
1446 {
1447   svn_sqlite__stmt_t *stmt;
1448   svn_sqlite__stmt_t *stmt_add;
1449   svn_boolean_t have_row;
1450   apr_pool_t *iterpool;
1451
1452   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1453                                     STMT_SELECT_EXTERNAL_PROPERTIES));
1454
1455   SVN_ERR(svn_sqlite__get_statement(&stmt_add, sdb,
1456                                     STMT_INSERT_EXTERNAL));
1457
1458   /* ### For this intermediate upgrade we just assume WC_ID = 1.
1459      ### Before this bump we lost track of externals all the time,
1460      ### so lets keep this easy. */
1461   SVN_ERR(svn_sqlite__bindf(stmt, "is", (apr_int64_t)1, ""));
1462
1463   SVN_ERR(svn_sqlite__step(&have_row, stmt));
1464
1465   iterpool = svn_pool_create(scratch_pool);
1466   while (have_row)
1467     {
1468       apr_hash_t *props;
1469       const char *externals;
1470
1471       svn_pool_clear(iterpool);
1472
1473       SVN_ERR(svn_sqlite__column_properties(&props, stmt, 0,
1474                                             iterpool, iterpool));
1475
1476       externals = svn_prop_get_value(props, SVN_PROP_EXTERNALS);
1477
1478       if (externals)
1479         {
1480           apr_array_header_t *ext;
1481           const char *local_relpath;
1482           const char *local_abspath;
1483           int i;
1484
1485           local_relpath = svn_sqlite__column_text(stmt, 1, NULL);
1486           local_abspath = svn_dirent_join(bb->wcroot_abspath, local_relpath,
1487                                           iterpool);
1488
1489           SVN_ERR(svn_wc_parse_externals_description3(&ext, local_abspath,
1490                                                       externals, FALSE,
1491                                                       iterpool));
1492
1493           for (i = 0; i < ext->nelts; i++)
1494             {
1495               const svn_wc_external_item2_t *item;
1496               const char *item_relpath;
1497
1498               item = APR_ARRAY_IDX(ext, i, const svn_wc_external_item2_t *);
1499               item_relpath = svn_relpath_join(local_relpath, item->target_dir,
1500                                               iterpool);
1501
1502               /* Insert dummy externals definitions: Insert an unknown
1503                  external, to make sure it will be cleaned up when it is not
1504                  updated on the next update. */
1505               SVN_ERR(svn_sqlite__bindf(stmt_add, "isssssis",
1506                                         (apr_int64_t)1, /* wc_id */
1507                                         item_relpath,
1508                                         svn_relpath_dirname(item_relpath,
1509                                                             iterpool),
1510                                         "normal",
1511                                         "unknown",
1512                                         local_relpath,
1513                                         (apr_int64_t)1, /* repos_id */
1514                                         "" /* repos_relpath */));
1515               SVN_ERR(svn_sqlite__insert(NULL, stmt_add));
1516             }
1517         }
1518
1519       SVN_ERR(svn_sqlite__step(&have_row, stmt));
1520     }
1521
1522   svn_pool_destroy(iterpool);
1523   return svn_error_trace(svn_sqlite__reset(stmt));
1524 }
1525
1526 static svn_error_t *
1527 bump_to_29(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1528 {
1529   struct bump_baton *bb = baton;
1530   const char *wcroot_abspath = bb->wcroot_abspath;
1531   const char *pristine_dir_abspath;
1532
1533   /* Rename all pristine files, adding a ".svn-base" suffix. */
1534   pristine_dir_abspath = svn_dirent_join_many(scratch_pool, wcroot_abspath,
1535                                               svn_wc_get_adm_dir(scratch_pool),
1536                                               PRISTINE_STORAGE_RELPATH,
1537                                               SVN_VA_NULL);
1538   SVN_ERR(svn_io_dir_walk2(pristine_dir_abspath, APR_FINFO_MIN,
1539                            rename_pristine_file, NULL, scratch_pool));
1540
1541   /* Externals */
1542   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_EXTERNALS));
1543
1544   SVN_ERR(upgrade_externals(bb, sdb, scratch_pool));
1545   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_29));
1546   return SVN_NO_ERROR;
1547 }
1548
1549 svn_error_t *
1550 svn_wc__upgrade_conflict_skel_from_raw(svn_skel_t **conflicts,
1551                                        svn_wc__db_t *db,
1552                                        const char *wri_abspath,
1553                                        const char *local_relpath,
1554                                        const char *conflict_old,
1555                                        const char *conflict_wrk,
1556                                        const char *conflict_new,
1557                                        const char *prej_file,
1558                                        const char *tree_conflict_data,
1559                                        apr_size_t tree_conflict_len,
1560                                        apr_pool_t *result_pool,
1561                                        apr_pool_t *scratch_pool)
1562 {
1563   svn_skel_t *conflict_data = NULL;
1564   const char *wcroot_abspath;
1565
1566   SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, db, wri_abspath,
1567                                 scratch_pool, scratch_pool));
1568
1569   if (conflict_old || conflict_new || conflict_wrk)
1570     {
1571       const char *old_abspath = NULL;
1572       const char *new_abspath = NULL;
1573       const char *wrk_abspath = NULL;
1574
1575       conflict_data = svn_wc__conflict_skel_create(result_pool);
1576
1577       if (conflict_old)
1578         old_abspath = svn_dirent_join(wcroot_abspath, conflict_old,
1579                                       scratch_pool);
1580
1581       if (conflict_new)
1582         new_abspath = svn_dirent_join(wcroot_abspath, conflict_new,
1583                                       scratch_pool);
1584
1585       if (conflict_wrk)
1586         wrk_abspath = svn_dirent_join(wcroot_abspath, conflict_wrk,
1587                                       scratch_pool);
1588
1589       SVN_ERR(svn_wc__conflict_skel_add_text_conflict(conflict_data,
1590                                                       db, wri_abspath,
1591                                                       wrk_abspath,
1592                                                       old_abspath,
1593                                                       new_abspath,
1594                                                       scratch_pool,
1595                                                       scratch_pool));
1596     }
1597
1598   if (prej_file)
1599     {
1600       const char *prej_abspath;
1601
1602       if (!conflict_data)
1603         conflict_data = svn_wc__conflict_skel_create(result_pool);
1604
1605       prej_abspath = svn_dirent_join(wcroot_abspath, prej_file, scratch_pool);
1606
1607       SVN_ERR(svn_wc__conflict_skel_add_prop_conflict(conflict_data,
1608                                                       db, wri_abspath,
1609                                                       prej_abspath,
1610                                                       NULL, NULL, NULL,
1611                                                 apr_hash_make(scratch_pool),
1612                                                       scratch_pool,
1613                                                       scratch_pool));
1614     }
1615
1616   if (tree_conflict_data)
1617     {
1618       svn_skel_t *tc_skel;
1619       const svn_wc_conflict_description2_t *tc;
1620       const char *local_abspath;
1621
1622       if (!conflict_data)
1623         conflict_data = svn_wc__conflict_skel_create(scratch_pool);
1624
1625       tc_skel = svn_skel__parse(tree_conflict_data, tree_conflict_len,
1626                                 scratch_pool);
1627
1628       local_abspath = svn_dirent_join(wcroot_abspath, local_relpath,
1629                                       scratch_pool);
1630
1631       SVN_ERR(svn_wc__deserialize_conflict(&tc, tc_skel,
1632                                            svn_dirent_dirname(local_abspath,
1633                                                               scratch_pool),
1634                                            scratch_pool, scratch_pool));
1635
1636       SVN_ERR(svn_wc__conflict_skel_add_tree_conflict(conflict_data,
1637                                                       db, wri_abspath,
1638                                                       tc->reason,
1639                                                       tc->action,
1640                                                       NULL,
1641                                                       scratch_pool,
1642                                                       scratch_pool));
1643
1644       switch (tc->operation)
1645         {
1646           case svn_wc_operation_update:
1647           default:
1648             SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_data,
1649                                                        tc->src_left_version,
1650                                                        tc->src_right_version,
1651                                                        scratch_pool,
1652                                                        scratch_pool));
1653             break;
1654           case svn_wc_operation_switch:
1655             SVN_ERR(svn_wc__conflict_skel_set_op_switch(conflict_data,
1656                                                         tc->src_left_version,
1657                                                         tc->src_right_version,
1658                                                         scratch_pool,
1659                                                         scratch_pool));
1660             break;
1661           case svn_wc_operation_merge:
1662             SVN_ERR(svn_wc__conflict_skel_set_op_merge(conflict_data,
1663                                                        tc->src_left_version,
1664                                                        tc->src_right_version,
1665                                                        scratch_pool,
1666                                                        scratch_pool));
1667             break;
1668         }
1669     }
1670   else if (conflict_data)
1671     {
1672       SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_data, NULL, NULL,
1673                                                   scratch_pool,
1674                                                   scratch_pool));
1675     }
1676
1677   *conflicts = conflict_data;
1678   return SVN_NO_ERROR;
1679 }
1680
1681 /* Helper function to upgrade a single conflict from bump_to_30 */
1682 static svn_error_t *
1683 bump_30_upgrade_one_conflict(svn_wc__db_t *wc_db,
1684                              const char *wcroot_abspath,
1685                              svn_sqlite__stmt_t *stmt,
1686                              svn_sqlite__db_t *sdb,
1687                              apr_pool_t *scratch_pool)
1688 {
1689   svn_sqlite__stmt_t *stmt_store;
1690   svn_stringbuf_t *skel_data;
1691   svn_skel_t *conflict_data;
1692   apr_int64_t wc_id = svn_sqlite__column_int64(stmt, 0);
1693   const char *local_relpath = svn_sqlite__column_text(stmt, 1, NULL);
1694   const char *conflict_old = svn_sqlite__column_text(stmt, 2, NULL);
1695   const char *conflict_wrk = svn_sqlite__column_text(stmt, 3, NULL);
1696   const char *conflict_new = svn_sqlite__column_text(stmt, 4, NULL);
1697   const char *prop_reject = svn_sqlite__column_text(stmt, 5, NULL);
1698   apr_size_t tree_conflict_size;
1699   const char *tree_conflict_data = svn_sqlite__column_blob(stmt, 6,
1700                                            &tree_conflict_size, NULL);
1701
1702   SVN_ERR(svn_wc__upgrade_conflict_skel_from_raw(&conflict_data,
1703                                                  wc_db, wcroot_abspath,
1704                                                  local_relpath,
1705                                                  conflict_old,
1706                                                  conflict_wrk,
1707                                                  conflict_new,
1708                                                  prop_reject,
1709                                                  tree_conflict_data,
1710                                                  tree_conflict_size,
1711                                                  scratch_pool, scratch_pool));
1712
1713   SVN_ERR_ASSERT(conflict_data != NULL);
1714
1715   skel_data = svn_skel__unparse(conflict_data, scratch_pool);
1716
1717   SVN_ERR(svn_sqlite__get_statement(&stmt_store, sdb,
1718                                     STMT_UPGRADE_30_SET_CONFLICT));
1719   SVN_ERR(svn_sqlite__bindf(stmt_store, "isb", wc_id, local_relpath,
1720                             skel_data->data, skel_data->len));
1721   SVN_ERR(svn_sqlite__step_done(stmt_store));
1722
1723   return SVN_NO_ERROR;
1724 }
1725
1726 static svn_error_t *
1727 bump_to_30(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
1728 {
1729   struct bump_baton *bb = baton;
1730   svn_boolean_t have_row;
1731   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
1732   svn_sqlite__stmt_t *stmt;
1733   svn_wc__db_t *db; /* Read only temp db */
1734
1735   SVN_ERR(svn_wc__db_open(&db, NULL, TRUE /* open_without_upgrade */, FALSE,
1736                           scratch_pool, scratch_pool));
1737
1738   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1739                                     STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE));
1740   SVN_ERR(svn_sqlite__step(&have_row, stmt));
1741
1742   while (have_row)
1743     {
1744       svn_error_t *err;
1745       svn_pool_clear(iterpool);
1746
1747       err = bump_30_upgrade_one_conflict(db, bb->wcroot_abspath, stmt, sdb,
1748                                          iterpool);
1749
1750       if (err)
1751         {
1752           return svn_error_trace(
1753                     svn_error_compose_create(
1754                             err,
1755                             svn_sqlite__reset(stmt)));
1756         }
1757
1758       SVN_ERR(svn_sqlite__step(&have_row, stmt));
1759     }
1760   SVN_ERR(svn_sqlite__reset(stmt));
1761
1762   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_30));
1763   SVN_ERR(svn_wc__db_close(db));
1764   return SVN_NO_ERROR;
1765 }
1766
1767 static svn_error_t *
1768 bump_to_31(void *baton,
1769            svn_sqlite__db_t *sdb,
1770            apr_pool_t *scratch_pool)
1771 {
1772   svn_sqlite__stmt_t *stmt, *stmt_mark_switch_roots;
1773   svn_boolean_t have_row;
1774   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
1775   apr_array_header_t *empty_iprops = apr_array_make(
1776     scratch_pool, 0, sizeof(svn_prop_inherited_item_t *));
1777   svn_boolean_t iprops_column_exists = FALSE;
1778   svn_error_t *err;
1779
1780   /* Add the inherited_props column to NODES if it does not yet exist.
1781    *
1782    * When using a format >= 31 client to upgrade from old formats which
1783    * did not yet have a NODES table, the inherited_props column has
1784    * already been created as part of the NODES table. Attemping to add
1785    * the inherited_props column will raise an error in this case, so check
1786    * if the column exists first.
1787    *
1788    * Checking for the existence of a column before ALTER TABLE is not
1789    * possible within SQLite. We need to run a separate query and evaluate
1790    * its result in C first.
1791    */
1792   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_PRAGMA_TABLE_INFO_NODES));
1793   SVN_ERR(svn_sqlite__step(&have_row, stmt));
1794   while (have_row)
1795     {
1796       const char *column_name = svn_sqlite__column_text(stmt, 1, NULL);
1797
1798       if (strcmp(column_name, "inherited_props") == 0)
1799         {
1800           iprops_column_exists = TRUE;
1801           break;
1802         }
1803
1804       SVN_ERR(svn_sqlite__step(&have_row, stmt));
1805     }
1806   SVN_ERR(svn_sqlite__reset(stmt));
1807   if (!iprops_column_exists)
1808     SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_31_ALTER_TABLE));
1809
1810   /* Run additional statements to finalize the upgrade to format 31. */
1811   SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_31_FINALIZE));
1812
1813   /* Set inherited_props to an empty array for the roots of all
1814      switched subtrees in the WC.  This allows subsequent updates
1815      to recognize these roots as needing an iprops cache. */
1816   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1817                                     STMT_UPGRADE_31_SELECT_WCROOT_NODES));
1818   SVN_ERR(svn_sqlite__step(&have_row, stmt));
1819
1820   err = svn_sqlite__get_statement(&stmt_mark_switch_roots, sdb,
1821                                   STMT_UPDATE_IPROP);
1822   if (err)
1823     return svn_error_compose_create(err, svn_sqlite__reset(stmt));
1824
1825   while (have_row)
1826     {
1827       const char *switched_relpath = svn_sqlite__column_text(stmt, 1, NULL);
1828       apr_int64_t wc_id = svn_sqlite__column_int64(stmt, 0);
1829
1830       err = svn_sqlite__bindf(stmt_mark_switch_roots, "is", wc_id,
1831                               switched_relpath);
1832       if (!err)
1833         err = svn_sqlite__bind_iprops(stmt_mark_switch_roots, 3,
1834                                       empty_iprops, iterpool);
1835       if (!err)
1836         err = svn_sqlite__step_done(stmt_mark_switch_roots);
1837       if (!err)
1838         err = svn_sqlite__step(&have_row, stmt);
1839
1840       if (err)
1841         return svn_error_compose_create(
1842                 err,
1843                 svn_error_compose_create(
1844                   /* Reset in either order is OK. */
1845                   svn_sqlite__reset(stmt),
1846                   svn_sqlite__reset(stmt_mark_switch_roots)));
1847     }
1848
1849   err = svn_sqlite__reset(stmt_mark_switch_roots);
1850   if (err)
1851     return svn_error_compose_create(err, svn_sqlite__reset(stmt));
1852   SVN_ERR(svn_sqlite__reset(stmt));
1853
1854   svn_pool_destroy(iterpool);
1855
1856   return SVN_NO_ERROR;
1857 }
1858
1859 static svn_error_t *
1860 upgrade_apply_dav_cache(svn_sqlite__db_t *sdb,
1861                         const char *dir_relpath,
1862                         apr_int64_t wc_id,
1863                         apr_hash_t *cache_values,
1864                         apr_pool_t *scratch_pool)
1865 {
1866   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
1867   apr_hash_index_t *hi;
1868   svn_sqlite__stmt_t *stmt;
1869
1870   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
1871                                     STMT_UPDATE_BASE_NODE_DAV_CACHE));
1872
1873   /* Iterate over all the wcprops, writing each one to the wc_db. */
1874   for (hi = apr_hash_first(scratch_pool, cache_values);
1875        hi;
1876        hi = apr_hash_next(hi))
1877     {
1878       const char *name = apr_hash_this_key(hi);
1879       apr_hash_t *props = apr_hash_this_val(hi);
1880       const char *local_relpath;
1881
1882       svn_pool_clear(iterpool);
1883
1884       local_relpath = svn_relpath_join(dir_relpath, name, iterpool);
1885
1886       SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
1887       SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, iterpool));
1888       SVN_ERR(svn_sqlite__step_done(stmt));
1889     }
1890
1891   svn_pool_destroy(iterpool);
1892
1893   return SVN_NO_ERROR;
1894 }
1895
1896
1897 struct upgrade_data_t {
1898   svn_sqlite__db_t *sdb;
1899   const char *root_abspath;
1900   apr_int64_t repos_id;
1901   apr_int64_t wc_id;
1902 };
1903
1904 /* Upgrade the working copy directory represented by DB/DIR_ABSPATH
1905    from OLD_FORMAT to the wc-ng format (SVN_WC__WC_NG_VERSION)'.
1906
1907    Pass REPOS_INFO_FUNC, REPOS_INFO_BATON and REPOS_CACHE to
1908    ensure_repos_info. Add the found repository root and UUID to
1909    REPOS_CACHE if it doesn't have a cached entry for this
1910    repository.
1911
1912    *DATA refers to the single root db.
1913
1914    Uses SCRATCH_POOL for all temporary allocation.  */
1915 static svn_error_t *
1916 upgrade_to_wcng(void **dir_baton,
1917                 void *parent_baton,
1918                 svn_wc__db_t *db,
1919                 const char *dir_abspath,
1920                 int old_format,
1921                 apr_int64_t wc_id,
1922                 svn_wc_upgrade_get_repos_info_t repos_info_func,
1923                 void *repos_info_baton,
1924                 apr_hash_t *repos_cache,
1925                 const struct upgrade_data_t *data,
1926                 apr_pool_t *result_pool,
1927                 apr_pool_t *scratch_pool)
1928 {
1929   const char *logfile_path = svn_wc__adm_child(dir_abspath, ADM_LOG,
1930                                                scratch_pool);
1931   svn_node_kind_t logfile_on_disk_kind;
1932   apr_hash_t *entries;
1933   svn_wc_entry_t *this_dir;
1934   const char *old_wcroot_abspath, *dir_relpath;
1935   apr_hash_t *text_bases_info;
1936   svn_error_t *err;
1937
1938   /* Don't try to mess with the WC if there are old log files left. */
1939
1940   /* Is the (first) log file present?  */
1941   SVN_ERR(svn_io_check_path(logfile_path, &logfile_on_disk_kind,
1942                             scratch_pool));
1943   if (logfile_on_disk_kind == svn_node_file)
1944     return svn_error_create(SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
1945                             _("Cannot upgrade with existing logs; run a "
1946                               "cleanup operation on this working copy using "
1947                               "a client version which is compatible with this "
1948                               "working copy's format (such as the version "
1949                               "you are upgrading from), then retry the "
1950                               "upgrade with the current version"));
1951
1952   /* Lock this working copy directory, or steal an existing lock. Do this
1953      BEFORE we read the entries. We don't want another process to modify the
1954      entries after we've read them into memory.  */
1955   SVN_ERR(create_physical_lock(dir_abspath, scratch_pool));
1956
1957   /* What's going on here?
1958    *
1959    * We're attempting to upgrade an older working copy to the new wc-ng format.
1960    * The semantics and storage mechanisms between the two are vastly different,
1961    * so it's going to be a bit painful.  Here's a plan for the operation:
1962    *
1963    * 1) Read the old 'entries' using the old-format reader.
1964    *
1965    * 2) Create the new DB if it hasn't already been created.
1966    *
1967    * 3) Use our compatibility code for writing entries to fill out the (new)
1968    *    DB state.  Use the remembered checksums, since an entry has only the
1969    *    MD5 not the SHA1 checksum, and in the case of a revert-base doesn't
1970    *    even have that.
1971    *
1972    * 4) Convert wcprop to the wc-ng format
1973    *
1974    * 5) Migrate regular properties to the WC-NG DB.
1975    */
1976
1977   /***** ENTRIES - READ *****/
1978   SVN_ERR(svn_wc__read_entries_old(&entries, dir_abspath,
1979                                    scratch_pool, scratch_pool));
1980
1981   this_dir = svn_hash_gets(entries, SVN_WC_ENTRY_THIS_DIR);
1982   SVN_ERR(ensure_repos_info(this_dir, dir_abspath,
1983                             repos_info_func, repos_info_baton,
1984                             repos_cache,
1985                             scratch_pool, scratch_pool));
1986
1987   /* Cache repos UUID pairs for when a subdir doesn't have this information */
1988   if (!svn_hash_gets(repos_cache, this_dir->repos))
1989     {
1990       apr_pool_t *hash_pool = apr_hash_pool_get(repos_cache);
1991
1992       svn_hash_sets(repos_cache,
1993                     apr_pstrdup(hash_pool, this_dir->repos),
1994                     apr_pstrdup(hash_pool, this_dir->uuid));
1995     }
1996
1997   old_wcroot_abspath = svn_dirent_get_longest_ancestor(dir_abspath,
1998                                                        data->root_abspath,
1999                                                        scratch_pool);
2000   dir_relpath = svn_dirent_skip_ancestor(old_wcroot_abspath, dir_abspath);
2001
2002   /***** TEXT BASES *****/
2003   SVN_ERR(migrate_text_bases(&text_bases_info, dir_abspath, data->root_abspath,
2004                              data->sdb, scratch_pool, scratch_pool));
2005
2006   /***** ENTRIES - WRITE *****/
2007   err = svn_wc__write_upgraded_entries(dir_baton, parent_baton, db, data->sdb,
2008                                        data->repos_id, data->wc_id,
2009                                        dir_abspath, data->root_abspath,
2010                                        entries, text_bases_info,
2011                                        result_pool, scratch_pool);
2012   if (err && err->apr_err == SVN_ERR_WC_CORRUPT)
2013     return svn_error_quick_wrap(err,
2014                                 _("This working copy is corrupt and "
2015                                   "cannot be upgraded. Please check out "
2016                                   "a new working copy."));
2017   else
2018     SVN_ERR(err);
2019
2020   /***** WC PROPS *****/
2021   /* If we don't know precisely where the wcprops are, ignore them.  */
2022   if (old_format != SVN_WC__WCPROPS_LOST)
2023     {
2024       apr_hash_t *all_wcprops;
2025
2026       if (old_format <= SVN_WC__WCPROPS_MANY_FILES_VERSION)
2027         SVN_ERR(read_many_wcprops(&all_wcprops, dir_abspath,
2028                                   scratch_pool, scratch_pool));
2029       else
2030         SVN_ERR(read_wcprops(&all_wcprops, dir_abspath,
2031                              scratch_pool, scratch_pool));
2032
2033       SVN_ERR(upgrade_apply_dav_cache(data->sdb, dir_relpath, wc_id,
2034                                       all_wcprops, scratch_pool));
2035     }
2036
2037   /* Upgrade all the properties (including "this dir").
2038
2039      Note: this must come AFTER the entries have been migrated into the
2040      database. The upgrade process needs the children in BASE_NODE and
2041      WORKING_NODE, and to examine the resultant WORKING state.  */
2042   SVN_ERR(migrate_props(dir_abspath, data->root_abspath, data->sdb, old_format,
2043                         wc_id, scratch_pool));
2044
2045   return SVN_NO_ERROR;
2046 }
2047
2048 const char *
2049 svn_wc__version_string_from_format(int wc_format)
2050 {
2051   switch (wc_format)
2052     {
2053       case 4: return "<=1.3";
2054       case 8: return "1.4";
2055       case 9: return "1.5";
2056       case 10: return "1.6";
2057       case SVN_WC__WC_NG_VERSION: return "1.7";
2058     }
2059   return _("(unreleased development version)");
2060 }
2061
2062 svn_error_t *
2063 svn_wc__upgrade_sdb(int *result_format,
2064                     const char *wcroot_abspath,
2065                     svn_sqlite__db_t *sdb,
2066                     int start_format,
2067                     apr_pool_t *scratch_pool)
2068 {
2069   struct bump_baton bb;
2070
2071   bb.wcroot_abspath = wcroot_abspath;
2072
2073   if (start_format < SVN_WC__WC_NG_VERSION /* 12 */)
2074     return svn_error_createf(SVN_ERR_WC_UPGRADE_REQUIRED, NULL,
2075                              _("Working copy '%s' is too old (format %d, "
2076                                "created by Subversion %s)"),
2077                              svn_dirent_local_style(wcroot_abspath,
2078                                                     scratch_pool),
2079                              start_format,
2080                              svn_wc__version_string_from_format(start_format));
2081
2082   /* Early WCNG formats no longer supported. */
2083   if (start_format < 19)
2084     return svn_error_createf(SVN_ERR_WC_UPGRADE_REQUIRED, NULL,
2085                              _("Working copy '%s' is an old development "
2086                                "version (format %d); to upgrade it, "
2087                                "use a format 18 client, then "
2088                                "use 'tools/dev/wc-ng/bump-to-19.py', then "
2089                                "use the current client"),
2090                              svn_dirent_local_style(wcroot_abspath,
2091                                                     scratch_pool),
2092                              start_format);
2093
2094   /* ### need lock-out. only one upgrade at a time. note that other code
2095      ### cannot use this un-upgraded database until we finish the upgrade.  */
2096
2097   /* Note: none of these have "break" statements; the fall-through is
2098      intentional. */
2099   switch (start_format)
2100     {
2101       case 19:
2102         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_20, &bb,
2103                                              scratch_pool));
2104         *result_format = 20;
2105         /* FALLTHROUGH  */
2106
2107       case 20:
2108         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_21, &bb,
2109                                              scratch_pool));
2110         *result_format = 21;
2111         /* FALLTHROUGH  */
2112
2113       case 21:
2114         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_22, &bb,
2115                                              scratch_pool));
2116         *result_format = 22;
2117         /* FALLTHROUGH  */
2118
2119       case 22:
2120         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_23, &bb,
2121                                              scratch_pool));
2122         *result_format = 23;
2123         /* FALLTHROUGH  */
2124
2125       case 23:
2126         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_24, &bb,
2127                                              scratch_pool));
2128         *result_format = 24;
2129         /* FALLTHROUGH  */
2130
2131       case 24:
2132         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_25, &bb,
2133                                              scratch_pool));
2134         *result_format = 25;
2135         /* FALLTHROUGH  */
2136
2137       case 25:
2138         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_26, &bb,
2139                                              scratch_pool));
2140         *result_format = 26;
2141         /* FALLTHROUGH  */
2142
2143       case 26:
2144         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_27, &bb,
2145                                              scratch_pool));
2146         *result_format = 27;
2147         /* FALLTHROUGH  */
2148
2149       case 27:
2150         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_28, &bb,
2151                                              scratch_pool));
2152         *result_format = 28;
2153         /* FALLTHROUGH  */
2154
2155       case 28:
2156         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_29, &bb,
2157                                              scratch_pool));
2158         *result_format = 29;
2159         /* FALLTHROUGH  */
2160
2161       case 29:
2162         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_30, &bb,
2163                                              scratch_pool));
2164         *result_format = 30;
2165
2166       case 30:
2167         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_31, &bb,
2168                                              scratch_pool));
2169         *result_format = 31;
2170         /* FALLTHROUGH  */
2171       /* ### future bumps go here.  */
2172 #if 0
2173       case XXX-1:
2174         /* Revamp the recording of tree conflicts.  */
2175         SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_XXX, &bb,
2176                                              scratch_pool));
2177         *result_format = XXX;
2178         /* FALLTHROUGH  */
2179 #endif
2180       case SVN_WC__VERSION:
2181         /* already upgraded */
2182         *result_format = SVN_WC__VERSION;
2183
2184         SVN_SQLITE__WITH_LOCK(
2185             svn_wc__db_install_schema_statistics(sdb, scratch_pool),
2186             sdb);
2187     }
2188
2189 #ifdef SVN_DEBUG
2190   if (*result_format != start_format)
2191     {
2192       int schema_version;
2193       SVN_ERR(svn_sqlite__read_schema_version(&schema_version, sdb, scratch_pool));
2194
2195       /* If this assertion fails the schema isn't updated correctly */
2196       SVN_ERR_ASSERT(schema_version == *result_format);
2197     }
2198 #endif
2199
2200   /* Zap anything that might be remaining or escaped our notice.  */
2201   wipe_obsolete_files(wcroot_abspath, scratch_pool);
2202
2203   return SVN_NO_ERROR;
2204 }
2205
2206
2207 /* */
2208 static svn_error_t *
2209 upgrade_working_copy(void *parent_baton,
2210                      svn_wc__db_t *db,
2211                      const char *dir_abspath,
2212                      svn_wc_upgrade_get_repos_info_t repos_info_func,
2213                      void *repos_info_baton,
2214                      apr_hash_t *repos_cache,
2215                      const struct upgrade_data_t *data,
2216                      svn_cancel_func_t cancel_func,
2217                      void *cancel_baton,
2218                      svn_wc_notify_func2_t notify_func,
2219                      void *notify_baton,
2220                      apr_pool_t *result_pool,
2221                      apr_pool_t *scratch_pool)
2222 {
2223   void *dir_baton;
2224   int old_format;
2225   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
2226   apr_array_header_t *subdirs;
2227   svn_error_t *err;
2228   int i;
2229
2230   if (cancel_func)
2231     SVN_ERR(cancel_func(cancel_baton));
2232
2233   SVN_ERR(svn_wc__db_temp_get_format(&old_format, db, dir_abspath,
2234                                      iterpool));
2235
2236   if (old_format >= SVN_WC__WC_NG_VERSION)
2237     {
2238       if (notify_func)
2239         notify_func(notify_baton,
2240                     svn_wc_create_notify(dir_abspath, svn_wc_notify_skip,
2241                                          iterpool),
2242                 iterpool);
2243       svn_pool_destroy(iterpool);
2244       return SVN_NO_ERROR;
2245     }
2246
2247   err = get_versioned_subdirs(&subdirs, NULL, dir_abspath, FALSE,
2248                               scratch_pool, iterpool);
2249   if (err)
2250     {
2251       if (APR_STATUS_IS_ENOENT(err->apr_err)
2252           || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err))
2253         {
2254           /* An unversioned dir is obstructing a versioned dir */
2255           svn_error_clear(err);
2256           err = NULL;
2257           if (notify_func)
2258             notify_func(notify_baton,
2259                         svn_wc_create_notify(dir_abspath, svn_wc_notify_skip,
2260                                              iterpool),
2261                         iterpool);
2262         }
2263       svn_pool_destroy(iterpool);
2264       return err;
2265     }
2266
2267
2268   SVN_ERR(upgrade_to_wcng(&dir_baton, parent_baton, db, dir_abspath,
2269                           old_format, data->wc_id,
2270                           repos_info_func, repos_info_baton,
2271                           repos_cache, data, scratch_pool, iterpool));
2272
2273   if (notify_func)
2274     notify_func(notify_baton,
2275                 svn_wc_create_notify(dir_abspath, svn_wc_notify_upgraded_path,
2276                                      iterpool),
2277                 iterpool);
2278
2279   for (i = 0; i < subdirs->nelts; ++i)
2280     {
2281       const char *child_abspath = APR_ARRAY_IDX(subdirs, i, const char *);
2282
2283       svn_pool_clear(iterpool);
2284
2285       SVN_ERR(upgrade_working_copy(dir_baton, db, child_abspath,
2286                                    repos_info_func, repos_info_baton,
2287                                    repos_cache, data,
2288                                    cancel_func, cancel_baton,
2289                                    notify_func, notify_baton,
2290                                    iterpool, iterpool));
2291     }
2292
2293   svn_pool_destroy(iterpool);
2294
2295   return SVN_NO_ERROR;
2296 }
2297
2298
2299 /* Return a verbose error if LOCAL_ABSPATH is a not a pre-1.7 working
2300    copy root */
2301 static svn_error_t *
2302 is_old_wcroot(const char *local_abspath,
2303               apr_pool_t *scratch_pool)
2304 {
2305   apr_hash_t *entries;
2306   const char *parent_abspath, *name;
2307   svn_wc_entry_t *entry;
2308   svn_error_t *err = svn_wc__read_entries_old(&entries, local_abspath,
2309                                               scratch_pool, scratch_pool);
2310   if (err)
2311     {
2312       return svn_error_createf(
2313         SVN_ERR_WC_INVALID_OP_ON_CWD, err,
2314         _("Can't upgrade '%s' as it is not a working copy"),
2315         svn_dirent_local_style(local_abspath, scratch_pool));
2316     }
2317   else if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
2318     return SVN_NO_ERROR;
2319
2320   svn_dirent_split(&parent_abspath, &name, local_abspath, scratch_pool);
2321
2322   err = svn_wc__read_entries_old(&entries, parent_abspath,
2323                                  scratch_pool, scratch_pool);
2324   if (err)
2325     {
2326       svn_error_clear(err);
2327       return SVN_NO_ERROR;
2328     }
2329
2330   entry = svn_hash_gets(entries, name);
2331   if (!entry
2332       || entry->absent
2333       || (entry->deleted && entry->schedule != svn_wc_schedule_add)
2334       || entry->depth == svn_depth_exclude)
2335     {
2336       return SVN_NO_ERROR;
2337     }
2338
2339   while (!svn_dirent_is_root(parent_abspath, strlen(parent_abspath)))
2340     {
2341       svn_dirent_split(&parent_abspath, &name, parent_abspath, scratch_pool);
2342       err = svn_wc__read_entries_old(&entries, parent_abspath,
2343                                      scratch_pool, scratch_pool);
2344       if (err)
2345         {
2346           svn_error_clear(err);
2347           parent_abspath = svn_dirent_join(parent_abspath, name, scratch_pool);
2348           break;
2349         }
2350       entry = svn_hash_gets(entries, name);
2351       if (!entry
2352           || entry->absent
2353           || (entry->deleted && entry->schedule != svn_wc_schedule_add)
2354           || entry->depth == svn_depth_exclude)
2355         {
2356           parent_abspath = svn_dirent_join(parent_abspath, name, scratch_pool);
2357           break;
2358         }
2359     }
2360
2361   return svn_error_createf(
2362     SVN_ERR_WC_INVALID_OP_ON_CWD, NULL,
2363     _("Can't upgrade '%s' as it is not a working copy root,"
2364       " the root is '%s'"),
2365     svn_dirent_local_style(local_abspath, scratch_pool),
2366     svn_dirent_local_style(parent_abspath, scratch_pool));
2367 }
2368
2369 svn_error_t *
2370 svn_wc_upgrade(svn_wc_context_t *wc_ctx,
2371                const char *local_abspath,
2372                svn_wc_upgrade_get_repos_info_t repos_info_func,
2373                void *repos_info_baton,
2374                svn_cancel_func_t cancel_func,
2375                void *cancel_baton,
2376                svn_wc_notify_func2_t notify_func,
2377                void *notify_baton,
2378                apr_pool_t *scratch_pool)
2379 {
2380   svn_wc__db_t *db;
2381   struct upgrade_data_t data = { NULL };
2382   svn_skel_t *work_item, *work_items = NULL;
2383   const char *pristine_from, *pristine_to, *db_from, *db_to;
2384   apr_hash_t *repos_cache = apr_hash_make(scratch_pool);
2385   svn_wc_entry_t *this_dir;
2386   apr_hash_t *entries;
2387   const char *root_adm_abspath;
2388   svn_error_t *err;
2389   int result_format;
2390   svn_boolean_t bumped_format;
2391
2392   /* Try upgrading a wc-ng-style working copy. */
2393   SVN_ERR(svn_wc__db_open(&db, NULL /* ### config */, TRUE, FALSE,
2394                           scratch_pool, scratch_pool));
2395
2396
2397   err = svn_wc__db_bump_format(&result_format, &bumped_format,
2398                                db, local_abspath,
2399                                scratch_pool);
2400   if (err)
2401     {
2402       if (err->apr_err != SVN_ERR_WC_UPGRADE_REQUIRED)
2403         {
2404           return svn_error_trace(
2405                     svn_error_compose_create(
2406                             err,
2407                             svn_wc__db_close(db)));
2408         }
2409
2410       svn_error_clear(err);
2411       /* Pre 1.7: Fall through */
2412     }
2413   else
2414     {
2415       /* Auto-upgrade worked! */
2416       SVN_ERR(svn_wc__db_close(db));
2417
2418       SVN_ERR_ASSERT(result_format == SVN_WC__VERSION);
2419
2420       if (bumped_format && notify_func)
2421         {
2422           svn_wc_notify_t *notify;
2423
2424           notify = svn_wc_create_notify(local_abspath,
2425                                         svn_wc_notify_upgraded_path,
2426                                         scratch_pool);
2427
2428           notify_func(notify_baton, notify, scratch_pool);
2429         }
2430
2431       return SVN_NO_ERROR;
2432     }
2433
2434   SVN_ERR(is_old_wcroot(local_abspath, scratch_pool));
2435
2436   /* Given a pre-wcng root some/wc we create a temporary wcng in
2437      some/wc/.svn/tmp/wcng/wc.db and copy the metadata from one to the
2438      other, then the temporary wc.db file gets moved into the original
2439      root.  Until the wc.db file is moved the original working copy
2440      remains a pre-wcng and 'cleanup' with an old client will remove
2441      the partial upgrade.  Moving the wc.db file creates a wcng, and
2442      'cleanup' with a new client will complete any outstanding
2443      upgrade. */
2444
2445   SVN_ERR(svn_wc__read_entries_old(&entries, local_abspath,
2446                                    scratch_pool, scratch_pool));
2447
2448   this_dir = svn_hash_gets(entries, SVN_WC_ENTRY_THIS_DIR);
2449   SVN_ERR(ensure_repos_info(this_dir, local_abspath, repos_info_func,
2450                             repos_info_baton, repos_cache,
2451                             scratch_pool, scratch_pool));
2452
2453   /* Cache repos UUID pairs for when a subdir doesn't have this information */
2454   if (!svn_hash_gets(repos_cache, this_dir->repos))
2455     svn_hash_sets(repos_cache,
2456                   apr_pstrdup(scratch_pool, this_dir->repos),
2457                   apr_pstrdup(scratch_pool, this_dir->uuid));
2458
2459   /* Create the new DB in the temporary root wc/.svn/tmp/wcng/.svn */
2460   data.root_abspath = svn_dirent_join(svn_wc__adm_child(local_abspath, "tmp",
2461                                                         scratch_pool),
2462                                        "wcng", scratch_pool);
2463   root_adm_abspath = svn_wc__adm_child(data.root_abspath, "",
2464                                        scratch_pool);
2465   SVN_ERR(svn_io_remove_dir2(root_adm_abspath, TRUE, NULL, NULL,
2466                              scratch_pool));
2467   SVN_ERR(svn_wc__ensure_directory(root_adm_abspath, scratch_pool));
2468
2469   /* Create an empty sqlite database for this directory and store it in DB. */
2470   SVN_ERR(svn_wc__db_upgrade_begin(&data.sdb,
2471                                    &data.repos_id, &data.wc_id,
2472                                    db, data.root_abspath,
2473                                    this_dir->repos, this_dir->uuid,
2474                                    scratch_pool));
2475
2476   /* Migrate the entries over to the new database.
2477    ### We need to think about atomicity here.
2478
2479    entries_write_new() writes in current format rather than
2480    f12. Thus, this function bumps a working copy all the way to
2481    current.  */
2482   SVN_ERR(svn_wc__db_wclock_obtain(db, data.root_abspath, 0, FALSE,
2483                                    scratch_pool));
2484
2485   SVN_SQLITE__WITH_LOCK(
2486     upgrade_working_copy(NULL, db, local_abspath,
2487                          repos_info_func, repos_info_baton,
2488                          repos_cache, &data,
2489                          cancel_func, cancel_baton,
2490                          notify_func, notify_baton,
2491                          scratch_pool, scratch_pool),
2492     data.sdb);
2493
2494   /* A workqueue item to move the pristine dir into place */
2495   pristine_from = svn_wc__adm_child(data.root_abspath, PRISTINE_STORAGE_RELPATH,
2496                                     scratch_pool);
2497   pristine_to = svn_wc__adm_child(local_abspath, PRISTINE_STORAGE_RELPATH,
2498                                   scratch_pool);
2499   SVN_ERR(svn_wc__ensure_directory(pristine_from, scratch_pool));
2500   SVN_ERR(svn_wc__wq_build_file_move(&work_item, db, local_abspath,
2501                                      pristine_from, pristine_to,
2502                                      scratch_pool, scratch_pool));
2503   work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
2504
2505   /* A workqueue item to remove pre-wcng metadata */
2506   SVN_ERR(svn_wc__wq_build_postupgrade(&work_item, scratch_pool));
2507   work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
2508   SVN_ERR(svn_wc__db_wq_add(db, data.root_abspath, work_items, scratch_pool));
2509
2510   SVN_ERR(svn_wc__db_wclock_release(db, data.root_abspath, scratch_pool));
2511   SVN_ERR(svn_wc__db_close(db));
2512
2513   /* Renaming the db file is what makes the pre-wcng into a wcng */
2514   db_from = svn_wc__adm_child(data.root_abspath, SDB_FILE, scratch_pool);
2515   db_to = svn_wc__adm_child(local_abspath, SDB_FILE, scratch_pool);
2516   SVN_ERR(svn_io_file_rename(db_from, db_to, scratch_pool));
2517
2518   /* Now we have a working wcng, tidy up the droppings */
2519   SVN_ERR(svn_wc__db_open(&db, NULL /* ### config */, FALSE, FALSE,
2520                           scratch_pool, scratch_pool));
2521   SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
2522                          scratch_pool));
2523   SVN_ERR(svn_wc__db_close(db));
2524
2525   /* Should we have the workqueue remove this empty dir? */
2526   SVN_ERR(svn_io_remove_dir2(data.root_abspath, FALSE, NULL, NULL,
2527                              scratch_pool));
2528
2529   return SVN_NO_ERROR;
2530 }
2531
2532 svn_error_t *
2533 svn_wc__upgrade_add_external_info(svn_wc_context_t *wc_ctx,
2534                                   const char *local_abspath,
2535                                   svn_node_kind_t kind,
2536                                   const char *def_local_abspath,
2537                                   const char *repos_relpath,
2538                                   const char *repos_root_url,
2539                                   const char *repos_uuid,
2540                                   svn_revnum_t def_peg_revision,
2541                                   svn_revnum_t def_revision,
2542                                   apr_pool_t *scratch_pool)
2543 {
2544   svn_node_kind_t db_kind;
2545   switch (kind)
2546     {
2547       case svn_node_dir:
2548         db_kind = svn_node_dir;
2549         break;
2550
2551       case svn_node_file:
2552         db_kind = svn_node_file;
2553         break;
2554
2555       case svn_node_unknown:
2556         db_kind = svn_node_unknown;
2557         break;
2558
2559       default:
2560         SVN_ERR_MALFUNCTION();
2561     }
2562
2563   SVN_ERR(svn_wc__db_upgrade_insert_external(wc_ctx->db, local_abspath,
2564                                              db_kind,
2565                                              svn_dirent_dirname(local_abspath,
2566                                                                 scratch_pool),
2567                                              def_local_abspath, repos_relpath,
2568                                              repos_root_url, repos_uuid,
2569                                              def_peg_revision, def_revision,
2570                                              scratch_pool));
2571   return SVN_NO_ERROR;
2572 }