]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/libsvn_wc/wc_db_pristine.c
MFC r275385 (by bapt):
[FreeBSD/stable/10.git] / contrib / subversion / subversion / libsvn_wc / wc_db_pristine.c
1 /*
2  * wc_db_pristine.c :  Pristine ("text base") management
3  *
4  * See the spec in 'notes/wc-ng/pristine-store'.
5  *
6  * ====================================================================
7  *    Licensed to the Apache Software Foundation (ASF) under one
8  *    or more contributor license agreements.  See the NOTICE file
9  *    distributed with this work for additional information
10  *    regarding copyright ownership.  The ASF licenses this file
11  *    to you under the Apache License, Version 2.0 (the
12  *    "License"); you may not use this file except in compliance
13  *    with the License.  You may obtain a copy of the License at
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
17  *    Unless required by applicable law or agreed to in writing,
18  *    software distributed under the License is distributed on an
19  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20  *    KIND, either express or implied.  See the License for the
21  *    specific language governing permissions and limitations
22  *    under the License.
23  * ====================================================================
24  */
25
26 #define SVN_WC__I_AM_WC_DB
27
28 #include "svn_pools.h"
29 #include "svn_io.h"
30 #include "svn_dirent_uri.h"
31
32 #include "private/svn_io_private.h"
33
34 #include "wc.h"
35 #include "wc_db.h"
36 #include "wc-queries.h"
37 #include "wc_db_private.h"
38
39 #define PRISTINE_STORAGE_EXT ".svn-base"
40 #define PRISTINE_STORAGE_RELPATH "pristine"
41 #define PRISTINE_TEMPDIR_RELPATH "tmp"
42
43
44
45 /* Returns in PRISTINE_ABSPATH a new string allocated from RESULT_POOL,
46    holding the local absolute path to the file location that is dedicated
47    to hold CHECKSUM's pristine file, relating to the pristine store
48    configured for the working copy indicated by PDH. The returned path
49    does not necessarily currently exist.
50
51    Any other allocations are made in SCRATCH_POOL. */
52 static svn_error_t *
53 get_pristine_fname(const char **pristine_abspath,
54                    const char *wcroot_abspath,
55                    const svn_checksum_t *sha1_checksum,
56                    apr_pool_t *result_pool,
57                    apr_pool_t *scratch_pool)
58 {
59   const char *base_dir_abspath;
60   const char *hexdigest = svn_checksum_to_cstring(sha1_checksum, scratch_pool);
61   char subdir[3];
62
63   /* ### code is in transition. make sure we have the proper data.  */
64   SVN_ERR_ASSERT(pristine_abspath != NULL);
65   SVN_ERR_ASSERT(svn_dirent_is_absolute(wcroot_abspath));
66   SVN_ERR_ASSERT(sha1_checksum != NULL);
67   SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
68
69   base_dir_abspath = svn_dirent_join_many(scratch_pool,
70                                           wcroot_abspath,
71                                           svn_wc_get_adm_dir(scratch_pool),
72                                           PRISTINE_STORAGE_RELPATH,
73                                           SVN_VA_NULL);
74
75   /* We should have a valid checksum and (thus) a valid digest. */
76   SVN_ERR_ASSERT(hexdigest != NULL);
77
78   /* Get the first two characters of the digest, for the subdir. */
79   subdir[0] = hexdigest[0];
80   subdir[1] = hexdigest[1];
81   subdir[2] = '\0';
82
83   hexdigest = apr_pstrcat(scratch_pool, hexdigest, PRISTINE_STORAGE_EXT,
84                           SVN_VA_NULL);
85
86   /* The file is located at DIR/.svn/pristine/XX/XXYYZZ...svn-base */
87   *pristine_abspath = svn_dirent_join_many(result_pool,
88                                            base_dir_abspath,
89                                            subdir,
90                                            hexdigest,
91                                            SVN_VA_NULL);
92   return SVN_NO_ERROR;
93 }
94
95
96 svn_error_t *
97 svn_wc__db_pristine_get_path(const char **pristine_abspath,
98                              svn_wc__db_t *db,
99                              const char *wri_abspath,
100                              const svn_checksum_t *sha1_checksum,
101                              apr_pool_t *result_pool,
102                              apr_pool_t *scratch_pool)
103 {
104   svn_wc__db_wcroot_t *wcroot;
105   const char *local_relpath;
106   svn_boolean_t present;
107
108   SVN_ERR_ASSERT(pristine_abspath != NULL);
109   SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
110   SVN_ERR_ASSERT(sha1_checksum != NULL);
111   /* ### Transitional: accept MD-5 and look up the SHA-1.  Return an error
112    * if the pristine text is not in the store. */
113   if (sha1_checksum->kind != svn_checksum_sha1)
114     SVN_ERR(svn_wc__db_pristine_get_sha1(&sha1_checksum, db, wri_abspath,
115                                          sha1_checksum,
116                                          scratch_pool, scratch_pool));
117   SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
118
119   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
120                                              db, wri_abspath,
121                                              scratch_pool, scratch_pool));
122   VERIFY_USABLE_WCROOT(wcroot);
123
124   SVN_ERR(svn_wc__db_pristine_check(&present, db, wri_abspath, sha1_checksum,
125                                     scratch_pool));
126   if (! present)
127     return svn_error_createf(SVN_ERR_WC_DB_ERROR, NULL,
128                              _("The pristine text with checksum '%s' was "
129                                "not found"),
130                              svn_checksum_to_cstring_display(sha1_checksum,
131                                                              scratch_pool));
132
133   SVN_ERR(get_pristine_fname(pristine_abspath, wcroot->abspath,
134                              sha1_checksum,
135                              result_pool, scratch_pool));
136
137   return SVN_NO_ERROR;
138 }
139
140 svn_error_t *
141 svn_wc__db_pristine_get_future_path(const char **pristine_abspath,
142                                     const char *wcroot_abspath,
143                                     const svn_checksum_t *sha1_checksum,
144                                     apr_pool_t *result_pool,
145                                     apr_pool_t *scratch_pool)
146 {
147   SVN_ERR(get_pristine_fname(pristine_abspath, wcroot_abspath,
148                              sha1_checksum,
149                              result_pool, scratch_pool));
150   return SVN_NO_ERROR;
151 }
152
153 /* Set *CONTENTS to a readable stream from which the pristine text
154  * identified by SHA1_CHECKSUM and PRISTINE_ABSPATH can be read from the
155  * pristine store of WCROOT.  If SIZE is not null, set *SIZE to the size
156  * in bytes of that text. If that text is not in the pristine store,
157  * return an error.
158  *
159  * Even if the pristine text is removed from the store while it is being
160  * read, the stream will remain valid and readable until it is closed.
161  *
162  * Allocate the stream in RESULT_POOL.
163  *
164  * This function expects to be executed inside a SQLite txn.
165  *
166  * Implements 'notes/wc-ng/pristine-store' section A-3(d).
167  */
168 static svn_error_t *
169 pristine_read_txn(svn_stream_t **contents,
170                   svn_filesize_t *size,
171                   svn_wc__db_wcroot_t *wcroot,
172                   const svn_checksum_t *sha1_checksum,
173                   const char *pristine_abspath,
174                   apr_pool_t *result_pool,
175                   apr_pool_t *scratch_pool)
176 {
177   svn_sqlite__stmt_t *stmt;
178   svn_boolean_t have_row;
179
180   /* Check that this pristine text is present in the store.  (The presence
181    * of the file is not sufficient.) */
182   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
183                                     STMT_SELECT_PRISTINE_SIZE));
184   SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
185   SVN_ERR(svn_sqlite__step(&have_row, stmt));
186
187   if (size)
188     *size = svn_sqlite__column_int64(stmt, 0);
189
190   SVN_ERR(svn_sqlite__reset(stmt));
191   if (! have_row)
192     {
193       return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
194                                _("Pristine text '%s' not present"),
195                                svn_checksum_to_cstring_display(
196                                  sha1_checksum, scratch_pool));
197     }
198
199   /* Open the file as a readable stream.  It will remain readable even when
200    * deleted from disk; APR guarantees that on Windows as well as Unix.
201    *
202    * We also don't enable APR_BUFFERED on this file to maximize throughput
203    * e.g. for fulltext comparison.  As we use SVN__STREAM_CHUNK_SIZE buffers
204    * where needed in streams, there is no point in having another layer of
205    * buffers. */
206   if (contents)
207     {
208       apr_file_t *file;
209       SVN_ERR(svn_io_file_open(&file, pristine_abspath, APR_READ,
210                                APR_OS_DEFAULT, result_pool));
211       *contents = svn_stream_from_aprfile2(file, FALSE, result_pool);
212     }
213
214   return SVN_NO_ERROR;
215 }
216
217 svn_error_t *
218 svn_wc__db_pristine_read(svn_stream_t **contents,
219                          svn_filesize_t *size,
220                          svn_wc__db_t *db,
221                          const char *wri_abspath,
222                          const svn_checksum_t *sha1_checksum,
223                          apr_pool_t *result_pool,
224                          apr_pool_t *scratch_pool)
225 {
226   svn_wc__db_wcroot_t *wcroot;
227   const char *local_relpath;
228   const char *pristine_abspath;
229
230   SVN_ERR_ASSERT(contents != NULL);
231   SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
232
233   /* Some 1.6-to-1.7 wc upgrades created rows without checksums and
234      updating such a row passes NULL here. */
235   if (!sha1_checksum)
236     return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
237                              _("Can't read '%s' from pristine store "
238                                "because no checksum supplied"),
239                              svn_dirent_local_style(wri_abspath, scratch_pool));
240
241   SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
242
243   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
244                               wri_abspath, scratch_pool, scratch_pool));
245   VERIFY_USABLE_WCROOT(wcroot);
246
247   SVN_ERR(get_pristine_fname(&pristine_abspath, wcroot->abspath,
248                              sha1_checksum,
249                              scratch_pool, scratch_pool));
250   SVN_WC__DB_WITH_TXN(
251     pristine_read_txn(contents, size,
252                       wcroot, sha1_checksum, pristine_abspath,
253                       result_pool, scratch_pool),
254     wcroot);
255
256   return SVN_NO_ERROR;
257 }
258
259
260 /* Return the absolute path to the temporary directory for pristine text
261    files within WCROOT. */
262 static char *
263 pristine_get_tempdir(svn_wc__db_wcroot_t *wcroot,
264                      apr_pool_t *result_pool,
265                      apr_pool_t *scratch_pool)
266 {
267   return svn_dirent_join_many(result_pool, wcroot->abspath,
268                               svn_wc_get_adm_dir(scratch_pool),
269                               PRISTINE_TEMPDIR_RELPATH, SVN_VA_NULL);
270 }
271
272 /* Install the pristine text described by BATON into the pristine store of
273  * SDB.  If it is already stored then just delete the new file
274  * BATON->tempfile_abspath.
275  *
276  * This function expects to be executed inside a SQLite txn that has already
277  * acquired a 'RESERVED' lock.
278  *
279  * Implements 'notes/wc-ng/pristine-store' section A-3(a).
280  */
281 static svn_error_t *
282 pristine_install_txn(svn_sqlite__db_t *sdb,
283                      /* The path to the source file that is to be moved into place. */
284                      svn_stream_t *install_stream,
285                      /* The target path for the file (within the pristine store). */
286                      const char *pristine_abspath,
287                      /* The pristine text's SHA-1 checksum. */
288                      const svn_checksum_t *sha1_checksum,
289                      /* The pristine text's MD-5 checksum. */
290                      const svn_checksum_t *md5_checksum,
291                      apr_pool_t *scratch_pool)
292 {
293   svn_sqlite__stmt_t *stmt;
294   svn_boolean_t have_row;
295
296   /* If this pristine text is already present in the store, just keep it:
297    * delete the new one and return. */
298   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_PRISTINE));
299   SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
300   SVN_ERR(svn_sqlite__step(&have_row, stmt));
301   SVN_ERR(svn_sqlite__reset(stmt));
302
303   if (have_row)
304     {
305 #ifdef SVN_DEBUG
306       /* Consistency checks.  Verify both files exist and match.
307        * ### We could check much more. */
308       {
309         apr_finfo_t finfo1, finfo2;
310
311         SVN_ERR(svn_stream__install_get_info(&finfo1, install_stream, APR_FINFO_SIZE,
312                                              scratch_pool));
313
314         SVN_ERR(svn_io_stat(&finfo2, pristine_abspath, APR_FINFO_SIZE,
315                             scratch_pool));
316         if (finfo1.size != finfo2.size)
317           {
318             return svn_error_createf(
319               SVN_ERR_WC_CORRUPT_TEXT_BASE, NULL,
320               _("New pristine text '%s' has different size: %ld versus %ld"),
321               svn_checksum_to_cstring_display(sha1_checksum, scratch_pool),
322               (long int)finfo1.size, (long int)finfo2.size);
323           }
324       }
325 #endif
326
327       /* Remove the temp file: it's already there */
328       SVN_ERR(svn_stream__install_delete(install_stream, scratch_pool));
329       return SVN_NO_ERROR;
330     }
331
332   /* Move the file to its target location.  (If it is already there, it is
333    * an orphan file and it doesn't matter if we overwrite it.) */
334   {
335     apr_finfo_t finfo;
336     SVN_ERR(svn_stream__install_get_info(&finfo, install_stream, APR_FINFO_SIZE,
337                                          scratch_pool));
338     SVN_ERR(svn_stream__install_stream(install_stream, pristine_abspath,
339                                         TRUE, scratch_pool));
340
341     SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
342                                       STMT_INSERT_PRISTINE));
343     SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
344     SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, scratch_pool));
345     SVN_ERR(svn_sqlite__bind_int64(stmt, 3, finfo.size));
346     SVN_ERR(svn_sqlite__insert(NULL, stmt));
347
348     SVN_ERR(svn_io_set_file_read_only(pristine_abspath, FALSE, scratch_pool));
349   }
350
351   return SVN_NO_ERROR;
352 }
353
354 struct svn_wc__db_install_data_t
355 {
356   svn_wc__db_wcroot_t *wcroot;
357   svn_stream_t *inner_stream;
358 };
359
360 svn_error_t *
361 svn_wc__db_pristine_prepare_install(svn_stream_t **stream,
362                                     svn_wc__db_install_data_t **install_data,
363                                     svn_checksum_t **sha1_checksum,
364                                     svn_checksum_t **md5_checksum,
365                                     svn_wc__db_t *db,
366                                     const char *wri_abspath,
367                                     apr_pool_t *result_pool,
368                                     apr_pool_t *scratch_pool)
369 {
370   svn_wc__db_wcroot_t *wcroot;
371   const char *local_relpath;
372   const char *temp_dir_abspath;
373
374   SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
375
376   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
377                               wri_abspath, scratch_pool, scratch_pool));
378   VERIFY_USABLE_WCROOT(wcroot);
379
380   temp_dir_abspath = pristine_get_tempdir(wcroot, scratch_pool, scratch_pool);
381
382   *install_data = apr_pcalloc(result_pool, sizeof(**install_data));
383   (*install_data)->wcroot = wcroot;
384
385   SVN_ERR_W(svn_stream__create_for_install(stream,
386                                            temp_dir_abspath,
387                                            result_pool, scratch_pool),
388             _("Unable to create pristine install stream"));
389
390   (*install_data)->inner_stream = *stream;
391
392   if (md5_checksum)
393     *stream = svn_stream_checksummed2(*stream, NULL, md5_checksum,
394                                       svn_checksum_md5, FALSE, result_pool);
395   if (sha1_checksum)
396     *stream = svn_stream_checksummed2(*stream, NULL, sha1_checksum,
397                                       svn_checksum_sha1, FALSE, result_pool);
398
399   return SVN_NO_ERROR;
400 }
401
402 svn_error_t *
403 svn_wc__db_pristine_install(svn_wc__db_install_data_t *install_data,
404                             const svn_checksum_t *sha1_checksum,
405                             const svn_checksum_t *md5_checksum,
406                             apr_pool_t *scratch_pool)
407 {
408   svn_wc__db_wcroot_t *wcroot = install_data->wcroot;
409   const char *pristine_abspath;
410
411   SVN_ERR_ASSERT(sha1_checksum != NULL);
412   SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
413   SVN_ERR_ASSERT(md5_checksum != NULL);
414   SVN_ERR_ASSERT(md5_checksum->kind == svn_checksum_md5);
415
416   SVN_ERR(get_pristine_fname(&pristine_abspath, wcroot->abspath,
417                              sha1_checksum,
418                              scratch_pool, scratch_pool));
419
420   /* Ensure the SQL txn has at least a 'RESERVED' lock before we start looking
421    * at the disk, to ensure no concurrent pristine install/delete txn. */
422   SVN_SQLITE__WITH_IMMEDIATE_TXN(
423     pristine_install_txn(wcroot->sdb,
424                          install_data->inner_stream, pristine_abspath,
425                          sha1_checksum, md5_checksum,
426                          scratch_pool),
427     wcroot->sdb);
428
429   return SVN_NO_ERROR;
430 }
431
432 svn_error_t *
433 svn_wc__db_pristine_install_abort(svn_wc__db_install_data_t *install_data,
434                                   apr_pool_t *scratch_pool)
435 {
436   return svn_error_trace(svn_stream__install_delete(install_data->inner_stream,
437                                                     scratch_pool));
438 }
439
440
441 svn_error_t *
442 svn_wc__db_pristine_get_md5(const svn_checksum_t **md5_checksum,
443                             svn_wc__db_t *db,
444                             const char *wri_abspath,
445                             const svn_checksum_t *sha1_checksum,
446                             apr_pool_t *result_pool,
447                             apr_pool_t *scratch_pool)
448 {
449   svn_wc__db_wcroot_t *wcroot;
450   const char *local_relpath;
451   svn_sqlite__stmt_t *stmt;
452   svn_boolean_t have_row;
453
454   SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
455   SVN_ERR_ASSERT(sha1_checksum != NULL);
456   SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
457
458   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
459                               wri_abspath, scratch_pool, scratch_pool));
460   VERIFY_USABLE_WCROOT(wcroot);
461
462   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_PRISTINE));
463   SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
464   SVN_ERR(svn_sqlite__step(&have_row, stmt));
465   if (!have_row)
466     return svn_error_createf(SVN_ERR_WC_DB_ERROR, svn_sqlite__reset(stmt),
467                              _("The pristine text with checksum '%s' was "
468                                "not found"),
469                              svn_checksum_to_cstring_display(sha1_checksum,
470                                                              scratch_pool));
471
472   SVN_ERR(svn_sqlite__column_checksum(md5_checksum, stmt, 0, result_pool));
473   SVN_ERR_ASSERT((*md5_checksum)->kind == svn_checksum_md5);
474
475   return svn_error_trace(svn_sqlite__reset(stmt));
476 }
477
478
479 svn_error_t *
480 svn_wc__db_pristine_get_sha1(const svn_checksum_t **sha1_checksum,
481                              svn_wc__db_t *db,
482                              const char *wri_abspath,
483                              const svn_checksum_t *md5_checksum,
484                              apr_pool_t *result_pool,
485                              apr_pool_t *scratch_pool)
486 {
487   svn_wc__db_wcroot_t *wcroot;
488   const char *local_relpath;
489   svn_sqlite__stmt_t *stmt;
490   svn_boolean_t have_row;
491
492   SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
493   SVN_ERR_ASSERT(sha1_checksum != NULL);
494   SVN_ERR_ASSERT(md5_checksum->kind == svn_checksum_md5);
495
496   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
497                               wri_abspath, scratch_pool, scratch_pool));
498   VERIFY_USABLE_WCROOT(wcroot);
499
500   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
501                                     STMT_SELECT_PRISTINE_BY_MD5));
502   SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, md5_checksum, scratch_pool));
503   SVN_ERR(svn_sqlite__step(&have_row, stmt));
504   if (!have_row)
505     return svn_error_createf(SVN_ERR_WC_DB_ERROR, svn_sqlite__reset(stmt),
506                              _("The pristine text with MD5 checksum '%s' was "
507                                "not found"),
508                              svn_checksum_to_cstring_display(md5_checksum,
509                                                              scratch_pool));
510
511   SVN_ERR(svn_sqlite__column_checksum(sha1_checksum, stmt, 0, result_pool));
512   SVN_ERR_ASSERT((*sha1_checksum)->kind == svn_checksum_sha1);
513
514   return svn_error_trace(svn_sqlite__reset(stmt));
515 }
516
517 /* Handle the moving of a pristine from SRC_WCROOT to DST_WCROOT. The existing
518    pristine in SRC_WCROOT is described by CHECKSUM, MD5_CHECKSUM and SIZE */
519 static svn_error_t *
520 maybe_transfer_one_pristine(svn_wc__db_wcroot_t *src_wcroot,
521                             svn_wc__db_wcroot_t *dst_wcroot,
522                             const svn_checksum_t *checksum,
523                             const svn_checksum_t *md5_checksum,
524                             apr_int64_t size,
525                             svn_cancel_func_t cancel_func,
526                             void *cancel_baton,
527                             apr_pool_t *scratch_pool)
528 {
529   const char *pristine_abspath;
530   svn_sqlite__stmt_t *stmt;
531   svn_stream_t *src_stream;
532   svn_stream_t *dst_stream;
533   const char *tmp_abspath;
534   const char *src_abspath;
535   int affected_rows;
536   svn_error_t *err;
537
538   SVN_ERR(svn_sqlite__get_statement(&stmt, dst_wcroot->sdb,
539                                     STMT_INSERT_OR_IGNORE_PRISTINE));
540   SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, checksum, scratch_pool));
541   SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, scratch_pool));
542   SVN_ERR(svn_sqlite__bind_int64(stmt, 3, size));
543
544   SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
545
546   if (affected_rows == 0)
547     return SVN_NO_ERROR;
548
549   SVN_ERR(svn_stream_open_unique(&dst_stream, &tmp_abspath,
550                                  pristine_get_tempdir(dst_wcroot,
551                                                       scratch_pool,
552                                                       scratch_pool),
553                                  svn_io_file_del_on_pool_cleanup,
554                                  scratch_pool, scratch_pool));
555
556   SVN_ERR(get_pristine_fname(&src_abspath, src_wcroot->abspath, checksum,
557                              scratch_pool, scratch_pool));
558
559   SVN_ERR(svn_stream_open_readonly(&src_stream, src_abspath,
560                                    scratch_pool, scratch_pool));
561
562   /* ### Should we verify the SHA1 or MD5 here, or is that too expensive? */
563   SVN_ERR(svn_stream_copy3(src_stream, dst_stream,
564                            cancel_func, cancel_baton,
565                            scratch_pool));
566
567   SVN_ERR(get_pristine_fname(&pristine_abspath, dst_wcroot->abspath, checksum,
568                              scratch_pool, scratch_pool));
569
570   /* Move the file to its target location.  (If it is already there, it is
571    * an orphan file and it doesn't matter if we overwrite it.) */
572   err = svn_io_file_rename(tmp_abspath, pristine_abspath, scratch_pool);
573
574   /* Maybe the directory doesn't exist yet? */
575   if (err && APR_STATUS_IS_ENOENT(err->apr_err))
576     {
577       svn_error_t *err2;
578
579       err2 = svn_io_dir_make(svn_dirent_dirname(pristine_abspath,
580                                                 scratch_pool),
581                              APR_OS_DEFAULT, scratch_pool);
582
583       if (err2)
584         /* Creating directory didn't work: Return all errors */
585         return svn_error_trace(svn_error_compose_create(err, err2));
586       else
587         /* We could create a directory: retry install */
588         svn_error_clear(err);
589
590       SVN_ERR(svn_io_file_rename(tmp_abspath, pristine_abspath, scratch_pool));
591     }
592   else
593     SVN_ERR(err);
594
595   return SVN_NO_ERROR;
596 }
597
598 /* Transaction implementation of svn_wc__db_pristine_transfer().
599    We have a lock on DST_WCROOT.
600  */
601 static svn_error_t *
602 pristine_transfer_txn(svn_wc__db_wcroot_t *src_wcroot,
603                        svn_wc__db_wcroot_t *dst_wcroot,
604                        const char *src_relpath,
605                        svn_cancel_func_t cancel_func,
606                        void *cancel_baton,
607                        apr_pool_t *scratch_pool)
608 {
609   svn_sqlite__stmt_t *stmt;
610   svn_boolean_t got_row;
611   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
612
613   SVN_ERR(svn_sqlite__get_statement(&stmt, src_wcroot->sdb,
614                                     STMT_SELECT_COPY_PRISTINES));
615   SVN_ERR(svn_sqlite__bindf(stmt, "is", src_wcroot->wc_id, src_relpath));
616
617   /* This obtains an sqlite read lock on src_wcroot */
618   SVN_ERR(svn_sqlite__step(&got_row, stmt));
619
620   while (got_row)
621     {
622       const svn_checksum_t *checksum;
623       const svn_checksum_t *md5_checksum;
624       apr_int64_t size;
625       svn_error_t *err;
626
627       svn_pool_clear(iterpool);
628
629       SVN_ERR(svn_sqlite__column_checksum(&checksum, stmt, 0, iterpool));
630       SVN_ERR(svn_sqlite__column_checksum(&md5_checksum, stmt, 1, iterpool));
631       size = svn_sqlite__column_int64(stmt, 2);
632
633       err = maybe_transfer_one_pristine(src_wcroot, dst_wcroot,
634                                         checksum, md5_checksum, size,
635                                         cancel_func, cancel_baton,
636                                         iterpool);
637
638       if (err)
639         return svn_error_trace(svn_error_compose_create(
640                                     err,
641                                     svn_sqlite__reset(stmt)));
642
643       SVN_ERR(svn_sqlite__step(&got_row, stmt));
644     }
645   SVN_ERR(svn_sqlite__reset(stmt));
646
647   svn_pool_destroy(iterpool);
648
649   return SVN_NO_ERROR;
650 }
651
652 svn_error_t *
653 svn_wc__db_pristine_transfer(svn_wc__db_t *db,
654                              const char *src_local_abspath,
655                              const char *dst_wri_abspath,
656                              svn_cancel_func_t cancel_func,
657                              void *cancel_baton,
658                              apr_pool_t *scratch_pool)
659 {
660   svn_wc__db_wcroot_t *src_wcroot, *dst_wcroot;
661   const char *src_relpath, *dst_relpath;
662
663   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&src_wcroot, &src_relpath,
664                                                 db, src_local_abspath,
665                                                 scratch_pool, scratch_pool));
666   VERIFY_USABLE_WCROOT(src_wcroot);
667   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&dst_wcroot, &dst_relpath,
668                                                 db, dst_wri_abspath,
669                                                 scratch_pool, scratch_pool));
670   VERIFY_USABLE_WCROOT(dst_wcroot);
671
672   if (src_wcroot == dst_wcroot
673       || src_wcroot->sdb == dst_wcroot->sdb)
674     {
675       return SVN_NO_ERROR; /* Nothing to transfer */
676     }
677
678   SVN_WC__DB_WITH_TXN(
679     pristine_transfer_txn(src_wcroot, dst_wcroot, src_relpath,
680                           cancel_func, cancel_baton, scratch_pool),
681     dst_wcroot);
682
683   return SVN_NO_ERROR;
684 }
685
686
687
688
689 /* Remove the file at FILE_ABSPATH in such a way that we could re-create a
690  * new file of the same name at any time thereafter.
691  *
692  * On Windows, the file will not disappear immediately from the directory if
693  * it is still being read so the best thing to do is first rename it to a
694  * unique name. */
695 static svn_error_t *
696 remove_file(const char *file_abspath,
697             svn_wc__db_wcroot_t *wcroot,
698             svn_boolean_t ignore_enoent,
699             apr_pool_t *scratch_pool)
700 {
701 #ifdef WIN32
702   svn_error_t *err;
703   const char *temp_abspath;
704   const char *temp_dir_abspath
705     = pristine_get_tempdir(wcroot, scratch_pool, scratch_pool);
706
707   /* To rename the file to a unique name in the temp dir, first create a
708    * uniquely named file in the temp dir and then overwrite it. */
709   SVN_ERR(svn_io_open_unique_file3(NULL, &temp_abspath, temp_dir_abspath,
710                                    svn_io_file_del_none,
711                                    scratch_pool, scratch_pool));
712   err = svn_io_file_rename(file_abspath, temp_abspath, scratch_pool);
713   if (err && ignore_enoent && APR_STATUS_IS_ENOENT(err->apr_err))
714     svn_error_clear(err);
715   else
716     SVN_ERR(err);
717   file_abspath = temp_abspath;
718 #endif
719
720   SVN_ERR(svn_io_remove_file2(file_abspath, ignore_enoent, scratch_pool));
721
722   return SVN_NO_ERROR;
723 }
724
725 /* If the pristine text referenced by SHA1_CHECKSUM in WCROOT/SDB, whose path
726  * within the pristine store is PRISTINE_ABSPATH, has a reference count of
727  * zero, delete it (both the database row and the disk file).
728  *
729  * This function expects to be executed inside a SQLite txn that has already
730  * acquired a 'RESERVED' lock.
731  */
732 static svn_error_t *
733 pristine_remove_if_unreferenced_txn(svn_sqlite__db_t *sdb,
734                                     svn_wc__db_wcroot_t *wcroot,
735                                     const svn_checksum_t *sha1_checksum,
736                                     const char *pristine_abspath,
737                                     apr_pool_t *scratch_pool)
738 {
739   svn_sqlite__stmt_t *stmt;
740   int affected_rows;
741
742   /* Remove the DB row, if refcount is 0. */
743   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
744                                     STMT_DELETE_PRISTINE_IF_UNREFERENCED));
745   SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
746   SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
747
748   /* If we removed the DB row, then remove the file. */
749   if (affected_rows > 0)
750     {
751       /* If the file is not present, something has gone wrong, but at this
752        * point it no longer matters.  In a debug build, raise an error, but
753        * in a release build, it is more helpful to ignore it and continue. */
754 #ifdef SVN_DEBUG
755       svn_boolean_t ignore_enoent = FALSE;
756 #else
757       svn_boolean_t ignore_enoent = TRUE;
758 #endif
759
760       SVN_ERR(remove_file(pristine_abspath, wcroot, ignore_enoent,
761                           scratch_pool));
762     }
763
764   return SVN_NO_ERROR;
765 }
766
767 /* If the pristine text referenced by SHA1_CHECKSUM in WCROOT has a
768  * reference count of zero, delete it (both the database row and the disk
769  * file).
770  *
771  * Implements 'notes/wc-ng/pristine-store' section A-3(b). */
772 static svn_error_t *
773 pristine_remove_if_unreferenced(svn_wc__db_wcroot_t *wcroot,
774                                 const svn_checksum_t *sha1_checksum,
775                                 apr_pool_t *scratch_pool)
776 {
777   const char *pristine_abspath;
778
779   SVN_ERR(get_pristine_fname(&pristine_abspath, wcroot->abspath,
780                              sha1_checksum, scratch_pool, scratch_pool));
781
782   /* Ensure the SQL txn has at least a 'RESERVED' lock before we start looking
783    * at the disk, to ensure no concurrent pristine install/delete txn. */
784   SVN_SQLITE__WITH_IMMEDIATE_TXN(
785     pristine_remove_if_unreferenced_txn(
786       wcroot->sdb, wcroot, sha1_checksum, pristine_abspath, scratch_pool),
787     wcroot->sdb);
788
789   return SVN_NO_ERROR;
790 }
791
792 svn_error_t *
793 svn_wc__db_pristine_remove(svn_wc__db_t *db,
794                            const char *wri_abspath,
795                            const svn_checksum_t *sha1_checksum,
796                            apr_pool_t *scratch_pool)
797 {
798   svn_wc__db_wcroot_t *wcroot;
799   const char *local_relpath;
800
801   SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
802   SVN_ERR_ASSERT(sha1_checksum != NULL);
803   /* ### Transitional: accept MD-5 and look up the SHA-1.  Return an error
804    * if the pristine text is not in the store. */
805   if (sha1_checksum->kind != svn_checksum_sha1)
806     SVN_ERR(svn_wc__db_pristine_get_sha1(&sha1_checksum, db, wri_abspath,
807                                          sha1_checksum,
808                                          scratch_pool, scratch_pool));
809   SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
810
811   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
812                               wri_abspath, scratch_pool, scratch_pool));
813   VERIFY_USABLE_WCROOT(wcroot);
814
815   /* If the work queue is not empty, don't delete any pristine text because
816    * the work queue may contain a reference to it. */
817   {
818     svn_sqlite__stmt_t *stmt;
819     svn_boolean_t have_row;
820
821     SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_LOOK_FOR_WORK));
822     SVN_ERR(svn_sqlite__step(&have_row, stmt));
823     SVN_ERR(svn_sqlite__reset(stmt));
824
825     if (have_row)
826       return SVN_NO_ERROR;
827   }
828
829   /* If not referenced, remove the PRISTINE table row and the file. */
830   SVN_ERR(pristine_remove_if_unreferenced(wcroot, sha1_checksum, scratch_pool));
831
832   return SVN_NO_ERROR;
833 }
834
835
836 /* Remove all unreferenced pristines in the WC DB in WCROOT.
837  *
838  * Look for pristine texts whose 'refcount' in the DB is zero, and remove
839  * them from the 'pristine' table and from disk.
840  *
841  * TODO: At least check that any zero refcount is really correct, before
842  *       using it.  See dev@ email thread "Pristine text missing - cleanup
843  *       doesn't work", <http://svn.haxx.se/dev/archive-2013-04/0426.shtml>.
844  *
845  * TODO: Ideas for possible extra clean-up operations:
846  *
847  *       * Check and correct all the refcounts.  Identify any rows missing
848  *         from the 'pristine' table.  (Create a temporary index for speed
849  *         if necessary?)
850  *
851  *       * Check the checksums.  (Very expensive to check them all, so find
852  *         a way to not check them all.)
853  *
854  *       * Check for pristine files missing from disk but referenced in the
855  *         'pristine' table.
856  *
857  *       * Repair any pristine files missing from disk and/or rows missing
858  *         from the 'pristine' table and/or bad checksums.  Generally
859  *         requires contacting the server, so requires support at a higher
860  *         level than this function.
861  *
862  *       * Identify any pristine text files on disk that are not referenced
863  *         in the DB, and delete them.
864  *
865  * TODO: Provide feedback about any errors found and any corrections made.
866  */
867 static svn_error_t *
868 pristine_cleanup_wcroot(svn_wc__db_wcroot_t *wcroot,
869                         apr_pool_t *scratch_pool)
870 {
871   svn_sqlite__stmt_t *stmt;
872   svn_error_t *err = NULL;
873   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
874
875   /* Find each unreferenced pristine in the DB and remove it. */
876   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
877                                     STMT_SELECT_UNREFERENCED_PRISTINES));
878   while (! err)
879     {
880       svn_boolean_t have_row;
881       const svn_checksum_t *sha1_checksum;
882
883       svn_pool_clear(iterpool);
884
885       SVN_ERR(svn_sqlite__step(&have_row, stmt));
886       if (! have_row)
887         break;
888
889       SVN_ERR(svn_sqlite__column_checksum(&sha1_checksum, stmt, 0,
890                                           iterpool));
891       err = pristine_remove_if_unreferenced(wcroot, sha1_checksum,
892                                             iterpool);
893     }
894
895   svn_pool_destroy(iterpool);
896
897   return svn_error_trace(
898       svn_error_compose_create(err, svn_sqlite__reset(stmt)));
899 }
900
901 svn_error_t *
902 svn_wc__db_pristine_cleanup(svn_wc__db_t *db,
903                             const char *wri_abspath,
904                             apr_pool_t *scratch_pool)
905 {
906   svn_wc__db_wcroot_t *wcroot;
907   const char *local_relpath;
908
909   SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
910
911   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
912                               wri_abspath, scratch_pool, scratch_pool));
913   VERIFY_USABLE_WCROOT(wcroot);
914
915   SVN_ERR(pristine_cleanup_wcroot(wcroot, scratch_pool));
916
917   return SVN_NO_ERROR;
918 }
919
920
921 svn_error_t *
922 svn_wc__db_pristine_check(svn_boolean_t *present,
923                           svn_wc__db_t *db,
924                           const char *wri_abspath,
925                           const svn_checksum_t *sha1_checksum,
926                           apr_pool_t *scratch_pool)
927 {
928   svn_wc__db_wcroot_t *wcroot;
929   const char *local_relpath;
930   svn_sqlite__stmt_t *stmt;
931   svn_boolean_t have_row;
932
933   SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
934   SVN_ERR_ASSERT(sha1_checksum != NULL);
935
936   if (sha1_checksum->kind != svn_checksum_sha1)
937     {
938       *present = FALSE;
939       return SVN_NO_ERROR;
940     }
941
942   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
943                               wri_abspath, scratch_pool, scratch_pool));
944   VERIFY_USABLE_WCROOT(wcroot);
945
946   /* A filestat is much cheaper than a sqlite transaction especially on NFS,
947      so first check if there is a pristine file and then if we are allowed
948      to use it. */
949   {
950     const char *pristine_abspath;
951     svn_node_kind_t kind_on_disk;
952
953     SVN_ERR(get_pristine_fname(&pristine_abspath, wcroot->abspath,
954                                sha1_checksum, scratch_pool, scratch_pool));
955     SVN_ERR(svn_io_check_path(pristine_abspath, &kind_on_disk, scratch_pool));
956     if (kind_on_disk != svn_node_file)
957       {
958         *present = FALSE;
959         return SVN_NO_ERROR;
960       }
961   }
962
963   /* Check that there is an entry in the PRISTINE table. */
964   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_PRISTINE));
965   SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
966   SVN_ERR(svn_sqlite__step(&have_row, stmt));
967   SVN_ERR(svn_sqlite__reset(stmt));
968
969   *present = have_row;
970   return SVN_NO_ERROR;
971 }