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