static svn_error_t * test_checksum_parse(apr_pool_t *pool) { const char *md5_digest = "8518b76f7a45fe4de2d0955085b41f98"; const char *sha1_digest = "74d82379bcc6771454377db03b912c2b62704139"; const char *checksum_display; svn_checksum_t *checksum; SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_md5, md5_digest, pool)); checksum_display = svn_checksum_to_cstring_display(checksum, pool); if (strcmp(checksum_display, md5_digest) != 0) return svn_error_createf (SVN_ERR_CHECKSUM_MISMATCH, NULL, "verify-checksum: md5 checksum mismatch:\n" " expected: %s\n" " actual: %s\n", md5_digest, checksum_display); SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_sha1, sha1_digest, pool)); checksum_display = svn_checksum_to_cstring_display(checksum, pool); if (strcmp(checksum_display, sha1_digest) != 0) return svn_error_createf (SVN_ERR_CHECKSUM_MISMATCH, NULL, "verify-checksum: sha1 checksum mismatch:\n" " expected: %s\n" " actual: %s\n", sha1_digest, checksum_display); return SVN_NO_ERROR; }
svn_error_t * svn_fs_fs__parse_footer(apr_off_t *l2p_offset, svn_checksum_t **l2p_checksum, apr_off_t *p2l_offset, svn_checksum_t **p2l_checksum, svn_stringbuf_t *footer, svn_revnum_t rev, apr_pool_t *result_pool) { apr_int64_t val; char *last_str = footer->data; /* Get the L2P offset. */ const char *str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid revision footer")); SVN_ERR(svn_cstring_atoi64(&val, str)); *l2p_offset = (apr_off_t)val; /* Get the L2P checksum. */ str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid revision footer")); SVN_ERR(svn_checksum_parse_hex(l2p_checksum, svn_checksum_md5, str, result_pool)); /* Get the P2L offset. */ str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid revision footer")); SVN_ERR(svn_cstring_atoi64(&val, str)); *p2l_offset = (apr_off_t)val; /* Get the P2L checksum. */ str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid revision footer")); SVN_ERR(svn_checksum_parse_hex(p2l_checksum, svn_checksum_md5, str, result_pool)); return SVN_NO_ERROR; }
static svn_error_t * close_file(void *file_baton, const char *text_digest, apr_pool_t *pool) { struct file_baton *fb = file_baton; if (text_digest) { svn_checksum_t *checksum; svn_checksum_t *text_checksum; SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5, fb->edit_baton->txn_root, fb->path, TRUE, pool)); SVN_ERR(svn_checksum_parse_hex(&text_checksum, svn_checksum_md5, text_digest, pool)); if (!svn_checksum_match(text_checksum, checksum)) return svn_checksum_mismatch_err(text_checksum, checksum, pool, _("Checksum mismatch for resulting fulltext\n(%s)"), fb->path); } return SVN_NO_ERROR; }
svn_error_t * svn_fs_apply_textdelta(svn_txdelta_window_handler_t *contents_p, void **contents_baton_p, svn_fs_root_t *root, const char *path, const char *base_checksum, const char *result_checksum, apr_pool_t *pool) { svn_checksum_t *base, *result; /* TODO: If we ever rev this API, we should make the supplied checksums svn_checksum_t structs. */ SVN_ERR(svn_checksum_parse_hex(&base, svn_checksum_md5, base_checksum, pool)); SVN_ERR(svn_checksum_parse_hex(&result, svn_checksum_md5, result_checksum, pool)); return svn_error_trace(root->vtable->apply_textdelta(contents_p, contents_baton_p, root, path, base, result, pool)); }
svn_error_t * svn_fs_apply_text(svn_stream_t **contents_p, svn_fs_root_t *root, const char *path, const char *result_checksum, apr_pool_t *pool) { svn_checksum_t *result; /* TODO: If we ever rev this API, we should make the supplied checksum an svn_checksum_t struct. */ SVN_ERR(svn_checksum_parse_hex(&result, svn_checksum_md5, result_checksum, pool)); return svn_error_trace(root->vtable->apply_text(contents_p, root, path, result, pool)); }
svn_error_t * svn_checksum_deserialize(const svn_checksum_t **checksum, const char *data, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_checksum_kind_t ckind; svn_checksum_t *parsed_checksum; /* "$md5 $..." or "$sha1$..." */ SVN_ERR_ASSERT(strlen(data) > 6); ckind = (data[1] == 'm' ? svn_checksum_md5 : svn_checksum_sha1); SVN_ERR(svn_checksum_parse_hex(&parsed_checksum, ckind, data + 6, result_pool)); *checksum = parsed_checksum; return SVN_NO_ERROR; }
static svn_error_t * file_close(void *file_baton, const char *text_checksum, apr_pool_t *scratch_pool) { struct file_baton_t *fb = file_baton; struct edit_baton_t *eb = fb->eb; struct dir_baton_t *pb = fb->pb; SVN_ERR(ensure_added(pb, fb->pool)); if (text_checksum) { svn_checksum_t *expected_checksum; svn_checksum_t *actual_checksum; SVN_ERR(svn_checksum_parse_hex(&expected_checksum, svn_checksum_md5, text_checksum, fb->pool)); actual_checksum = svn_checksum__from_digest_md5(fb->digest, fb->pool); if (! svn_checksum_match(expected_checksum, actual_checksum)) return svn_error_trace( svn_checksum_mismatch_err(expected_checksum, actual_checksum, fb->pool, _("Checksum mismatch for '%s'"), svn_dirent_local_style( fb->local_abspath, fb->pool))); } SVN_ERR(svn_wc_add_from_disk3(eb->wc_ctx, fb->local_abspath, fb->properties, TRUE /* skip checks */, eb->notify_func, eb->notify_baton, fb->pool)); svn_pool_destroy(fb->pool); SVN_ERR(maybe_done(pb)); return SVN_NO_ERROR; }
static svn_error_t * file_close(void *file_baton, const char *text_checksum, apr_pool_t *scratch_pool) { struct file_baton_t *fb = file_baton; struct dir_baton_t *pb = fb->pb; if (fb->writing_file) SVN_ERR(svn_io_file_rename2(fb->writing_file, fb->local_abspath, FALSE /*flush*/, scratch_pool)); if (text_checksum) { svn_checksum_t *expected_checksum; svn_checksum_t *actual_checksum; SVN_ERR(svn_checksum_parse_hex(&expected_checksum, svn_checksum_md5, text_checksum, fb->pool)); actual_checksum = svn_checksum__from_digest_md5(fb->digest, fb->pool); if (! svn_checksum_match(expected_checksum, actual_checksum)) return svn_error_trace( svn_checksum_mismatch_err(expected_checksum, actual_checksum, fb->pool, _("Checksum mismatch for '%s'"), svn_dirent_local_style( fb->local_abspath, fb->pool))); } SVN_ERR(ensure_added_file(fb, fb->pool)); svn_pool_destroy(fb->pool); SVN_ERR(maybe_done(pb)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_fs__parse_representation(representation_t **rep_p, svn_stringbuf_t *text, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { representation_t *rep; char *str; apr_int64_t val; char *string = text->data; svn_checksum_t *checksum; const char *end; rep = apr_pcalloc(result_pool, sizeof(*rep)); *rep_p = rep; SVN_ERR(parse_revnum(&rep->revision, (const char **)&string)); /* initialize transaction info (never stored) */ svn_fs_fs__id_txn_reset(&rep->txn_id); /* while in transactions, it is legal to simply write "-1" */ str = svn_cstring_tokenize(" ", &string); if (str == NULL) { if (rep->revision == SVN_INVALID_REVNUM) return SVN_NO_ERROR; return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); } SVN_ERR(svn_cstring_atoi64(&val, str)); rep->item_index = (apr_uint64_t)val; str = svn_cstring_tokenize(" ", &string); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); SVN_ERR(svn_cstring_atoi64(&val, str)); rep->size = (svn_filesize_t)val; str = svn_cstring_tokenize(" ", &string); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); SVN_ERR(svn_cstring_atoi64(&val, str)); rep->expanded_size = (svn_filesize_t)val; /* Read in the MD5 hash. */ str = svn_cstring_tokenize(" ", &string); if ((str == NULL) || (strlen(str) != (APR_MD5_DIGESTSIZE * 2))) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_md5, str, scratch_pool)); memcpy(rep->md5_digest, checksum->digest, sizeof(rep->md5_digest)); /* The remaining fields are only used for formats >= 4, so check that. */ str = svn_cstring_tokenize(" ", &string); if (str == NULL) return SVN_NO_ERROR; /* Read the SHA1 hash. */ if (strlen(str) != (APR_SHA1_DIGESTSIZE * 2)) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_sha1, str, scratch_pool)); rep->has_sha1 = checksum != NULL; memcpy(rep->sha1_digest, checksum->digest, sizeof(rep->sha1_digest)); /* Read the uniquifier. */ str = svn_cstring_tokenize("/", &string); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); SVN_ERR(svn_fs_fs__id_txn_parse(&rep->uniquifier.noderev_txn_id, str)); str = svn_cstring_tokenize(" ", &string); if (str == NULL || *str != '_') return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); ++str; rep->uniquifier.number = svn__base36toui64(&end, str); if (*end) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); return SVN_NO_ERROR; }
svn_error_t * svn_fs_fs__walk_rep_reference(svn_fs_t *fs, svn_error_t *(*walker)(representation_t *, void *, svn_fs_t *, apr_pool_t *), void *walker_baton, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) { fs_fs_data_t *ffd = fs->fsap_data; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; int iterations = 0; apr_pool_t *iterpool = svn_pool_create(pool); /* Don't check ffd->rep_sharing_allowed. */ SVN_ERR_ASSERT(ffd->format >= SVN_FS_FS__MIN_REP_SHARING_FORMAT); if (! ffd->rep_cache_db) SVN_ERR(svn_fs_fs__open_rep_cache(fs, pool)); /* Get the statement. (There are no arguments to bind.) */ SVN_ERR(svn_sqlite__get_statement(&stmt, ffd->rep_cache_db, STMT_GET_ALL_REPS)); /* Walk the cache entries. */ SVN_ERR(svn_sqlite__step(&have_row, stmt)); while (have_row) { representation_t *rep; const char *sha1_digest; /* Clear ITERPOOL occasionally. */ if (iterations++ % 16 == 0) svn_pool_clear(iterpool); /* Check for cancellation. */ if (cancel_func) SVN_ERR(cancel_func(cancel_baton)); /* Construct a representation_t. */ rep = apr_pcalloc(iterpool, sizeof(*rep)); sha1_digest = svn_sqlite__column_text(stmt, 0, iterpool); SVN_ERR(svn_checksum_parse_hex(&rep->sha1_checksum, svn_checksum_sha1, sha1_digest, iterpool)); rep->revision = svn_sqlite__column_revnum(stmt, 1); rep->offset = svn_sqlite__column_int64(stmt, 2); rep->size = svn_sqlite__column_int64(stmt, 3); rep->expanded_size = svn_sqlite__column_int64(stmt, 4); /* Sanity check. */ if (rep) SVN_ERR(rep_has_been_born(rep, fs, iterpool)); /* Walk. */ SVN_ERR(walker(rep, walker_baton, fs, iterpool)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); } SVN_ERR(svn_sqlite__reset(stmt)); svn_pool_destroy(iterpool); return SVN_NO_ERROR; }
/* Make a node baton, parsing the relevant HEADERS. * * If RB->pb->parent_dir: * prefix it to NB->path * prefix it to NB->copyfrom_path (if present) */ static svn_error_t * make_node_baton(struct node_baton **node_baton_p, apr_hash_t *headers, struct revision_baton *rb, apr_pool_t *pool) { struct node_baton *nb = apr_pcalloc(pool, sizeof(*nb)); const char *val; /* Start with sensible defaults. */ nb->rb = rb; nb->pool = pool; nb->kind = svn_node_unknown; /* Then add info from the headers. */ if ((val = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_PATH))) { val = svn_relpath_canonicalize(val, pool); if (rb->pb->parent_dir) nb->path = svn_relpath_join(rb->pb->parent_dir, val, pool); else nb->path = val; } if ((val = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_KIND))) { if (! strcmp(val, "file")) nb->kind = svn_node_file; else if (! strcmp(val, "dir")) nb->kind = svn_node_dir; } nb->action = (enum svn_node_action)(-1); /* an invalid action code */ if ((val = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_ACTION))) { if (! strcmp(val, "change")) nb->action = svn_node_action_change; else if (! strcmp(val, "add")) nb->action = svn_node_action_add; else if (! strcmp(val, "delete")) nb->action = svn_node_action_delete; else if (! strcmp(val, "replace")) nb->action = svn_node_action_replace; } nb->copyfrom_rev = SVN_INVALID_REVNUM; if ((val = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV))) { nb->copyfrom_rev = SVN_STR_TO_REV(val); } if ((val = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH))) { val = svn_relpath_canonicalize(val, pool); if (rb->pb->parent_dir) nb->copyfrom_path = svn_relpath_join(rb->pb->parent_dir, val, pool); else nb->copyfrom_path = val; } if ((val = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_TEXT_CONTENT_CHECKSUM))) { SVN_ERR(svn_checksum_parse_hex(&nb->result_checksum, svn_checksum_md5, val, pool)); } if ((val = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_CHECKSUM))) { SVN_ERR(svn_checksum_parse_hex(&nb->base_checksum, svn_checksum_md5, val, pool)); } if ((val = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_CHECKSUM))) { SVN_ERR(svn_checksum_parse_hex(&nb->copy_source_checksum, svn_checksum_md5, val, pool)); } /* What's cool about this dump format is that the parser just ignores any unrecognized headers. :-) */ *node_baton_p = nb; return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__parse_representation(svn_fs_x__representation_t **rep_p, svn_stringbuf_t *text, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_fs_x__representation_t *rep; char *str; apr_int64_t val; char *string = text->data; svn_checksum_t *checksum; rep = apr_pcalloc(result_pool, sizeof(*rep)); *rep_p = rep; str = svn_cstring_tokenize(" ", &string); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); SVN_ERR(svn_cstring_atoi64(&rep->id.change_set, str)); /* while in transactions, it is legal to simply write "-1" */ if (rep->id.change_set == -1) return SVN_NO_ERROR; str = svn_cstring_tokenize(" ", &string); if (str == NULL) { if (rep->id.change_set == SVN_FS_X__INVALID_CHANGE_SET) return SVN_NO_ERROR; return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); } SVN_ERR(svn_cstring_atoi64(&val, str)); rep->id.number = (apr_off_t)val; str = svn_cstring_tokenize(" ", &string); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); SVN_ERR(svn_cstring_atoi64(&val, str)); rep->size = (svn_filesize_t)val; str = svn_cstring_tokenize(" ", &string); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); SVN_ERR(svn_cstring_atoi64(&val, str)); rep->expanded_size = (svn_filesize_t)val; /* Read in the MD5 hash. */ str = svn_cstring_tokenize(" ", &string); if ((str == NULL) || (strlen(str) != (APR_MD5_DIGESTSIZE * 2))) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_md5, str, scratch_pool)); if (checksum) memcpy(rep->md5_digest, checksum->digest, sizeof(rep->md5_digest)); /* The remaining fields are only used for formats >= 4, so check that. */ str = svn_cstring_tokenize(" ", &string); if (str == NULL) return SVN_NO_ERROR; /* Read the SHA1 hash. */ if (strlen(str) != (APR_SHA1_DIGESTSIZE * 2)) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_sha1, str, scratch_pool)); rep->has_sha1 = checksum != NULL; if (checksum) memcpy(rep->sha1_digest, checksum->digest, sizeof(rep->sha1_digest)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__parse_footer(apr_off_t *l2p_offset, svn_checksum_t **l2p_checksum, apr_off_t *p2l_offset, svn_checksum_t **p2l_checksum, svn_stringbuf_t *footer, svn_revnum_t rev, apr_off_t footer_offset, apr_pool_t *result_pool) { apr_int64_t val; char *last_str = footer->data; /* Get the L2P offset. */ const char *str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, "Invalid r%ld footer", rev); SVN_ERR(wrap_footer_error(svn_cstring_strtoi64(&val, str, 0, footer_offset - 1, 10), "Invalid L2P offset in r%ld footer", rev)); *l2p_offset = (apr_off_t)val; /* Get the L2P checksum. */ str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, "Invalid r%ld footer", rev); SVN_ERR(svn_checksum_parse_hex(l2p_checksum, svn_checksum_md5, str, result_pool)); /* Get the P2L offset. */ str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, "Invalid r%ld footer", rev); SVN_ERR(wrap_footer_error(svn_cstring_strtoi64(&val, str, 0, footer_offset - 1, 10), "Invalid P2L offset in r%ld footer", rev)); *p2l_offset = (apr_off_t)val; /* The P2L indes follows the L2P index */ if (*p2l_offset <= *l2p_offset) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, "P2L offset %s must be larger than L2P offset %s" " in r%ld footer", apr_psprintf(result_pool, "%" APR_UINT64_T_HEX_FMT, (apr_uint64_t)*p2l_offset), apr_psprintf(result_pool, "%" APR_UINT64_T_HEX_FMT, (apr_uint64_t)*l2p_offset), rev); /* Get the P2L checksum. */ str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, "Invalid r%ld footer", rev); SVN_ERR(svn_checksum_parse_hex(p2l_checksum, svn_checksum_md5, str, result_pool)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_fs__walk_rep_reference(svn_fs_t *fs, svn_revnum_t start, svn_revnum_t end, svn_error_t *(*walker)(representation_t *, void *, svn_fs_t *, apr_pool_t *), void *walker_baton, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) { fs_fs_data_t *ffd = fs->fsap_data; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; int iterations = 0; apr_pool_t *iterpool = svn_pool_create(pool); /* Don't check ffd->rep_sharing_allowed. */ SVN_ERR_ASSERT(ffd->format >= SVN_FS_FS__MIN_REP_SHARING_FORMAT); if (! ffd->rep_cache_db) SVN_ERR(svn_fs_fs__open_rep_cache(fs, pool)); /* Check global invariants. */ if (start == 0) { svn_revnum_t max; SVN_ERR(svn_sqlite__get_statement(&stmt, ffd->rep_cache_db, STMT_GET_MAX_REV)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); max = svn_sqlite__column_revnum(stmt, 0); SVN_ERR(svn_sqlite__reset(stmt)); if (SVN_IS_VALID_REVNUM(max)) /* The rep-cache could be empty. */ SVN_ERR(svn_fs_fs__ensure_revision_exists(max, fs, iterpool)); } SVN_ERR(svn_sqlite__get_statement(&stmt, ffd->rep_cache_db, STMT_GET_REPS_FOR_RANGE)); SVN_ERR(svn_sqlite__bindf(stmt, "rr", start, end)); /* Walk the cache entries. */ SVN_ERR(svn_sqlite__step(&have_row, stmt)); while (have_row) { representation_t *rep; const char *sha1_digest; svn_error_t *err; svn_checksum_t *checksum; /* Clear ITERPOOL occasionally. */ if (iterations++ % 16 == 0) svn_pool_clear(iterpool); /* Check for cancellation. */ if (cancel_func) { err = cancel_func(cancel_baton); if (err) return svn_error_compose_create(err, svn_sqlite__reset(stmt)); } /* Construct a representation_t. */ rep = apr_pcalloc(iterpool, sizeof(*rep)); svn_fs_fs__id_txn_reset(&rep->txn_id); sha1_digest = svn_sqlite__column_text(stmt, 0, iterpool); err = svn_checksum_parse_hex(&checksum, svn_checksum_sha1, sha1_digest, iterpool); if (err) return svn_error_compose_create(err, svn_sqlite__reset(stmt)); rep->has_sha1 = TRUE; memcpy(rep->sha1_digest, checksum->digest, sizeof(rep->sha1_digest)); rep->revision = svn_sqlite__column_revnum(stmt, 1); rep->item_index = svn_sqlite__column_int64(stmt, 2); rep->size = svn_sqlite__column_int64(stmt, 3); rep->expanded_size = svn_sqlite__column_int64(stmt, 4); /* Walk. */ err = walker(rep, walker_baton, fs, iterpool); if (err) return svn_error_compose_create(err, svn_sqlite__reset(stmt)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); } SVN_ERR(svn_sqlite__reset(stmt)); svn_pool_destroy(iterpool); return SVN_NO_ERROR; }
/* An svn_delta_editor_t function. When the file is closed we have a temporary * file containing a pristine version of the repository file. This can * be compared against the working copy. * * ### Ignore TEXT_CHECKSUM for now. Someday we can use it to verify * ### the integrity of the file being diffed. Done efficiently, this * ### would probably involve calculating the checksum as the data is * ### received, storing the final checksum in the file_baton, and * ### comparing against it here. */ static svn_error_t * close_file(void *file_baton, const char *expected_md5_digest, apr_pool_t *pool) { struct file_baton *b = file_baton; struct edit_baton *eb = b->edit_baton; svn_wc_notify_state_t content_state = svn_wc_notify_state_unknown; svn_wc_notify_state_t prop_state = svn_wc_notify_state_unknown; apr_pool_t *scratch_pool; /* Skip *everything* within a newly tree-conflicted directory. */ if (b->skip) { svn_pool_destroy(b->pool); return SVN_NO_ERROR; } scratch_pool = b->pool; if (expected_md5_digest && eb->text_deltas) { svn_checksum_t *expected_md5_checksum; SVN_ERR(svn_checksum_parse_hex(&expected_md5_checksum, svn_checksum_md5, expected_md5_digest, scratch_pool)); if (!svn_checksum_match(expected_md5_checksum, b->result_md5_checksum)) return svn_error_trace(svn_checksum_mismatch_err( expected_md5_checksum, b->result_md5_checksum, pool, _("Checksum mismatch for '%s'"), b->path)); } if (!b->added && b->propchanges->nelts > 0) { if (!b->pristine_props) { /* We didn't receive a text change, so we have no pristine props. Retrieve just the props now. */ SVN_ERR(get_file_from_ra(b, TRUE, scratch_pool)); } remove_non_prop_changes(b->pristine_props, b->propchanges); } if (b->path_end_revision || b->propchanges->nelts > 0) { const char *mimetype1, *mimetype2; get_file_mime_types(&mimetype1, &mimetype2, b); if (b->added) SVN_ERR(eb->diff_callbacks->file_added( &content_state, &prop_state, &b->tree_conflicted, b->path, b->path_end_revision ? b->path_start_revision : NULL, b->path_end_revision, 0, b->edit_baton->target_revision, mimetype1, mimetype2, NULL, SVN_INVALID_REVNUM, b->propchanges, b->pristine_props, b->edit_baton->diff_cmd_baton, scratch_pool)); else SVN_ERR(eb->diff_callbacks->file_changed( &content_state, &prop_state, &b->tree_conflicted, b->path, b->path_end_revision ? b->path_start_revision : NULL, b->path_end_revision, b->edit_baton->revision, b->edit_baton->target_revision, mimetype1, mimetype2, b->propchanges, b->pristine_props, b->edit_baton->diff_cmd_baton, scratch_pool)); } if (eb->notify_func) { deleted_path_notify_t *dpn; svn_wc_notify_t *notify; svn_wc_notify_action_t action; svn_node_kind_t kind = svn_node_file; /* Find out if a pending delete notification for this path is * still around. */ dpn = apr_hash_get(eb->deleted_paths, b->path, APR_HASH_KEY_STRING); if (dpn) { /* If any was found, we will handle the pending 'deleted path * notification' (DPN) here. Remove it from the list. */ apr_hash_set(eb->deleted_paths, b->path, APR_HASH_KEY_STRING, NULL); /* the pending delete might be on a different node kind. */ kind = dpn->kind; content_state = prop_state = dpn->state; } /* Determine what the notification (ACTION) should be. * In case of a pending 'delete', this might become a 'replace'. */ if (b->tree_conflicted) action = svn_wc_notify_tree_conflict; else if (dpn) { if (dpn->action == svn_wc_notify_update_delete && b->added) action = svn_wc_notify_update_replace; else /* Note: dpn->action might be svn_wc_notify_tree_conflict */ action = dpn->action; } else if ((content_state == svn_wc_notify_state_missing) || (content_state == svn_wc_notify_state_obstructed)) action = svn_wc_notify_skip; else if (b->added) action = svn_wc_notify_update_add; else action = svn_wc_notify_update_update; notify = svn_wc_create_notify(b->path, action, scratch_pool); notify->kind = kind; notify->content_state = content_state; notify->prop_state = prop_state; (*eb->notify_func)(eb->notify_baton, notify, scratch_pool); } svn_pool_destroy(b->pool); /* Destroy file and scratch pool */ return SVN_NO_ERROR; }
/* An svn_delta_editor_t function. */ static svn_error_t * apply_textdelta(void *file_baton, const char *base_md5_digest, apr_pool_t *pool, svn_txdelta_window_handler_t *handler, void **handler_baton) { struct file_baton *b = file_baton; svn_stream_t *src_stream; svn_stream_t *result_stream; apr_pool_t *scratch_pool = b->pool; /* Skip *everything* within a newly tree-conflicted directory. */ if (b->skip) { *handler = svn_delta_noop_window_handler; *handler_baton = NULL; return SVN_NO_ERROR; } /* If we're not sending file text, then ignore any that we receive. */ if (! b->edit_baton->text_deltas) { /* Supply valid paths to indicate there is a text change. */ SVN_ERR(get_empty_file(b->edit_baton, &b->path_start_revision)); SVN_ERR(get_empty_file(b->edit_baton, &b->path_end_revision)); *handler = svn_delta_noop_window_handler; *handler_baton = NULL; return SVN_NO_ERROR; } /* We need the expected pristine file, so go get it */ if (!b->added) SVN_ERR(get_file_from_ra(b, FALSE, scratch_pool)); else SVN_ERR(get_empty_file(b->edit_baton, &(b->path_start_revision))); SVN_ERR_ASSERT(b->path_start_revision != NULL); if (base_md5_digest != NULL) { svn_checksum_t *base_md5_checksum; SVN_ERR(svn_checksum_parse_hex(&base_md5_checksum, svn_checksum_md5, base_md5_digest, scratch_pool)); if (!svn_checksum_match(base_md5_checksum, b->start_md5_checksum)) return svn_error_trace(svn_checksum_mismatch_err( base_md5_checksum, b->start_md5_checksum, scratch_pool, _("Base checksum mismatch for '%s'"), b->path)); } /* Open the file to be used as the base for second revision */ SVN_ERR(svn_stream_open_readonly(&src_stream, b->path_start_revision, scratch_pool, scratch_pool)); /* Open the file that will become the second revision after applying the text delta, it starts empty */ SVN_ERR(svn_stream_open_unique(&result_stream, &b->path_end_revision, NULL, svn_io_file_del_on_pool_cleanup, scratch_pool, scratch_pool)); svn_txdelta_apply(src_stream, result_stream, b->result_digest, b->path, b->pool, &(b->apply_handler), &(b->apply_baton)); *handler = window_handler; *handler_baton = file_baton; return SVN_NO_ERROR; }