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_x__dag_finalize_edits(dag_node_t *file, const svn_checksum_t *checksum, apr_pool_t *pool) { if (checksum) { svn_checksum_t *file_checksum; SVN_ERR(svn_fs_x__dag_file_checksum(&file_checksum, file, checksum->kind, pool)); if (!svn_checksum_match(checksum, file_checksum)) return svn_checksum_mismatch_err(checksum, file_checksum, pool, _("Checksum mismatch for '%s'"), file->created_path); } 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; }
/* Perform a copy or a plain add. * * For a copy, also adjust the copy-from rev, check any copy-source checksum, * and send a notification. */ static svn_error_t * maybe_add_with_history(struct node_baton *nb, struct revision_baton *rb, apr_pool_t *pool) { struct parse_baton *pb = rb->pb; if ((nb->copyfrom_path == NULL) || (! pb->use_history)) { /* Add empty file or dir, without history. */ if (nb->kind == svn_node_file) SVN_ERR(svn_fs_make_file(rb->txn_root, nb->path, pool)); else if (nb->kind == svn_node_dir) SVN_ERR(svn_fs_make_dir(rb->txn_root, nb->path, pool)); } else { /* Hunt down the source revision in this fs. */ svn_fs_root_t *copy_root; svn_revnum_t copyfrom_rev; /* Try to find the copyfrom revision in the revision map; failing that, fall back to the revision offset approach. */ copyfrom_rev = get_revision_mapping(rb->pb->rev_map, nb->copyfrom_rev); if (! SVN_IS_VALID_REVNUM(copyfrom_rev)) copyfrom_rev = nb->copyfrom_rev - rb->rev_offset; if (! SVN_IS_VALID_REVNUM(copyfrom_rev)) return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL, _("Relative source revision %ld is not" " available in current repository"), copyfrom_rev); SVN_ERR(svn_fs_revision_root(©_root, pb->fs, copyfrom_rev, pool)); if (nb->copy_source_checksum) { svn_checksum_t *checksum; SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5, copy_root, nb->copyfrom_path, TRUE, pool)); if (!svn_checksum_match(nb->copy_source_checksum, checksum)) return svn_checksum_mismatch_err(nb->copy_source_checksum, checksum, pool, _("Copy source checksum mismatch on copy from '%s'@%ld\n" "to '%s' in rev based on r%ld"), nb->copyfrom_path, copyfrom_rev, nb->path, rb->rev); } SVN_ERR(svn_fs_copy(copy_root, nb->copyfrom_path, rb->txn_root, nb->path, pool)); if (pb->notify_func) { /* ### TODO: Use proper scratch pool instead of pb->notify_pool */ svn_repos_notify_t *notify = svn_repos_notify_create( svn_repos_notify_load_copied_node, pb->notify_pool); pb->notify_func(pb->notify_baton, notify, pb->notify_pool); svn_pool_clear(pb->notify_pool); } } 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; }