svn_error_t * svn_wc__get_pristine_contents(svn_stream_t **contents, svn_filesize_t *size, svn_wc__db_t *db, const char *local_abspath, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_wc__db_status_t status; svn_wc__db_kind_t kind; const svn_checksum_t *sha1_checksum; if (size) *size = SVN_INVALID_FILESIZE; SVN_ERR(svn_wc__db_read_pristine_info(&status, &kind, NULL, NULL, NULL, NULL, &sha1_checksum, NULL, NULL, db, local_abspath, scratch_pool, scratch_pool)); /* Sanity */ if (kind != svn_wc__db_kind_file) return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL, _("Can only get the pristine contents of files; " "'%s' is not a file"), svn_dirent_local_style(local_abspath, scratch_pool)); if (status == svn_wc__db_status_added && !sha1_checksum) { /* Simply added. The pristine base does not exist. */ *contents = NULL; return SVN_NO_ERROR; } else if (status == svn_wc__db_status_not_present) /* We know that the delete of this node has been committed. This should be the same as if called on an unknown path. */ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, _("Cannot get the pristine contents of '%s' " "because its delete is already committed"), svn_dirent_local_style(local_abspath, scratch_pool)); else if (status == svn_wc__db_status_server_excluded || status == svn_wc__db_status_excluded || status == svn_wc__db_status_incomplete) return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, _("Cannot get the pristine contents of '%s' " "because it has an unexpected status"), svn_dirent_local_style(local_abspath, scratch_pool)); if (sha1_checksum) SVN_ERR(svn_wc__db_pristine_read(contents, size, db, local_abspath, sha1_checksum, result_pool, scratch_pool)); else *contents = NULL; return SVN_NO_ERROR; }
/* Exercise the pristine text API with a simple write and read. */ static svn_error_t * pristine_write_read(const svn_test_opts_t *opts, apr_pool_t *pool) { svn_wc__db_t *db; const char *wc_abspath; svn_wc__db_install_data_t *install_data; svn_stream_t *pristine_stream; apr_size_t sz; const char data[] = "Blah"; svn_string_t *data_string = svn_string_create(data, pool); svn_checksum_t *data_sha1, *data_md5; SVN_ERR(create_repos_and_wc(&wc_abspath, &db, "pristine_write_read", opts, pool)); /* Write DATA into a new temporary pristine file, set PRISTINE_TMP_ABSPATH * to its path and set DATA_SHA1 and DATA_MD5 to its checksums. */ SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream, &install_data, &data_sha1, &data_md5, db, wc_abspath, pool, pool)); sz = strlen(data); SVN_ERR(svn_stream_write(pristine_stream, data, &sz)); SVN_ERR(svn_stream_close(pristine_stream)); /* Ensure it's not already in the store. */ { svn_boolean_t present; SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1, pool)); SVN_TEST_ASSERT(! present); } /* Install the new pristine file, referenced by its checksum. */ SVN_ERR(svn_wc__db_pristine_install(install_data, data_sha1, data_md5, pool)); /* Ensure it is now found in the store. */ { svn_boolean_t present; SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1, pool)); SVN_TEST_ASSERT(present); } /* Look up its MD-5 from its SHA-1, and check it's the same MD-5. */ { const svn_checksum_t *looked_up_md5; SVN_ERR(svn_wc__db_pristine_get_md5(&looked_up_md5, db, wc_abspath, data_sha1, pool, pool)); SVN_TEST_ASSERT(looked_up_md5->kind == svn_checksum_md5); SVN_TEST_ASSERT(svn_checksum_match(data_md5, looked_up_md5)); } /* Read the pristine text back and verify it's the same content. */ { svn_stream_t *data_stream = svn_stream_from_string(data_string, pool); svn_stream_t *data_read_back; svn_boolean_t same; SVN_ERR(svn_wc__db_pristine_read(&data_read_back, NULL, db, wc_abspath, data_sha1, pool, pool)); SVN_ERR(svn_stream_contents_same2(&same, data_read_back, data_stream, pool)); SVN_TEST_ASSERT(same); } /* Trivially test the "remove if unreferenced" API: it's not referenced so we should be able to remove it. */ { svn_error_t *err; svn_stream_t *data_read_back; SVN_ERR(svn_wc__db_pristine_remove(db, wc_abspath, data_sha1, pool)); err = svn_wc__db_pristine_read(&data_read_back, NULL, db, wc_abspath, data_sha1, pool, pool); SVN_TEST_ASSERT_ERROR(err, SVN_ERR_WC_PATH_NOT_FOUND); } /* Ensure it's no longer found in the store. */ { svn_boolean_t present; SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1, pool)); SVN_TEST_ASSERT(! present); } return SVN_NO_ERROR; }
/* Test deleting a pristine text while it is open for reading. */ static svn_error_t * pristine_delete_while_open(const svn_test_opts_t *opts, apr_pool_t *pool) { svn_wc__db_t *db; const char *wc_abspath; svn_wc__db_install_data_t *install_data; svn_stream_t *pristine_stream; svn_stream_t *contents; apr_size_t sz; const char data[] = "Blah"; svn_checksum_t *data_sha1, *data_md5; SVN_ERR(create_repos_and_wc(&wc_abspath, &db, "pristine_delete_while_open", opts, pool)); SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream, &install_data, &data_sha1, &data_md5, db, wc_abspath, pool, pool)); sz = strlen(data); SVN_ERR(svn_stream_write(pristine_stream, data, &sz)); SVN_ERR(svn_stream_close(pristine_stream)); SVN_ERR(svn_wc__db_pristine_install(install_data, data_sha1, data_md5, pool)); /* Open it for reading */ SVN_ERR(svn_wc__db_pristine_read(&contents, NULL, db, wc_abspath, data_sha1, pool, pool)); /* Delete it */ SVN_ERR(svn_wc__db_pristine_remove(db, wc_abspath, data_sha1, pool)); /* Continue to read from it */ { char buffer[4]; apr_size_t len = 4; SVN_ERR(svn_stream_read_full(contents, buffer, &len)); SVN_TEST_ASSERT(len == 4); SVN_TEST_ASSERT(memcmp(buffer, data, len) == 0); } /* Ensure it's no longer found in the store. (The file may still exist as * an orphan, depending on the implementation.) */ { svn_boolean_t present; SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1, pool)); SVN_TEST_ASSERT(! present); } /* Close the read stream */ SVN_ERR(svn_stream_close(contents)); return SVN_NO_ERROR; }