svn_error_t * svn_fs_fs__set_rep_reference(svn_fs_t *fs, representation_t *rep, apr_pool_t *pool) { fs_fs_data_t *ffd = fs->fsap_data; svn_sqlite__stmt_t *stmt; svn_error_t *err; svn_checksum_t checksum; checksum.kind = svn_checksum_sha1; checksum.digest = rep->sha1_digest; SVN_ERR_ASSERT(ffd->rep_sharing_allowed); if (! ffd->rep_cache_db) SVN_ERR(svn_fs_fs__open_rep_cache(fs, pool)); /* We only allow SHA1 checksums in this table. */ if (! rep->has_sha1) return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, _("Only SHA1 checksums can be used as keys in the " "rep_cache table.\n")); SVN_ERR(svn_sqlite__get_statement(&stmt, ffd->rep_cache_db, STMT_SET_REP)); SVN_ERR(svn_sqlite__bindf(stmt, "siiii", svn_checksum_to_cstring(&checksum, pool), (apr_int64_t) rep->revision, (apr_int64_t) rep->item_index, (apr_int64_t) rep->size, (apr_int64_t) rep->expanded_size)); err = svn_sqlite__insert(NULL, stmt); if (err) { representation_t *old_rep; if (err->apr_err != SVN_ERR_SQLITE_CONSTRAINT) return svn_error_trace(err); svn_error_clear(err); /* Constraint failed so the mapping for SHA1_CHECKSUM->REP should exist. If so that's cool -- just do nothing. If not, that's a red flag! */ SVN_ERR(svn_fs_fs__get_rep_reference(&old_rep, fs, &checksum, pool)); if (!old_rep) { /* Something really odd at this point, we failed to insert the checksum AND failed to read an existing checksum. Do we need to flag this? */ } } return SVN_NO_ERROR; }
svn_error_t * svn_fs_fs__set_rep_reference(svn_fs_t *fs, representation_t *rep, svn_boolean_t reject_dup, apr_pool_t *pool) { fs_fs_data_t *ffd = fs->fsap_data; svn_sqlite__stmt_t *stmt; svn_error_t *err; SVN_ERR_ASSERT(ffd->rep_sharing_allowed); if (! ffd->rep_cache_db) SVN_ERR(svn_fs_fs__open_rep_cache(fs, pool)); /* We only allow SHA1 checksums in this table. */ if (rep->sha1_checksum == NULL) return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, _("Only SHA1 checksums can be used as keys in the " "rep_cache table.\n")); SVN_ERR(svn_sqlite__get_statement(&stmt, ffd->rep_cache_db, STMT_SET_REP)); SVN_ERR(svn_sqlite__bindf(stmt, "siiii", svn_checksum_to_cstring(rep->sha1_checksum, pool), (apr_int64_t) rep->revision, (apr_int64_t) rep->offset, (apr_int64_t) rep->size, (apr_int64_t) rep->expanded_size)); err = svn_sqlite__insert(NULL, stmt); if (err) { representation_t *old_rep; if (err->apr_err != SVN_ERR_SQLITE_CONSTRAINT) return svn_error_trace(err); svn_error_clear(err); /* Constraint failed so the mapping for SHA1_CHECKSUM->REP should exist. If so, and the value is the same one we were about to write, that's cool -- just do nothing. If, however, the value is *different*, that's a red flag! */ SVN_ERR(svn_fs_fs__get_rep_reference(&old_rep, fs, rep->sha1_checksum, pool)); if (old_rep) { if (reject_dup && ((old_rep->revision != rep->revision) || (old_rep->offset != rep->offset) || (old_rep->size != rep->size) || (old_rep->expanded_size != rep->expanded_size))) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, apr_psprintf(pool, _("Representation key for checksum '%%s' exists " "in filesystem '%%s' with a different value " "(%%ld,%%%s,%%%s,%%%s) than what we were about " "to store (%%ld,%%%s,%%%s,%%%s)"), APR_OFF_T_FMT, SVN_FILESIZE_T_FMT, SVN_FILESIZE_T_FMT, APR_OFF_T_FMT, SVN_FILESIZE_T_FMT, SVN_FILESIZE_T_FMT), svn_checksum_to_cstring_display(rep->sha1_checksum, pool), fs->path, old_rep->revision, old_rep->offset, old_rep->size, old_rep->expanded_size, rep->revision, rep->offset, rep->size, rep->expanded_size); else return SVN_NO_ERROR; } else { /* Something really odd at this point, we failed to insert the checksum AND failed to read an existing checksum. Do we need to flag this? */ } } return SVN_NO_ERROR; }
/* Install the pristine text described by BATON into the pristine store of * SDB. If it is already stored then just delete the new file * BATON->tempfile_abspath. * * This function expects to be executed inside a SQLite txn that has already * acquired a 'RESERVED' lock. * * Implements 'notes/wc-ng/pristine-store' section A-3(a). */ static svn_error_t * pristine_install_txn(svn_sqlite__db_t *sdb, /* The path to the source file that is to be moved into place. */ svn_stream_t *install_stream, /* The target path for the file (within the pristine store). */ const char *pristine_abspath, /* The pristine text's SHA-1 checksum. */ const svn_checksum_t *sha1_checksum, /* The pristine text's MD-5 checksum. */ const svn_checksum_t *md5_checksum, apr_pool_t *scratch_pool) { svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; /* If this pristine text is already present in the store, just keep it: * delete the new one and return. */ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_PRISTINE)); SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); SVN_ERR(svn_sqlite__reset(stmt)); if (have_row) { #ifdef SVN_DEBUG /* Consistency checks. Verify both files exist and match. * ### We could check much more. */ { apr_finfo_t finfo1, finfo2; SVN_ERR(svn_stream__install_get_info(&finfo1, install_stream, APR_FINFO_SIZE, scratch_pool)); SVN_ERR(svn_io_stat(&finfo2, pristine_abspath, APR_FINFO_SIZE, scratch_pool)); if (finfo1.size != finfo2.size) { return svn_error_createf( SVN_ERR_WC_CORRUPT_TEXT_BASE, NULL, _("New pristine text '%s' has different size: %s versus %s"), svn_checksum_to_cstring_display(sha1_checksum, scratch_pool), apr_off_t_toa(scratch_pool, finfo1.size), apr_off_t_toa(scratch_pool, finfo2.size)); } } #endif /* Remove the temp file: it's already there */ SVN_ERR(svn_stream__install_delete(install_stream, scratch_pool)); return SVN_NO_ERROR; } /* Move the file to its target location. (If it is already there, it is * an orphan file and it doesn't matter if we overwrite it.) */ { apr_finfo_t finfo; SVN_ERR(svn_stream__install_get_info(&finfo, install_stream, APR_FINFO_SIZE, scratch_pool)); SVN_ERR(svn_stream__install_stream(install_stream, pristine_abspath, TRUE, scratch_pool)); SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_PRISTINE)); SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, scratch_pool)); SVN_ERR(svn_sqlite__bind_int64(stmt, 3, finfo.size)); SVN_ERR(svn_sqlite__insert(NULL, stmt)); SVN_ERR(svn_io_set_file_read_only(pristine_abspath, FALSE, scratch_pool)); } return SVN_NO_ERROR; }