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. */ 49static svn_error_t * 50get_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 93svn_error_t * 94svn_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 137svn_error_t * 138svn_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 */ 165static svn_error_t * 166pristine_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 204svn_error_t * 205svn_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. */ 249static char * 250pristine_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 259svn_error_t * 260svn_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 */ 290static svn_error_t * 291pristine_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 382svn_error_t * 383svn_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 431svn_error_t * 432svn_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 469svn_error_t * 470svn_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 */ 509static svn_error_t * 510maybe_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 */ 591static svn_error_t * 592pristine_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 642svn_error_t * 643svn_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. */ 685static svn_error_t * 686remove_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 */ 722static svn_error_t * 723pristine_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). */ 762static svn_error_t * 763pristine_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 782svn_error_t * 783svn_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 826static svn_error_t * 827pristine_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 855svn_error_t * 856svn_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 875svn_error_t * 876svn_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} 926