wc_db_pristine.c revision 362181
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. */ 52static svn_error_t * 53get_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 96svn_error_t * 97svn_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 140svn_error_t * 141svn_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 */ 168static svn_error_t * 169pristine_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 217svn_error_t * 218svn_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(svn_dirent_is_absolute(wri_abspath)); 231 232 /* Some 1.6-to-1.7 wc upgrades created rows without checksums and 233 updating such a row passes NULL here. */ 234 if (!sha1_checksum) 235 return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, 236 _("Can't read '%s' from pristine store " 237 "because no checksum supplied"), 238 svn_dirent_local_style(wri_abspath, scratch_pool)); 239 240 SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1); 241 242 SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, 243 wri_abspath, scratch_pool, scratch_pool)); 244 VERIFY_USABLE_WCROOT(wcroot); 245 246 SVN_ERR(get_pristine_fname(&pristine_abspath, wcroot->abspath, 247 sha1_checksum, 248 scratch_pool, scratch_pool)); 249 SVN_WC__DB_WITH_TXN( 250 pristine_read_txn(contents, size, 251 wcroot, sha1_checksum, pristine_abspath, 252 result_pool, scratch_pool), 253 wcroot); 254 255 return SVN_NO_ERROR; 256} 257 258 259/* Return the absolute path to the temporary directory for pristine text 260 files within WCROOT. */ 261static char * 262pristine_get_tempdir(svn_wc__db_wcroot_t *wcroot, 263 apr_pool_t *result_pool, 264 apr_pool_t *scratch_pool) 265{ 266 return svn_dirent_join_many(result_pool, wcroot->abspath, 267 svn_wc_get_adm_dir(scratch_pool), 268 PRISTINE_TEMPDIR_RELPATH, SVN_VA_NULL); 269} 270 271/* Install the pristine text described by BATON into the pristine store of 272 * SDB. If it is already stored then just delete the new file 273 * BATON->tempfile_abspath. 274 * 275 * This function expects to be executed inside a SQLite txn that has already 276 * acquired a 'RESERVED' lock. 277 * 278 * Implements 'notes/wc-ng/pristine-store' section A-3(a). 279 */ 280static svn_error_t * 281pristine_install_txn(svn_sqlite__db_t *sdb, 282 /* The path to the source file that is to be moved into place. */ 283 svn_stream_t *install_stream, 284 /* The target path for the file (within the pristine store). */ 285 const char *pristine_abspath, 286 /* The pristine text's SHA-1 checksum. */ 287 const svn_checksum_t *sha1_checksum, 288 /* The pristine text's MD-5 checksum. */ 289 const svn_checksum_t *md5_checksum, 290 apr_pool_t *scratch_pool) 291{ 292 svn_sqlite__stmt_t *stmt; 293 svn_boolean_t have_row; 294 295 /* If this pristine text is already present in the store, just keep it: 296 * delete the new one and return. */ 297 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_PRISTINE)); 298 SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); 299 SVN_ERR(svn_sqlite__step(&have_row, stmt)); 300 SVN_ERR(svn_sqlite__reset(stmt)); 301 302 if (have_row) 303 { 304#ifdef SVN_DEBUG 305 /* Consistency checks. Verify both files exist and match. 306 * ### We could check much more. */ 307 { 308 apr_finfo_t finfo1, finfo2; 309 310 SVN_ERR(svn_stream__install_get_info(&finfo1, install_stream, APR_FINFO_SIZE, 311 scratch_pool)); 312 313 SVN_ERR(svn_io_stat(&finfo2, pristine_abspath, APR_FINFO_SIZE, 314 scratch_pool)); 315 if (finfo1.size != finfo2.size) 316 { 317 return svn_error_createf( 318 SVN_ERR_WC_CORRUPT_TEXT_BASE, NULL, 319 _("New pristine text '%s' has different size: %s versus %s"), 320 svn_checksum_to_cstring_display(sha1_checksum, scratch_pool), 321 apr_off_t_toa(scratch_pool, finfo1.size), 322 apr_off_t_toa(scratch_pool, 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, 337 APR_FINFO_SIZE, 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, STMT_INSERT_PRISTINE)); 342 SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); 343 SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, scratch_pool)); 344 SVN_ERR(svn_sqlite__bind_int64(stmt, 3, finfo.size)); 345 SVN_ERR(svn_sqlite__insert(NULL, stmt)); 346 347 SVN_ERR(svn_io_set_file_read_only(pristine_abspath, FALSE, scratch_pool)); 348 } 349 350 return SVN_NO_ERROR; 351} 352 353struct svn_wc__db_install_data_t 354{ 355 svn_wc__db_wcroot_t *wcroot; 356 svn_stream_t *inner_stream; 357}; 358 359svn_error_t * 360svn_wc__db_pristine_prepare_install(svn_stream_t **stream, 361 svn_wc__db_install_data_t **install_data, 362 svn_checksum_t **sha1_checksum, 363 svn_checksum_t **md5_checksum, 364 svn_wc__db_t *db, 365 const char *wri_abspath, 366 apr_pool_t *result_pool, 367 apr_pool_t *scratch_pool) 368{ 369 svn_wc__db_wcroot_t *wcroot; 370 const char *local_relpath; 371 const char *temp_dir_abspath; 372 373 SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); 374 375 SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, 376 wri_abspath, scratch_pool, scratch_pool)); 377 VERIFY_USABLE_WCROOT(wcroot); 378 379 temp_dir_abspath = pristine_get_tempdir(wcroot, scratch_pool, scratch_pool); 380 381 *install_data = apr_pcalloc(result_pool, sizeof(**install_data)); 382 (*install_data)->wcroot = wcroot; 383 384 SVN_ERR_W(svn_stream__create_for_install(stream, 385 temp_dir_abspath, 386 result_pool, scratch_pool), 387 _("Unable to create pristine install stream")); 388 389 (*install_data)->inner_stream = *stream; 390 391 if (md5_checksum) 392 *stream = svn_stream_checksummed2(*stream, NULL, md5_checksum, 393 svn_checksum_md5, FALSE, result_pool); 394 if (sha1_checksum) 395 *stream = svn_stream_checksummed2(*stream, NULL, sha1_checksum, 396 svn_checksum_sha1, FALSE, result_pool); 397 398 return SVN_NO_ERROR; 399} 400 401svn_error_t * 402svn_wc__db_pristine_install(svn_wc__db_install_data_t *install_data, 403 const svn_checksum_t *sha1_checksum, 404 const svn_checksum_t *md5_checksum, 405 apr_pool_t *scratch_pool) 406{ 407 svn_wc__db_wcroot_t *wcroot = install_data->wcroot; 408 const char *pristine_abspath; 409 410 SVN_ERR_ASSERT(sha1_checksum != NULL); 411 SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1); 412 SVN_ERR_ASSERT(md5_checksum != NULL); 413 SVN_ERR_ASSERT(md5_checksum->kind == svn_checksum_md5); 414 415 SVN_ERR(get_pristine_fname(&pristine_abspath, wcroot->abspath, 416 sha1_checksum, 417 scratch_pool, scratch_pool)); 418 419 /* Ensure the SQL txn has at least a 'RESERVED' lock before we start looking 420 * at the disk, to ensure no concurrent pristine install/delete txn. */ 421 SVN_SQLITE__WITH_IMMEDIATE_TXN( 422 pristine_install_txn(wcroot->sdb, 423 install_data->inner_stream, pristine_abspath, 424 sha1_checksum, md5_checksum, 425 scratch_pool), 426 wcroot->sdb); 427 428 return SVN_NO_ERROR; 429} 430 431svn_error_t * 432svn_wc__db_pristine_install_abort(svn_wc__db_install_data_t *install_data, 433 apr_pool_t *scratch_pool) 434{ 435 return svn_error_trace(svn_stream__install_delete(install_data->inner_stream, 436 scratch_pool)); 437} 438 439 440svn_error_t * 441svn_wc__db_pristine_get_md5(const svn_checksum_t **md5_checksum, 442 svn_wc__db_t *db, 443 const char *wri_abspath, 444 const svn_checksum_t *sha1_checksum, 445 apr_pool_t *result_pool, 446 apr_pool_t *scratch_pool) 447{ 448 svn_wc__db_wcroot_t *wcroot; 449 const char *local_relpath; 450 svn_sqlite__stmt_t *stmt; 451 svn_boolean_t have_row; 452 453 SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); 454 SVN_ERR_ASSERT(sha1_checksum != NULL); 455 SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1); 456 457 SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, 458 wri_abspath, scratch_pool, scratch_pool)); 459 VERIFY_USABLE_WCROOT(wcroot); 460 461 SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_PRISTINE)); 462 SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); 463 SVN_ERR(svn_sqlite__step(&have_row, stmt)); 464 if (!have_row) 465 return svn_error_createf(SVN_ERR_WC_DB_ERROR, svn_sqlite__reset(stmt), 466 _("The pristine text with checksum '%s' was " 467 "not found"), 468 svn_checksum_to_cstring_display(sha1_checksum, 469 scratch_pool)); 470 471 SVN_ERR(svn_sqlite__column_checksum(md5_checksum, stmt, 0, result_pool)); 472 SVN_ERR_ASSERT((*md5_checksum)->kind == svn_checksum_md5); 473 474 return svn_error_trace(svn_sqlite__reset(stmt)); 475} 476 477 478svn_error_t * 479svn_wc__db_pristine_get_sha1(const svn_checksum_t **sha1_checksum, 480 svn_wc__db_t *db, 481 const char *wri_abspath, 482 const svn_checksum_t *md5_checksum, 483 apr_pool_t *result_pool, 484 apr_pool_t *scratch_pool) 485{ 486 svn_wc__db_wcroot_t *wcroot; 487 const char *local_relpath; 488 svn_sqlite__stmt_t *stmt; 489 svn_boolean_t have_row; 490 491 SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); 492 SVN_ERR_ASSERT(sha1_checksum != NULL); 493 SVN_ERR_ASSERT(md5_checksum->kind == svn_checksum_md5); 494 495 SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, 496 wri_abspath, scratch_pool, scratch_pool)); 497 VERIFY_USABLE_WCROOT(wcroot); 498 499 SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, 500 STMT_SELECT_PRISTINE_BY_MD5)); 501 SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, md5_checksum, scratch_pool)); 502 SVN_ERR(svn_sqlite__step(&have_row, stmt)); 503 if (!have_row) 504 return svn_error_createf(SVN_ERR_WC_DB_ERROR, svn_sqlite__reset(stmt), 505 _("The pristine text with MD5 checksum '%s' was " 506 "not found"), 507 svn_checksum_to_cstring_display(md5_checksum, 508 scratch_pool)); 509 510 SVN_ERR(svn_sqlite__column_checksum(sha1_checksum, stmt, 0, result_pool)); 511 SVN_ERR_ASSERT((*sha1_checksum)->kind == svn_checksum_sha1); 512 513 return svn_error_trace(svn_sqlite__reset(stmt)); 514} 515 516/* Handle the moving of a pristine from SRC_WCROOT to DST_WCROOT. The existing 517 pristine in SRC_WCROOT is described by CHECKSUM, MD5_CHECKSUM and SIZE */ 518static svn_error_t * 519maybe_transfer_one_pristine(svn_wc__db_wcroot_t *src_wcroot, 520 svn_wc__db_wcroot_t *dst_wcroot, 521 const svn_checksum_t *checksum, 522 const svn_checksum_t *md5_checksum, 523 apr_int64_t size, 524 svn_cancel_func_t cancel_func, 525 void *cancel_baton, 526 apr_pool_t *scratch_pool) 527{ 528 const char *pristine_abspath; 529 svn_sqlite__stmt_t *stmt; 530 svn_stream_t *src_stream; 531 svn_stream_t *dst_stream; 532 const char *tmp_abspath; 533 const char *src_abspath; 534 int affected_rows; 535 svn_error_t *err; 536 537 SVN_ERR(svn_sqlite__get_statement(&stmt, dst_wcroot->sdb, 538 STMT_INSERT_OR_IGNORE_PRISTINE)); 539 SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, checksum, scratch_pool)); 540 SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, scratch_pool)); 541 SVN_ERR(svn_sqlite__bind_int64(stmt, 3, size)); 542 543 SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); 544 545 if (affected_rows == 0) 546 return SVN_NO_ERROR; 547 548 SVN_ERR(svn_stream_open_unique(&dst_stream, &tmp_abspath, 549 pristine_get_tempdir(dst_wcroot, 550 scratch_pool, 551 scratch_pool), 552 svn_io_file_del_on_pool_cleanup, 553 scratch_pool, scratch_pool)); 554 555 SVN_ERR(get_pristine_fname(&src_abspath, src_wcroot->abspath, checksum, 556 scratch_pool, scratch_pool)); 557 558 SVN_ERR(svn_stream_open_readonly(&src_stream, src_abspath, 559 scratch_pool, scratch_pool)); 560 561 /* ### Should we verify the SHA1 or MD5 here, or is that too expensive? */ 562 SVN_ERR(svn_stream_copy3(src_stream, dst_stream, 563 cancel_func, cancel_baton, 564 scratch_pool)); 565 566 SVN_ERR(get_pristine_fname(&pristine_abspath, dst_wcroot->abspath, checksum, 567 scratch_pool, scratch_pool)); 568 569 /* Move the file to its target location. (If it is already there, it is 570 * an orphan file and it doesn't matter if we overwrite it.) */ 571 err = svn_io_file_rename2(tmp_abspath, pristine_abspath, FALSE, 572 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_rename2(tmp_abspath, pristine_abspath, FALSE, 591 scratch_pool)); 592 } 593 else 594 SVN_ERR(err); 595 596 return SVN_NO_ERROR; 597} 598 599/* Transaction implementation of svn_wc__db_pristine_transfer(). 600 We have a lock on DST_WCROOT. 601 */ 602static svn_error_t * 603pristine_transfer_txn(svn_wc__db_wcroot_t *src_wcroot, 604 svn_wc__db_wcroot_t *dst_wcroot, 605 const char *src_relpath, 606 svn_cancel_func_t cancel_func, 607 void *cancel_baton, 608 apr_pool_t *scratch_pool) 609{ 610 svn_sqlite__stmt_t *stmt; 611 svn_boolean_t got_row; 612 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 613 614 SVN_ERR(svn_sqlite__get_statement(&stmt, src_wcroot->sdb, 615 STMT_SELECT_COPY_PRISTINES)); 616 SVN_ERR(svn_sqlite__bindf(stmt, "is", src_wcroot->wc_id, src_relpath)); 617 618 /* This obtains an sqlite read lock on src_wcroot */ 619 SVN_ERR(svn_sqlite__step(&got_row, stmt)); 620 621 while (got_row) 622 { 623 const svn_checksum_t *checksum; 624 const svn_checksum_t *md5_checksum; 625 apr_int64_t size; 626 svn_error_t *err; 627 628 svn_pool_clear(iterpool); 629 630 SVN_ERR(svn_sqlite__column_checksum(&checksum, stmt, 0, iterpool)); 631 SVN_ERR(svn_sqlite__column_checksum(&md5_checksum, stmt, 1, iterpool)); 632 size = svn_sqlite__column_int64(stmt, 2); 633 634 err = maybe_transfer_one_pristine(src_wcroot, dst_wcroot, 635 checksum, md5_checksum, size, 636 cancel_func, cancel_baton, 637 iterpool); 638 639 if (err) 640 return svn_error_trace(svn_error_compose_create( 641 err, 642 svn_sqlite__reset(stmt))); 643 644 SVN_ERR(svn_sqlite__step(&got_row, stmt)); 645 } 646 SVN_ERR(svn_sqlite__reset(stmt)); 647 648 svn_pool_destroy(iterpool); 649 650 return SVN_NO_ERROR; 651} 652 653svn_error_t * 654svn_wc__db_pristine_transfer(svn_wc__db_t *db, 655 const char *src_local_abspath, 656 const char *dst_wri_abspath, 657 svn_cancel_func_t cancel_func, 658 void *cancel_baton, 659 apr_pool_t *scratch_pool) 660{ 661 svn_wc__db_wcroot_t *src_wcroot, *dst_wcroot; 662 const char *src_relpath, *dst_relpath; 663 664 SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&src_wcroot, &src_relpath, 665 db, src_local_abspath, 666 scratch_pool, scratch_pool)); 667 VERIFY_USABLE_WCROOT(src_wcroot); 668 SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&dst_wcroot, &dst_relpath, 669 db, dst_wri_abspath, 670 scratch_pool, scratch_pool)); 671 VERIFY_USABLE_WCROOT(dst_wcroot); 672 673 if (src_wcroot == dst_wcroot 674 || src_wcroot->sdb == dst_wcroot->sdb) 675 { 676 return SVN_NO_ERROR; /* Nothing to transfer */ 677 } 678 679 SVN_WC__DB_WITH_TXN( 680 pristine_transfer_txn(src_wcroot, dst_wcroot, src_relpath, 681 cancel_func, cancel_baton, scratch_pool), 682 dst_wcroot); 683 684 return SVN_NO_ERROR; 685} 686 687 688 689 690/* If the pristine text referenced by SHA1_CHECKSUM in WCROOT/SDB, whose path 691 * within the pristine store is PRISTINE_ABSPATH, has a reference count of 692 * zero, delete it (both the database row and the disk file). 693 * 694 * This function expects to be executed inside a SQLite txn that has already 695 * acquired a 'RESERVED' lock. 696 */ 697static svn_error_t * 698pristine_remove_if_unreferenced_txn(svn_sqlite__db_t *sdb, 699 svn_wc__db_wcroot_t *wcroot, 700 const svn_checksum_t *sha1_checksum, 701 const char *pristine_abspath, 702 apr_pool_t *scratch_pool) 703{ 704 svn_sqlite__stmt_t *stmt; 705 int affected_rows; 706 707 /* Remove the DB row, if refcount is 0. */ 708 SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 709 STMT_DELETE_PRISTINE_IF_UNREFERENCED)); 710 SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); 711 SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); 712 713 /* If we removed the DB row, then remove the file. */ 714 if (affected_rows > 0) 715 { 716 /* If the file is not present, something has gone wrong, but at this 717 * point it no longer matters. In a debug build, raise an error, but 718 * in a release build, it is more helpful to ignore it and continue. */ 719#ifdef SVN_DEBUG 720 svn_boolean_t ignore_enoent = FALSE; 721#else 722 svn_boolean_t ignore_enoent = TRUE; 723#endif 724 725 SVN_ERR(svn_io_remove_file2(pristine_abspath, ignore_enoent, 726 scratch_pool)); 727 } 728 729 return SVN_NO_ERROR; 730} 731 732/* If the pristine text referenced by SHA1_CHECKSUM in WCROOT has a 733 * reference count of zero, delete it (both the database row and the disk 734 * file). 735 * 736 * Implements 'notes/wc-ng/pristine-store' section A-3(b). */ 737static svn_error_t * 738pristine_remove_if_unreferenced(svn_wc__db_wcroot_t *wcroot, 739 const svn_checksum_t *sha1_checksum, 740 apr_pool_t *scratch_pool) 741{ 742 const char *pristine_abspath; 743 744 SVN_ERR(get_pristine_fname(&pristine_abspath, wcroot->abspath, 745 sha1_checksum, scratch_pool, scratch_pool)); 746 747 /* Ensure the SQL txn has at least a 'RESERVED' lock before we start looking 748 * at the disk, to ensure no concurrent pristine install/delete txn. */ 749 SVN_SQLITE__WITH_IMMEDIATE_TXN( 750 pristine_remove_if_unreferenced_txn( 751 wcroot->sdb, wcroot, sha1_checksum, pristine_abspath, scratch_pool), 752 wcroot->sdb); 753 754 return SVN_NO_ERROR; 755} 756 757svn_error_t * 758svn_wc__db_pristine_remove(svn_wc__db_t *db, 759 const char *wri_abspath, 760 const svn_checksum_t *sha1_checksum, 761 apr_pool_t *scratch_pool) 762{ 763 svn_wc__db_wcroot_t *wcroot; 764 const char *local_relpath; 765 766 SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); 767 SVN_ERR_ASSERT(sha1_checksum != NULL); 768 /* ### Transitional: accept MD-5 and look up the SHA-1. Return an error 769 * if the pristine text is not in the store. */ 770 if (sha1_checksum->kind != svn_checksum_sha1) 771 SVN_ERR(svn_wc__db_pristine_get_sha1(&sha1_checksum, db, wri_abspath, 772 sha1_checksum, 773 scratch_pool, scratch_pool)); 774 SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1); 775 776 SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, 777 wri_abspath, scratch_pool, scratch_pool)); 778 VERIFY_USABLE_WCROOT(wcroot); 779 780 /* If the work queue is not empty, don't delete any pristine text because 781 * the work queue may contain a reference to it. */ 782 { 783 svn_sqlite__stmt_t *stmt; 784 svn_boolean_t have_row; 785 786 SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_LOOK_FOR_WORK)); 787 SVN_ERR(svn_sqlite__step(&have_row, stmt)); 788 SVN_ERR(svn_sqlite__reset(stmt)); 789 790 if (have_row) 791 return SVN_NO_ERROR; 792 } 793 794 /* If not referenced, remove the PRISTINE table row and the file. */ 795 SVN_ERR(pristine_remove_if_unreferenced(wcroot, sha1_checksum, scratch_pool)); 796 797 return SVN_NO_ERROR; 798} 799 800 801/* Remove all unreferenced pristines in the WC DB in WCROOT. 802 * 803 * Look for pristine texts whose 'refcount' in the DB is zero, and remove 804 * them from the 'pristine' table and from disk. 805 * 806 * TODO: At least check that any zero refcount is really correct, before 807 * using it. See dev@ email thread "Pristine text missing - cleanup 808 * doesn't work", <http://svn.haxx.se/dev/archive-2013-04/0426.shtml>. 809 * 810 * TODO: Ideas for possible extra clean-up operations: 811 * 812 * * Check and correct all the refcounts. Identify any rows missing 813 * from the 'pristine' table. (Create a temporary index for speed 814 * if necessary?) 815 * 816 * * Check the checksums. (Very expensive to check them all, so find 817 * a way to not check them all.) 818 * 819 * * Check for pristine files missing from disk but referenced in the 820 * 'pristine' table. 821 * 822 * * Repair any pristine files missing from disk and/or rows missing 823 * from the 'pristine' table and/or bad checksums. Generally 824 * requires contacting the server, so requires support at a higher 825 * level than this function. 826 * 827 * * Identify any pristine text files on disk that are not referenced 828 * in the DB, and delete them. 829 * 830 * TODO: Provide feedback about any errors found and any corrections made. 831 */ 832static svn_error_t * 833pristine_cleanup_wcroot(svn_wc__db_wcroot_t *wcroot, 834 apr_pool_t *scratch_pool) 835{ 836 svn_sqlite__stmt_t *stmt; 837 svn_error_t *err = NULL; 838 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 839 840 /* Find each unreferenced pristine in the DB and remove it. */ 841 SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, 842 STMT_SELECT_UNREFERENCED_PRISTINES)); 843 while (! err) 844 { 845 svn_boolean_t have_row; 846 const svn_checksum_t *sha1_checksum; 847 848 svn_pool_clear(iterpool); 849 850 SVN_ERR(svn_sqlite__step(&have_row, stmt)); 851 if (! have_row) 852 break; 853 854 SVN_ERR(svn_sqlite__column_checksum(&sha1_checksum, stmt, 0, 855 iterpool)); 856 err = pristine_remove_if_unreferenced(wcroot, sha1_checksum, 857 iterpool); 858 } 859 860 svn_pool_destroy(iterpool); 861 862 return svn_error_trace( 863 svn_error_compose_create(err, svn_sqlite__reset(stmt))); 864} 865 866svn_error_t * 867svn_wc__db_pristine_cleanup(svn_wc__db_t *db, 868 const char *wri_abspath, 869 apr_pool_t *scratch_pool) 870{ 871 svn_wc__db_wcroot_t *wcroot; 872 const char *local_relpath; 873 874 SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); 875 876 SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, 877 wri_abspath, scratch_pool, scratch_pool)); 878 VERIFY_USABLE_WCROOT(wcroot); 879 880 SVN_ERR(pristine_cleanup_wcroot(wcroot, scratch_pool)); 881 882 return SVN_NO_ERROR; 883} 884 885 886svn_error_t * 887svn_wc__db_pristine_check(svn_boolean_t *present, 888 svn_wc__db_t *db, 889 const char *wri_abspath, 890 const svn_checksum_t *sha1_checksum, 891 apr_pool_t *scratch_pool) 892{ 893 svn_wc__db_wcroot_t *wcroot; 894 const char *local_relpath; 895 svn_sqlite__stmt_t *stmt; 896 svn_boolean_t have_row; 897 898 SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); 899 SVN_ERR_ASSERT(sha1_checksum != NULL); 900 901 if (sha1_checksum->kind != svn_checksum_sha1) 902 { 903 *present = FALSE; 904 return SVN_NO_ERROR; 905 } 906 907 SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, 908 wri_abspath, scratch_pool, scratch_pool)); 909 VERIFY_USABLE_WCROOT(wcroot); 910 911 /* A filestat is much cheaper than a sqlite transaction especially on NFS, 912 so first check if there is a pristine file and then if we are allowed 913 to use it. */ 914 { 915 const char *pristine_abspath; 916 svn_node_kind_t kind_on_disk; 917 svn_error_t *err; 918 919 SVN_ERR(get_pristine_fname(&pristine_abspath, wcroot->abspath, 920 sha1_checksum, scratch_pool, scratch_pool)); 921 err = svn_io_check_path(pristine_abspath, &kind_on_disk, scratch_pool); 922#ifdef WIN32 923 if (err && err->apr_err == APR_FROM_OS_ERROR(ERROR_ACCESS_DENIED)) 924 { 925 svn_error_clear(err); 926 /* Possible race condition: The filename is locked, but there is no 927 file or dir with this name. Let's fall back on checking the DB. 928 929 This case is triggered by the pristine store tests on deleting 930 a file that is still open via another handle, where this other 931 handle has a FILE_SHARE_DELETE share mode. 932 */ 933 } 934 else 935#endif 936 if (err) 937 return svn_error_trace(err); 938 else if (kind_on_disk != svn_node_file) 939 { 940 *present = FALSE; 941 return SVN_NO_ERROR; 942 } 943 } 944 945 /* Check that there is an entry in the PRISTINE table. */ 946 SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_PRISTINE)); 947 SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); 948 SVN_ERR(svn_sqlite__step(&have_row, stmt)); 949 SVN_ERR(svn_sqlite__reset(stmt)); 950 951 *present = have_row; 952 return SVN_NO_ERROR; 953} 954