static svn_error_t * test_serialization(apr_pool_t *pool) { svn_stringbuf_t *original_content; svn_stringbuf_t *written_content; svn_config_t *cfg; const struct { const char *section; const char *option; const char *value; } test_data[] = { { "my section", "value1", "some" }, { "my section", "value2", "something" }, { "another Section", "value1", "one" }, { "another Section", "value2", "two" }, { "another Section", "value 3", "more" }, }; int i; /* Format the original with the same formatting that the writer will use. */ original_content = svn_stringbuf_create("\n[my section]\n" "value1=some\n" "value2=%(value1)sthing\n" "\n[another Section]\n" "value1=one\n" "value2=two\n" "value 3=more\n", pool); written_content = svn_stringbuf_create_empty(pool); SVN_ERR(svn_config_parse(&cfg, svn_stream_from_stringbuf(original_content, pool), TRUE, TRUE, pool)); SVN_ERR(svn_config__write(svn_stream_from_stringbuf(written_content, pool), cfg, pool)); SVN_ERR(svn_config_parse(&cfg, svn_stream_from_stringbuf(written_content, pool), TRUE, TRUE, pool)); /* The serialized and re-parsed config must have the expected contents. */ for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i) { const char *val; svn_config_get(cfg, &val, test_data[i].section, test_data[i].option, NULL); SVN_TEST_STRING_ASSERT(val, test_data[i].value); } return SVN_NO_ERROR; }
/* * mw_svn_get() * * Return the contents of the head of the file at subversion location * <url>. On failure return NULL. */ char * mw_svn_get(const char *url, void *baton, apr_pool_t *pool) { svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx; svn_stream_t *out; apr_pool_t *subpool = svn_pool_create(pool); svn_stringbuf_t *string; svn_error_t *err = NULL; svn_opt_revision_t rev; char *res; string = svn_stringbuf_create("", pool); out = svn_stream_from_stringbuf(string, pool); /* For now, we always want the HEAD revision, but in future we * may want to support specifying a revision here.*/ rev.kind = svn_opt_revision_head; svn_pool_clear(subpool); err = svn_client_cat(out, url, &rev, ctx, subpool); if (err != NULL) { svn_pool_destroy(subpool); svn_stream_close(out); return (NULL); } res = xstrdup(string->data); svn_pool_destroy(subpool); svn_stream_close(out); return (res); }
static svn_error_t * test_stream_base64(apr_pool_t *pool) { svn_stream_t *stream; svn_stringbuf_t *actual = svn_stringbuf_create_empty(pool); svn_stringbuf_t *expected = svn_stringbuf_create_empty(pool); int i; static const char *strings[] = { "fairly boring test data... blah blah", "A", "abc", "012345679", NULL }; stream = svn_stream_from_stringbuf(actual, pool); stream = svn_base64_decode(stream, pool); stream = svn_base64_encode(stream, pool); for (i = 0; strings[i]; i++) { apr_size_t len = strlen(strings[i]); svn_stringbuf_appendbytes(expected, strings[i], len); SVN_ERR(svn_stream_write(stream, strings[i], &len)); } SVN_ERR(svn_stream_close(stream)); SVN_TEST_STRING_ASSERT(actual->data, expected->data); return SVN_NO_ERROR; }
svn_error_t * svn_fs_fs__dag_serialize(char **data, apr_size_t *data_len, void *in, apr_pool_t *pool) { dag_node_t *node = in; svn_stringbuf_t *buf = svn_stringbuf_create("", pool); if (svn_fs_fs__dag_check_mutable(node)) { svn_stringbuf_appendcstr(buf, "M"); svn_stringbuf_appendcstr(buf, (node->kind == svn_node_file ? "F" : "D")); svn_stringbuf_appendcstr(buf, svn_fs_fs__id_unparse(node->id, pool)->data); svn_stringbuf_appendcstr(buf, "\n"); svn_stringbuf_appendcstr(buf, node->created_path); } else { fs_fs_data_t *ffd = node->fs->fsap_data; svn_stringbuf_appendcstr(buf, "I"); SVN_ERR(svn_fs_fs__write_noderev(svn_stream_from_stringbuf(buf, pool), node->node_revision, ffd->format, TRUE, pool)); } *data = buf->data; *data_len = buf->len; return SVN_NO_ERROR; }
/* Helper for svn_repos_dump_fs. Write a revision record of REV in FS to writable STREAM, using POOL. */ static svn_error_t * write_revision_record(svn_stream_t *stream, svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool) { apr_size_t len; apr_hash_t *props; svn_stringbuf_t *encoded_prophash; apr_time_t timetemp; svn_string_t *datevalue; svn_stream_t *propstream; /* Read the revision props even if we're aren't going to dump them for verification purposes */ SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, pool)); /* Run revision date properties through the time conversion to canonicalize them. */ /* ### Remove this when it is no longer needed for sure. */ datevalue = apr_hash_get(props, SVN_PROP_REVISION_DATE, APR_HASH_KEY_STRING); if (datevalue) { SVN_ERR(svn_time_from_cstring(&timetemp, datevalue->data, pool)); datevalue = svn_string_create(svn_time_to_cstring(timetemp, pool), pool); apr_hash_set(props, SVN_PROP_REVISION_DATE, APR_HASH_KEY_STRING, datevalue); } encoded_prophash = svn_stringbuf_create_ensure(0, pool); propstream = svn_stream_from_stringbuf(encoded_prophash, pool); SVN_ERR(svn_hash_write2(props, propstream, "PROPS-END", pool)); SVN_ERR(svn_stream_close(propstream)); /* ### someday write a revision-content-checksum */ SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_REVISION_NUMBER ": %ld\n", rev)); SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH ": %" APR_SIZE_T_FMT "\n", encoded_prophash->len)); /* Write out a regular Content-length header for the benefit of non-Subversion RFC-822 parsers. */ SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_CONTENT_LENGTH ": %" APR_SIZE_T_FMT "\n\n", encoded_prophash->len)); len = encoded_prophash->len; SVN_ERR(svn_stream_write(stream, encoded_prophash->data, &len)); len = 1; return svn_stream_write(stream, "\n", &len); }
inline Try<std::string> patch(const std::string& s, const Diff& diff) { // Initialize the Apache Portable Runtime subsystem, as necessary // for using the svn library. initialize(); // Note that svn_pool_create wraps apr_pool_create_ex, which is // thread safe, see: http://goo.gl/NX0hps. apr_pool_t* pool = svn_pool_create(NULL); // We want to apply the svndiff format diff to the source trying to // produce a result. First setup a handler for applying a text delta // to the source stream. svn_string_t source; source.data = s.data(); source.len = s.length(); svn_txdelta_window_handler_t handler; void* baton = NULL; svn_stringbuf_t* patched = svn_stringbuf_create_ensure(s.length(), pool); svn_txdelta_apply( svn_stream_from_string(&source, pool), svn_stream_from_stringbuf(patched, pool), NULL, NULL, pool, &handler, &baton); // Setup a stream that converts an svndiff format diff to a text // delta, so that we can use our handler to patch the source string. svn_stream_t* stream = svn_txdelta_parse_svndiff( handler, baton, TRUE, pool); // Now feed the diff into the stream to compute the patched result. const char* data = diff.data.data(); apr_size_t length = diff.data.length(); svn_error_t* error = svn_stream_write(stream, data, &length); if (error != NULL) { char buffer[1024]; std::string message(svn_err_best_message(error, buffer, 1024)); svn_pool_destroy(pool); return Error(message); } std::string result(patched->data, patched->len); svn_pool_destroy(pool); return result; }
static svn_error_t * store_and_load_table(string_table_t **table, apr_pool_t *pool) { svn_stringbuf_t *stream_buffer = svn_stringbuf_create_empty(pool); svn_stream_t *stream; stream = svn_stream_from_stringbuf(stream_buffer, pool); SVN_ERR(svn_fs_x__write_string_table(stream, *table, pool)); SVN_ERR(svn_stream_close(stream)); *table = NULL; stream = svn_stream_from_stringbuf(stream_buffer, pool); SVN_ERR(svn_fs_x__read_string_table(table, stream, pool, pool)); SVN_ERR(svn_stream_close(stream)); return SVN_NO_ERROR; }
static svn_error_t * test_stringbuf_from_stream(apr_pool_t *pool) { const char *test_cases[] = { "", "x", "this string is longer than the default 64 minimum block size used" "by the function under test", NULL }; const char **test_case; for (test_case = test_cases; *test_case; ++test_case) { svn_stringbuf_t *result1, *result2, *result3, *result4; svn_stringbuf_t *original = svn_stringbuf_create(*test_case, pool); svn_stream_t *stream1 = svn_stream_from_stringbuf(original, pool); svn_stream_t *stream2 = svn_stream_from_stringbuf(original, pool); SVN_ERR(svn_stringbuf_from_stream(&result1, stream1, 0, pool)); SVN_ERR(svn_stringbuf_from_stream(&result2, stream1, 0, pool)); SVN_ERR(svn_stringbuf_from_stream(&result3, stream2, original->len, pool)); SVN_ERR(svn_stringbuf_from_stream(&result4, stream2, original->len, pool)); /* C-string contents must match */ SVN_TEST_STRING_ASSERT(result1->data, original->data); SVN_TEST_STRING_ASSERT(result2->data, ""); SVN_TEST_STRING_ASSERT(result3->data, original->data); SVN_TEST_STRING_ASSERT(result4->data, ""); /* assumed length must match */ SVN_TEST_ASSERT(result1->len == original->len); SVN_TEST_ASSERT(result2->len == 0); SVN_TEST_ASSERT(result3->len == original->len); SVN_TEST_ASSERT(result4->len == 0); } return SVN_NO_ERROR; }
static svn_error_t * test_stream_tee(apr_pool_t *pool) { svn_stringbuf_t *test_bytes = generate_test_bytes(100, pool); svn_stringbuf_t *output_buf1 = svn_stringbuf_create_empty(pool); svn_stringbuf_t *output_buf2 = svn_stringbuf_create_empty(pool); svn_stream_t *source_stream = svn_stream_from_stringbuf(test_bytes, pool); svn_stream_t *output_stream1 = svn_stream_from_stringbuf(output_buf1, pool); svn_stream_t *output_stream2 = svn_stream_from_stringbuf(output_buf2, pool); svn_stream_t *tee_stream; tee_stream = svn_stream_tee(output_stream1, output_stream2, pool); SVN_ERR(svn_stream_copy3(source_stream, tee_stream, NULL, NULL, pool)); if (!svn_stringbuf_compare(output_buf1, output_buf2)) return svn_error_create(SVN_ERR_TEST_FAILED, NULL, "Duplicated streams did not match."); return SVN_NO_ERROR; }
static svn_error_t * test_one_long_keyword(const char *keyword, const char *expected, apr_pool_t *pool) { svn_string_t *src_string; svn_stream_t *src_stream, *dst_stream; svn_stringbuf_t *dst_stringbuf, *src_stringbuf; apr_hash_t *keywords = apr_hash_make(pool); svn_string_t *expanded = svn_string_create("abcdefg", pool); svn_hash_sets(keywords, keyword, expanded); /* Expand */ src_string = svn_string_createf(pool, "$%s$", keyword); src_stream = svn_stream_from_string(src_string, pool); dst_stringbuf = svn_stringbuf_create_empty(pool); dst_stream = svn_stream_from_stringbuf(dst_stringbuf, pool); dst_stream = svn_subst_stream_translated(dst_stream, NULL, FALSE, keywords, TRUE, pool); SVN_ERR(svn_stream_copy3(src_stream, dst_stream, NULL, NULL, pool)); SVN_TEST_STRING_ASSERT(dst_stringbuf->data, expected); /* Unexpand */ src_stringbuf = dst_stringbuf; src_stream = svn_stream_from_stringbuf(src_stringbuf, pool); dst_stringbuf = svn_stringbuf_create_empty(pool); dst_stream = svn_stream_from_stringbuf(dst_stringbuf, pool); dst_stream = svn_subst_stream_translated(dst_stream, NULL, FALSE, keywords, FALSE, pool); SVN_ERR(svn_stream_copy3(src_stream, dst_stream, NULL, NULL, pool)); SVN_TEST_STRING_ASSERT(dst_stringbuf->data, src_string->data); return SVN_NO_ERROR; }
/* Print dumpstream-formatted information about REVISION. * Implements the `svn_ra_replay_revstart_callback_t' interface. */ static svn_error_t * replay_revstart(svn_revnum_t revision, void *replay_baton, const svn_delta_editor_t **editor, void **edit_baton, apr_hash_t *rev_props, apr_pool_t *pool) { struct replay_baton *rb = replay_baton; apr_hash_t *normal_props; svn_stringbuf_t *propstring; svn_stream_t *stdout_stream; svn_stream_t *revprop_stream; SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool)); /* Revision-number: 19 */ SVN_ERR(svn_stream_printf(stdout_stream, pool, SVN_REPOS_DUMPFILE_REVISION_NUMBER ": %ld\n", revision)); SVN_ERR(svn_rdump__normalize_props(&normal_props, rev_props, pool)); propstring = svn_stringbuf_create_ensure(0, pool); revprop_stream = svn_stream_from_stringbuf(propstring, pool); SVN_ERR(svn_hash_write2(normal_props, revprop_stream, "PROPS-END", pool)); SVN_ERR(svn_stream_close(revprop_stream)); /* Prop-content-length: 13 */ SVN_ERR(svn_stream_printf(stdout_stream, pool, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH ": %" APR_SIZE_T_FMT "\n", propstring->len)); /* Content-length: 29 */ SVN_ERR(svn_stream_printf(stdout_stream, pool, SVN_REPOS_DUMPFILE_CONTENT_LENGTH ": %" APR_SIZE_T_FMT "\n\n", propstring->len)); /* Property data. */ SVN_ERR(svn_stream_write(stdout_stream, propstring->data, &(propstring->len))); SVN_ERR(svn_stream_printf(stdout_stream, pool, "\n")); SVN_ERR(svn_stream_close(stdout_stream)); SVN_ERR(svn_rdump__get_dump_editor(editor, edit_baton, revision, rb->stdout_stream, rb->extra_ra_session, check_cancel, NULL, pool)); return SVN_NO_ERROR; }
static svn_error_t * test_stream_seek_stringbuf(apr_pool_t *pool) { svn_stream_t *stream; svn_stringbuf_t *stringbuf; char buf[4]; apr_size_t len; svn_stream_mark_t *mark; stringbuf = svn_stringbuf_create("OneTwo", pool); stream = svn_stream_from_stringbuf(stringbuf, pool); len = 3; SVN_ERR(svn_stream_read_full(stream, buf, &len)); buf[3] = '\0'; SVN_TEST_STRING_ASSERT(buf, "One"); SVN_ERR(svn_stream_mark(stream, &mark, pool)); len = 3; SVN_ERR(svn_stream_read_full(stream, buf, &len)); buf[3] = '\0'; SVN_TEST_STRING_ASSERT(buf, "Two"); SVN_ERR(svn_stream_seek(stream, mark)); len = 3; SVN_ERR(svn_stream_read_full(stream, buf, &len)); buf[3] = '\0'; SVN_TEST_STRING_ASSERT(buf, "Two"); /* Go back to the begin of last word and try to skip some of it */ SVN_ERR(svn_stream_seek(stream, mark)); SVN_ERR(svn_stream_skip(stream, 2)); /* The remaining line should be empty */ len = 3; SVN_ERR(svn_stream_read_full(stream, buf, &len)); buf[len] = '\0'; SVN_TEST_ASSERT(len == 1); SVN_TEST_STRING_ASSERT(buf, "o"); SVN_ERR(svn_stream_close(stream)); return SVN_NO_ERROR; }
static svn_error_t * test_svn_subst_truncated_keywords(apr_pool_t *pool) { svn_string_t *src_string = svn_string_create("$Qq: " "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789" "012345678901234567890123456789012345678901234567" " $", pool); svn_stream_t *src_stream = svn_stream_from_string(src_string, pool); svn_stringbuf_t *dst_stringbuf = svn_stringbuf_create_empty(pool); svn_stream_t *dst_stream = svn_stream_from_stringbuf(dst_stringbuf, pool); apr_hash_t *keywords = apr_hash_make(pool); svn_string_t *expanded = svn_string_create("01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789" "012345678901234567890123456789012345678901234567" "xxxxxxxxxx", pool); /* The source is already at the maximum length. */ SVN_TEST_ASSERT(src_string->len == SVN_KEYWORD_MAX_LEN); svn_hash_sets(keywords, "Qq", expanded); dst_stream = svn_subst_stream_translated(dst_stream, NULL, FALSE, keywords, TRUE, pool); SVN_ERR(svn_stream_copy3(src_stream, dst_stream, NULL, NULL, pool)); /* The expanded value would make the keyword longer than the maximum allowed so it must be truncated; the remaining part of the expanded value is the same as the source. */ SVN_TEST_STRING_ASSERT(dst_stringbuf->data, src_string->data); return SVN_NO_ERROR; }
/* Print a revision record header for REVISION to STDOUT_STREAM. Use * SESSION to contact the repository for revision properties and * such. */ static svn_error_t * dump_revision_header(svn_ra_session_t *session, svn_stream_t *stdout_stream, svn_revnum_t revision, apr_pool_t *pool) { apr_hash_t *prophash; svn_stringbuf_t *propstring; svn_stream_t *propstream; SVN_ERR(svn_stream_printf(stdout_stream, pool, SVN_REPOS_DUMPFILE_REVISION_NUMBER ": %ld\n", revision)); prophash = apr_hash_make(pool); propstring = svn_stringbuf_create_empty(pool); SVN_ERR(svn_ra_rev_proplist(session, revision, &prophash, pool)); propstream = svn_stream_from_stringbuf(propstring, pool); SVN_ERR(svn_hash_write2(prophash, propstream, "PROPS-END", pool)); SVN_ERR(svn_stream_close(propstream)); /* Property-content-length: 14; Content-length: 14 */ SVN_ERR(svn_stream_printf(stdout_stream, pool, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH ": %" APR_SIZE_T_FMT "\n", propstring->len)); SVN_ERR(svn_stream_printf(stdout_stream, pool, SVN_REPOS_DUMPFILE_CONTENT_LENGTH ": %" APR_SIZE_T_FMT "\n\n", propstring->len)); /* The properties */ SVN_ERR(svn_stream_write(stdout_stream, propstring->data, &(propstring->len))); SVN_ERR(svn_stream_printf(stdout_stream, pool, "\n")); return SVN_NO_ERROR; }
/* fonction simulant la commande svn cat */ apr_array_header_t *svn_support_cat_call(char *file_path, int revision, apr_pool_t *subpool){ svn_error_t *err; svn_opt_revision_t rev; svn_stream_t *out; // -- Initialisation de la révision -- if (revision != -1) { rev.kind = svn_opt_revision_number; rev.value.number = revision; } else rev.kind = svn_opt_revision_unspecified; // -- Initialisation du tableau et du buffer de résultats -- apr_array_header_t *list_result = apr_array_make(subpool, 1, sizeof (const char *)); svn_stringbuf_t *res = svn_stringbuf_create("",subpool); // -- Initialisation du flux de sortie -- out = svn_stream_from_stringbuf(res,subpool); err = svn_client_cat2(out, file_path, &rev, &rev, ctx, subpool); if (err) { svn_handle_error2 (err, stderr, FALSE, "svn_support_cat: "); svn_pool_destroy(subpool); return NULL; } svn_cstring_split_endline_append(list_result,res->data,subpool); svn_pool_destroy(subpool); return list_result; }
std::string Client::cat(const Path & path, const Revision & revision, const Revision & peg_revision) throw(ClientException) { Pool pool; svn_stringbuf_t * stringbuf = svn_stringbuf_create("", pool); svn_stream_t * stream = svn_stream_from_stringbuf(stringbuf, pool); svn_error_t * error; error = svn_client_cat2(stream, path.c_str(), peg_revision.revision(), revision.revision(), *m_context, pool); if (error != 0) throw ClientException(error); return std::string(stringbuf->data, stringbuf->len); }
/* This helper is the main "meat" of the editor -- it does all the work of writing a node record. Write out a node record for PATH of type KIND under EB->FS_ROOT. ACTION describes what is happening to the node (see enum svn_node_action). Write record to writable EB->STREAM, using EB->BUFFER to write in chunks. If the node was itself copied, IS_COPY is TRUE and the path/revision of the copy source are in CMP_PATH/CMP_REV. If IS_COPY is FALSE, yet CMP_PATH/CMP_REV are valid, this node is part of a copied subtree. */ static svn_error_t * dump_node(struct edit_baton *eb, const char *path, svn_node_kind_t kind, enum svn_node_action action, svn_boolean_t is_copy, const char *cmp_path, svn_revnum_t cmp_rev, apr_pool_t *pool) { svn_stringbuf_t *propstring; svn_filesize_t content_length = 0; apr_size_t len; svn_boolean_t must_dump_text = FALSE, must_dump_props = FALSE; const char *compare_path = path; svn_revnum_t compare_rev = eb->current_rev - 1; svn_fs_root_t *compare_root = NULL; apr_file_t *delta_file = NULL; /* Maybe validate the path. */ if (eb->verify || eb->notify_func) { svn_error_t *err = svn_fs__path_valid(path, pool); if (err) { if (eb->notify_func) { char errbuf[512]; /* ### svn_strerror() magic number */ svn_repos_notify_t *notify; notify = svn_repos_notify_create(svn_repos_notify_warning, pool); notify->warning = svn_repos_notify_warning_invalid_fspath; notify->warning_str = apr_psprintf( pool, _("E%06d: While validating fspath '%s': %s"), err->apr_err, path, svn_err_best_message(err, errbuf, sizeof(errbuf))); eb->notify_func(eb->notify_baton, notify, pool); } /* Return the error in addition to notifying about it. */ if (eb->verify) return svn_error_trace(err); else svn_error_clear(err); } } /* Write out metadata headers for this file node. */ SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n", path)); if (kind == svn_node_file) SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_NODE_KIND ": file\n")); else if (kind == svn_node_dir) SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n")); /* Remove leading slashes from copyfrom paths. */ if (cmp_path) cmp_path = svn_relpath_canonicalize(cmp_path, pool); /* Validate the comparison path/rev. */ if (ARE_VALID_COPY_ARGS(cmp_path, cmp_rev)) { compare_path = cmp_path; compare_rev = cmp_rev; } if (action == svn_node_action_change) { SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_NODE_ACTION ": change\n")); /* either the text or props changed, or possibly both. */ SVN_ERR(svn_fs_revision_root(&compare_root, svn_fs_root_fs(eb->fs_root), compare_rev, pool)); SVN_ERR(svn_fs_props_changed(&must_dump_props, compare_root, compare_path, eb->fs_root, path, pool)); if (kind == svn_node_file) SVN_ERR(svn_fs_contents_changed(&must_dump_text, compare_root, compare_path, eb->fs_root, path, pool)); } else if (action == svn_node_action_replace) { if (! is_copy) { /* a simple delete+add, implied by a single 'replace' action. */ SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_NODE_ACTION ": replace\n")); /* definitely need to dump all content for a replace. */ if (kind == svn_node_file) must_dump_text = TRUE; must_dump_props = TRUE; } else { /* more complex: delete original, then add-with-history. */ /* the path & kind headers have already been printed; just add a delete action, and end the current record.*/ SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_NODE_ACTION ": delete\n\n")); /* recurse: print an additional add-with-history record. */ SVN_ERR(dump_node(eb, path, kind, svn_node_action_add, is_copy, compare_path, compare_rev, pool)); /* we can leave this routine quietly now, don't need to dump any content; that was already done in the second record. */ must_dump_text = FALSE; must_dump_props = FALSE; } } else if (action == svn_node_action_delete) { SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_NODE_ACTION ": delete\n")); /* we can leave this routine quietly now, don't need to dump any content. */ must_dump_text = FALSE; must_dump_props = FALSE; } else if (action == svn_node_action_add) { SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n")); if (! is_copy) { /* Dump all contents for a simple 'add'. */ if (kind == svn_node_file) must_dump_text = TRUE; must_dump_props = TRUE; } else { if (!eb->verify && cmp_rev < eb->oldest_dumped_rev && eb->notify_func) { svn_repos_notify_t *notify = svn_repos_notify_create(svn_repos_notify_warning, pool); notify->warning = svn_repos_notify_warning_found_old_reference; notify->warning_str = apr_psprintf( pool, _("Referencing data in revision %ld," " which is older than the oldest" " dumped revision (r%ld). Loading this dump" " into an empty repository" " will fail."), cmp_rev, eb->oldest_dumped_rev); eb->found_old_reference = TRUE; eb->notify_func(eb->notify_baton, notify, pool); } SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV ": %ld\n" SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH ": %s\n", cmp_rev, cmp_path)); SVN_ERR(svn_fs_revision_root(&compare_root, svn_fs_root_fs(eb->fs_root), compare_rev, pool)); /* Need to decide if the copied node had any extra textual or property mods as well. */ SVN_ERR(svn_fs_props_changed(&must_dump_props, compare_root, compare_path, eb->fs_root, path, pool)); if (kind == svn_node_file) { svn_checksum_t *checksum; const char *hex_digest; SVN_ERR(svn_fs_contents_changed(&must_dump_text, compare_root, compare_path, eb->fs_root, path, pool)); SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5, compare_root, compare_path, FALSE, pool)); hex_digest = svn_checksum_to_cstring(checksum, pool); if (hex_digest) SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_MD5 ": %s\n", hex_digest)); SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1, compare_root, compare_path, FALSE, pool)); hex_digest = svn_checksum_to_cstring(checksum, pool); if (hex_digest) SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_SHA1 ": %s\n", hex_digest)); } } } if ((! must_dump_text) && (! must_dump_props)) { /* If we're not supposed to dump text or props, so be it, we can just go home. However, if either one needs to be dumped, then our dumpstream format demands that at a *minimum*, we see a lone "PROPS-END" as a divider between text and props content within the content-block. */ len = 2; return svn_stream_write(eb->stream, "\n\n", &len); /* ### needed? */ } /*** Start prepping content to dump... ***/ /* If we are supposed to dump properties, write out a property length header and generate a stringbuf that contains those property values here. */ if (must_dump_props) { apr_hash_t *prophash, *oldhash = NULL; apr_size_t proplen; svn_stream_t *propstream; SVN_ERR(svn_fs_node_proplist(&prophash, eb->fs_root, path, pool)); /* If this is a partial dump, then issue a warning if we dump mergeinfo properties that refer to revisions older than the first revision dumped. */ if (!eb->verify && eb->notify_func && eb->oldest_dumped_rev > 1) { svn_string_t *mergeinfo_str = apr_hash_get(prophash, SVN_PROP_MERGEINFO, APR_HASH_KEY_STRING); if (mergeinfo_str) { svn_mergeinfo_t mergeinfo, old_mergeinfo; SVN_ERR(svn_mergeinfo_parse(&mergeinfo, mergeinfo_str->data, pool)); SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges( &old_mergeinfo, mergeinfo, eb->oldest_dumped_rev - 1, 0, TRUE, pool, pool)); if (apr_hash_count(old_mergeinfo)) { svn_repos_notify_t *notify = svn_repos_notify_create(svn_repos_notify_warning, pool); notify->warning = svn_repos_notify_warning_found_old_mergeinfo; notify->warning_str = apr_psprintf( pool, _("Mergeinfo referencing revision(s) prior " "to the oldest dumped revision (r%ld). " "Loading this dump may result in invalid " "mergeinfo."), eb->oldest_dumped_rev); eb->found_old_mergeinfo = TRUE; eb->notify_func(eb->notify_baton, notify, pool); } } } if (eb->use_deltas && compare_root) { /* Fetch the old property hash to diff against and output a header saying that our property contents are a delta. */ SVN_ERR(svn_fs_node_proplist(&oldhash, compare_root, compare_path, pool)); SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_PROP_DELTA ": true\n")); } else oldhash = apr_hash_make(pool); propstring = svn_stringbuf_create_ensure(0, pool); propstream = svn_stream_from_stringbuf(propstring, pool); SVN_ERR(svn_hash_write_incremental(prophash, oldhash, propstream, "PROPS-END", pool)); SVN_ERR(svn_stream_close(propstream)); proplen = propstring->len; content_length += proplen; SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH ": %" APR_SIZE_T_FMT "\n", proplen)); } /* If we are supposed to dump text, write out a text length header here, and an MD5 checksum (if available). */ if (must_dump_text && (kind == svn_node_file)) { svn_checksum_t *checksum; const char *hex_digest; svn_filesize_t textlen; if (eb->use_deltas) { /* Compute the text delta now and write it into a temporary file, so that we can find its length. Output a header saying our text contents are a delta. */ SVN_ERR(store_delta(&delta_file, &textlen, compare_root, compare_path, eb->fs_root, path, pool)); SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_TEXT_DELTA ": true\n")); if (compare_root) { SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5, compare_root, compare_path, FALSE, pool)); hex_digest = svn_checksum_to_cstring(checksum, pool); if (hex_digest) SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_MD5 ": %s\n", hex_digest)); SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1, compare_root, compare_path, FALSE, pool)); hex_digest = svn_checksum_to_cstring(checksum, pool); if (hex_digest) SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_SHA1 ": %s\n", hex_digest)); } } else { /* Just fetch the length of the file. */ SVN_ERR(svn_fs_file_length(&textlen, eb->fs_root, path, pool)); } content_length += textlen; SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH ": %" SVN_FILESIZE_T_FMT "\n", textlen)); SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5, eb->fs_root, path, FALSE, pool)); hex_digest = svn_checksum_to_cstring(checksum, pool); if (hex_digest) SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_TEXT_CONTENT_MD5 ": %s\n", hex_digest)); SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1, eb->fs_root, path, FALSE, pool)); hex_digest = svn_checksum_to_cstring(checksum, pool); if (hex_digest) SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_TEXT_CONTENT_SHA1 ": %s\n", hex_digest)); } /* 'Content-length:' is the last header before we dump the content, and is the sum of the text and prop contents lengths. We write this only for the benefit of non-Subversion RFC-822 parsers. */ SVN_ERR(svn_stream_printf(eb->stream, pool, SVN_REPOS_DUMPFILE_CONTENT_LENGTH ": %" SVN_FILESIZE_T_FMT "\n\n", content_length)); /* Dump property content if we're supposed to do so. */ if (must_dump_props) { len = propstring->len; SVN_ERR(svn_stream_write(eb->stream, propstring->data, &len)); } /* Dump text content */ if (must_dump_text && (kind == svn_node_file)) { svn_stream_t *contents; if (delta_file) { /* Make sure to close the underlying file when the stream is closed. */ contents = svn_stream_from_aprfile2(delta_file, FALSE, pool); } else SVN_ERR(svn_fs_file_contents(&contents, eb->fs_root, path, pool)); SVN_ERR(svn_stream_copy3(contents, svn_stream_disown(eb->stream, pool), NULL, NULL, pool)); } len = 2; return svn_stream_write(eb->stream, "\n\n", &len); /* ### needed? */ }
/* This test doesn't test much unless run under valgrind when it triggers the problem reported here: http://mail-archives.apache.org/mod_mbox/subversion-dev/201202.mbox/%[email protected]%3E The two data writes caused the base 64 code to allocate a buffer that was a byte short but exactly matched a stringbuf blocksize. That meant the stringbuf didn't overallocate and a write beyond the end of the buffer occurred. */ static svn_error_t * test_stream_base64_2(apr_pool_t *pool) { const struct data_t { const char *encoded1; const char *encoded2; } data[] = { { "MTI", "123456789A123456789B123456789C123456789D123456789E" "223456789A123456789B123456789C123456789D123456789E" "323456789A123456789B123456789C123456789D123456789E" "423456789A123456789B123456789C123456789D123456789E" "523456789A123456789B123456789C123456789D123456789E" "623456789A123456789B123456789C123456789D123456789E" "723456789A123456789B123456789C123456789D123456789E" "823456789A123456789B123456789C123456789D123456789E" "923456789A123456789B123456789C123456789D123456789E" "A23456789A123456789B123456789C123456789D123456789E" "123456789A123456789B123456789C123456789D123456789E" "223456789A123456789B123456789C123456789D123456789E" "323456789A123456789B123456789C123456789D123456789E" "423456789A123456789B123456789C123456789D123456789E" "523456789A123456789B123456789C123456789D123456789E" "623456789A123456789B123456789C123456789D123456789E" "723456789A123456789B123456789C123456789D123456789E" "823456789A123456789B123456789C123456789D123456789E" "923456789A123456789B123456789C123456789D123456789E" "B23456789A123456789B123456789C123456789D123456789E" "123456789A123456789B123456789C123456789D123456789E" "223456789A123456789B123456789C123456789D123456789E" "323456789A123456789B123456789C123456789D123456789E" "423456789A123456789B123456789C123456789D123456789E" "523456789A123456789B123456789C123456789D123456789E" "623456789A123456789B123456789C123456789D123456789E" "723456789A123456789B123456789C123456789D123456789E" "823456789A123456789B123456789C123456789D123456789E" "923456789A123456789B123456789C123456789D123456789E" "C23456789A123456789B123456789C123456789D123456789E" "123456789A123456789B123456789C123456789D123456789E" "223456789A123456789B123456789C123456789D123456789E" "323456789A123456789B123456789C123456789D123456789E" "423456789A123456789B123456789C123456789D123456789E" "523456789A123456789B123456789C123456789D123456789E" "623456789A123456789B123456789C123456789D123456789E" "723456789A123456789B123456789C123456789D123456789E" "823456789A123456789B123456789C123456789D123456789E" "923456789A123456789B123456789C123456789D123456789E" "D23456789A123456789B123456789C123456789D123456789E" "123456789A123456789B123456789C123456789D123456789E" "223456789A123456789B123456789C123456789D123456789E" "323456789A123456789B123456789C123456789D123456789E" "423456789A123456789B123456789C123456789D123456789E" "523456789A123456789B123456789C123456789D123456789E" "623456789A123456789B123456789C123456789D123456789E" "723456789A123456789B123456789C123456789D123456789E" "823456789A123456789B123456789C123456789D123456789E" "923456789A123456789B123456789C123456789D123456789E" "E23456789A123456789B123456789C123456789D123456789E" "123456789A123456789B123456789C123456789D123456789E" "223456789A123456789B123456789C123456789D123456789E" "323456789A123456789B123456789C123456789D123456789E" "423456789A123456789B123456789C123456789D123456789E" "523456789A123456789B123456789C123456789D123456789E" "623456789A123456789B123456789C123456789D123456789E" "723456789A123456789B123456789C123456789D123456789E" "823456789A123456789B123456789C123456789D123456789E" "923456789A123456789B123456789C123456789D123456789E" "F23456789A123456789B123456789C123456789D123456789E" "123456789A123456789B123456789C123456789D123456789E" "223456789A123456789B123456789C123456789D123456789E" "323456789A123456789B123456789C123456789D123456789E" "423456789A123456789B123456789C123456789D123456789E" "523456789A123456789B123456789C123456789D123456789E" "623456789A123456789B123456789C123456789D123456789E" "723456789A123456789B123456789C123456789D123456789E" "823456789A123456789B123456789C123456789D123456789E" "923456789A123456789B123456789C123456789D123456789E" "G23456789A123456789B123456789C123456789D123456789E" "123456789A123456789B123456789C123456789D123456789E" "223456789A123456789B123456789C123456789D123456789E" "323456789A123456789B123456789C123456789D123456789E" "423456789A123456789B123456789C123456789D123456789E" "523456789A123456789B123456789C123456789D123456789E" "623456789A123456789B123456789C123456789D123456789E" "723456789A123456789B123456789C123456789D123456789E" "823456789A123456789B123456789C123456789D123456789E" "923456789A123456789B123456789C123456789D123456789E" "H23456789A123456789B123456789C123456789D123456789E" "123456789A123456789B123456789C123456789D123456789E" "223456789A123456789B123456789C123456789D123456789E" "323456789A123456789B123456789C123456789D123456789E" "423456789A123456789B123456789C123456789D123456789E" "523456789A123456789B123456789C123456789D123456789E" "623456789A123456789B123456789C123456789D123456789E" "723456789A123456789B123456789C123456789D123456789E" "823456789A123456789B123456789C123456789D123456789E" "923456789A123456789B123456789C123456789D123456789E" "I23456789A123456789B123456789C123456789D123456789E" "123456789A123456789B123456789C123456789D123456789E" "223456789A123456789B123456789C123456789D123456789E" "323456789A123456789B123456789C123456789D123456789E" "423456789A123456789B123456789C123456789D123456789E" "523456789A123456789B123456789C123456789D123456789E" "623456789A123456789B123456789C123456789D123456789E" "723456789A123456789B123456789C123456789D123456789E" "823456789A123456789B123456789C123456789D123456789E" "923456789A123456789B123456789C123456789D123456789E" "J23456789A123456789B123456789C123456789D123456789E" "123456789A123456789B123456789C123456789D123456789E" "223456789A123456789B123456789C123456789D123456789E" "323456789A123456789B123456789C123456789D123456789E" "423456789A123456789B123456789C123456789D123456789E" "523456789A123456789B123456789C123456789D12345" }, { NULL, NULL, }, }; int i; for (i = 0; data[i].encoded1; i++) { apr_size_t len1 = strlen(data[i].encoded1); svn_stringbuf_t *actual = svn_stringbuf_create_empty(pool); svn_stringbuf_t *expected = svn_stringbuf_create_empty(pool); svn_stream_t *stream = svn_stream_from_stringbuf(actual, pool); stream = svn_base64_encode(stream, pool); stream = svn_base64_decode(stream, pool); SVN_ERR(svn_stream_write(stream, data[i].encoded1, &len1)); svn_stringbuf_appendbytes(expected, data[i].encoded1, len1); if (data[i].encoded2) { apr_size_t len2 = strlen(data[i].encoded2); SVN_ERR(svn_stream_write(stream, data[i].encoded2, &len2)); svn_stringbuf_appendbytes(expected, data[i].encoded2, len2); } SVN_ERR(svn_stream_close(stream)); } return SVN_NO_ERROR; }
static svn_error_t * test_stream_seek_translated(apr_pool_t *pool) { svn_stream_t *stream, *translated_stream; svn_stringbuf_t *stringbuf; char buf[44]; /* strlen("One$MyKeyword: my keyword was expanded $Two") + \0 */ apr_size_t len; svn_stream_mark_t *mark; apr_hash_t *keywords; svn_string_t *keyword_val; keywords = apr_hash_make(pool); keyword_val = svn_string_create("my keyword was expanded", pool); apr_hash_set(keywords, "MyKeyword", APR_HASH_KEY_STRING, keyword_val); stringbuf = svn_stringbuf_create("One$MyKeyword$Two", pool); stream = svn_stream_from_stringbuf(stringbuf, pool); translated_stream = svn_subst_stream_translated(stream, APR_EOL_STR, FALSE, keywords, TRUE, pool); /* Seek from outside of keyword to inside of keyword. */ len = 25; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 25); buf[25] = '\0'; SVN_TEST_STRING_ASSERT(buf, "One$MyKeyword: my keyword"); SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); SVN_ERR(svn_stream_reset(translated_stream)); SVN_ERR(svn_stream_seek(translated_stream, mark)); len = 4; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 4); buf[4] = '\0'; SVN_TEST_STRING_ASSERT(buf, " was"); SVN_ERR(svn_stream_seek(translated_stream, mark)); SVN_ERR(svn_stream_skip(translated_stream, 2)); len = 2; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 2); buf[len] = '\0'; SVN_TEST_STRING_ASSERT(buf, "as"); /* Seek from inside of keyword to inside of keyword. */ SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); len = 9; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 9); buf[9] = '\0'; SVN_TEST_STRING_ASSERT(buf, " expanded"); SVN_ERR(svn_stream_seek(translated_stream, mark)); len = 9; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 9); buf[9] = '\0'; SVN_TEST_STRING_ASSERT(buf, " expanded"); SVN_ERR(svn_stream_seek(translated_stream, mark)); SVN_ERR(svn_stream_skip(translated_stream, 6)); len = 3; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 3); buf[len] = '\0'; SVN_TEST_STRING_ASSERT(buf, "ded"); /* Seek from inside of keyword to outside of keyword. */ SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); len = 4; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 4); buf[4] = '\0'; SVN_TEST_STRING_ASSERT(buf, " $Tw"); SVN_ERR(svn_stream_seek(translated_stream, mark)); len = 4; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 4); buf[4] = '\0'; SVN_TEST_STRING_ASSERT(buf, " $Tw"); SVN_ERR(svn_stream_seek(translated_stream, mark)); SVN_ERR(svn_stream_skip(translated_stream, 2)); len = 2; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 2); buf[len] = '\0'; SVN_TEST_STRING_ASSERT(buf, "Tw"); /* Seek from outside of keyword to outside of keyword. */ SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); len = 1; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 1); buf[1] = '\0'; SVN_TEST_STRING_ASSERT(buf, "o"); SVN_ERR(svn_stream_seek(translated_stream, mark)); len = 1; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 1); buf[1] = '\0'; SVN_TEST_STRING_ASSERT(buf, "o"); SVN_ERR(svn_stream_seek(translated_stream, mark)); SVN_ERR(svn_stream_skip(translated_stream, 2)); len = 1; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 0); buf[len] = '\0'; SVN_TEST_STRING_ASSERT(buf, ""); SVN_ERR(svn_stream_close(stream)); return SVN_NO_ERROR; }
static svn_error_t * test_stream_from_string(apr_pool_t *pool) { int i; apr_pool_t *subpool = svn_pool_create(pool); #define NUM_TEST_STRINGS 4 #define TEST_BUF_SIZE 10 static const char * const strings[NUM_TEST_STRINGS] = { /* 0 */ "", /* 1 */ "This is a string.", /* 2 */ "This is, by comparison to the previous string, a much longer string.", /* 3 */ "And if you thought that last string was long, you just wait until " "I'm finished here. I mean, how can a string really claim to be long " "when it fits on a single line of 80-columns? Give me a break. " "Now, I'm not saying that I'm the longest string out there--far from " "it--but I feel that it is safe to assume that I'm far longer than my " "peers. And that demands some amount of respect, wouldn't you say?" }; /* Test svn_stream_from_stringbuf() as a readable stream. */ for (i = 0; i < NUM_TEST_STRINGS; i++) { svn_stream_t *stream; char buffer[TEST_BUF_SIZE]; svn_stringbuf_t *inbuf, *outbuf; apr_size_t len; inbuf = svn_stringbuf_create(strings[i], subpool); outbuf = svn_stringbuf_create_empty(subpool); stream = svn_stream_from_stringbuf(inbuf, subpool); len = TEST_BUF_SIZE; while (len == TEST_BUF_SIZE) { /* Read a chunk ... */ SVN_ERR(svn_stream_read_full(stream, buffer, &len)); /* ... and append the chunk to the stringbuf. */ svn_stringbuf_appendbytes(outbuf, buffer, len); } if (! svn_stringbuf_compare(inbuf, outbuf)) return svn_error_create(SVN_ERR_TEST_FAILED, NULL, "Got unexpected result."); svn_pool_clear(subpool); } /* Test svn_stream_from_stringbuf() as a writable stream. */ for (i = 0; i < NUM_TEST_STRINGS; i++) { svn_stream_t *stream; svn_stringbuf_t *inbuf, *outbuf; apr_size_t amt_read, len; inbuf = svn_stringbuf_create(strings[i], subpool); outbuf = svn_stringbuf_create_empty(subpool); stream = svn_stream_from_stringbuf(outbuf, subpool); amt_read = 0; while (amt_read < inbuf->len) { /* Write a chunk ... */ len = TEST_BUF_SIZE < (inbuf->len - amt_read) ? TEST_BUF_SIZE : inbuf->len - amt_read; SVN_ERR(svn_stream_write(stream, inbuf->data + amt_read, &len)); amt_read += len; } if (! svn_stringbuf_compare(inbuf, outbuf)) return svn_error_create(SVN_ERR_TEST_FAILED, NULL, "Got unexpected result."); svn_pool_clear(subpool); } #undef NUM_TEST_STRINGS #undef TEST_BUF_SIZE svn_pool_destroy(subpool); return SVN_NO_ERROR; }
svn_error_t * svn_fs_fs__dag_deserialize(void **out, const char *data, apr_size_t data_len, apr_pool_t *pool) { dag_node_t *node = apr_pcalloc(pool, sizeof(*node)); if (data_len == 0) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Empty noderev in cache")); if (*data == 'M') { const char *newline; int id_len; data++; data_len--; if (data_len == 0) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Kindless noderev in cache")); if (*data == 'F') node->kind = svn_node_file; else if (*data == 'D') node->kind = svn_node_dir; else return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Unknown kind for noderev in cache: '%c'"), *data); data++; data_len--; newline = memchr(data, '\n', data_len); if (!newline) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Unterminated ID in cache")); id_len = newline - 1 - data; node->id = svn_fs_fs__id_parse(data, id_len, pool); if (! node->id) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Bogus ID '%s' in cache"), apr_pstrndup(pool, data, id_len)); data += id_len; data_len -= id_len; data++; data_len--; if (data_len == 0) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("No created path")); node->created_path = apr_pstrndup(pool, data, data_len); } else if (*data == 'I') { node_revision_t *noderev; apr_pool_t *subpool = svn_pool_create(pool); svn_stream_t *stream = svn_stream_from_stringbuf(svn_stringbuf_ncreate(data + 1, data_len - 1, subpool), subpool); SVN_ERR(svn_fs_fs__read_noderev(&noderev, stream, pool)); node->kind = noderev->kind; node->id = svn_fs_fs__id_copy(noderev->id, pool); node->created_path = apr_pstrdup(pool, noderev->created_path); if (noderev->is_fresh_txn_root) node->fresh_root_predecessor_id = noderev->predecessor_id; node->node_revision = noderev; svn_pool_destroy(subpool); } else return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Unknown node type in cache: '%c'"), *data); *out = node; return SVN_NO_ERROR; }
inline Try<Diff> diff(const std::string& from, const std::string& to) { // Initialize the Apache Portable Runtime subsystem, as necessary // for using the svn library. initialize(); // Note that svn_pool_create wraps apr_pool_create_ex, which is // thread safe, see: http://goo.gl/NX0hps. apr_pool_t* pool = svn_pool_create(NULL); // First we need to produce a text delta stream by diffing 'source' // against 'target'. svn_string_t source; source.data = from.data(); source.len = from.length(); svn_string_t target; target.data = to.data(); target.len = to.length(); svn_txdelta_stream_t* delta; #if SVN_VER_MAJOR >= 1 && SVN_VER_MINOR >= 8 svn_txdelta2( &delta, svn_stream_from_string(&source, pool), svn_stream_from_string(&target, pool), false, pool); #else svn_txdelta( &delta, svn_stream_from_string(&source, pool), svn_stream_from_string(&target, pool), pool); #endif // Now we want to convert this text delta stream into an svndiff // format based diff. Setup the handler that will consume the text // delta and produce the svndiff. svn_txdelta_window_handler_t handler; void* baton = NULL; svn_stringbuf_t* diff = svn_stringbuf_create_ensure(1024, pool); #if SVN_VER_MAJOR >= 1 && SVN_VER_MINOR >= 7 svn_txdelta_to_svndiff3( &handler, &baton, svn_stream_from_stringbuf(diff, pool), 0, SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, pool); #elif SVN_VER_MAJOR >= 1 && SVN_VER_MINOR >= 4 svn_txdelta_to_svndiff2( &handler, &baton, svn_stream_from_stringbuf(diff, pool), 0, pool); #else svn_txdelta_to_svndiff( svn_stream_from_stringbuf(diff, pool), pool, &handler, &baton); #endif // Now feed the text delta to the handler. svn_error_t* error = svn_txdelta_send_txstream(delta, handler, baton, pool); if (error != NULL) { char buffer[1024]; std::string message(svn_err_best_message(error, buffer, 1024)); svn_pool_destroy(pool); return Error(message); } Diff d(std::string(diff->data, diff->len)); svn_pool_destroy(pool); return d; }
static svn_error_t * test_stream_compressed(apr_pool_t *pool) { #define NUM_TEST_STRINGS 5 #define TEST_BUF_SIZE 10 #define GENERATED_SIZE 20000 int i; svn_stringbuf_t *bufs[NUM_TEST_STRINGS]; apr_pool_t *subpool = svn_pool_create(pool); static const char * const strings[NUM_TEST_STRINGS - 1] = { /* 0 */ "", /* 1 */ "This is a string.", /* 2 */ "This is, by comparison to the previous string, a much longer string.", /* 3 */ "And if you thought that last string was long, you just wait until " "I'm finished here. I mean, how can a string really claim to be long " "when it fits on a single line of 80-columns? Give me a break. " "Now, I'm not saying that I'm the longest string out there--far from " "it--but I feel that it is safe to assume that I'm far longer than my " "peers. And that demands some amount of respect, wouldn't you say?" }; for (i = 0; i < (NUM_TEST_STRINGS - 1); i++) bufs[i] = svn_stringbuf_create(strings[i], pool); /* the last buffer is for the generated data */ bufs[NUM_TEST_STRINGS - 1] = generate_test_bytes(GENERATED_SIZE, pool); for (i = 0; i < NUM_TEST_STRINGS; i++) { svn_stream_t *stream; svn_stringbuf_t *origbuf, *inbuf, *outbuf; char buf[TEST_BUF_SIZE]; apr_size_t len; origbuf = bufs[i]; inbuf = svn_stringbuf_create_empty(subpool); outbuf = svn_stringbuf_create_empty(subpool); stream = svn_stream_compressed(svn_stream_from_stringbuf(outbuf, subpool), subpool); len = origbuf->len; SVN_ERR(svn_stream_write(stream, origbuf->data, &len)); SVN_ERR(svn_stream_close(stream)); stream = svn_stream_compressed(svn_stream_from_stringbuf(outbuf, subpool), subpool); len = TEST_BUF_SIZE; while (len >= TEST_BUF_SIZE) { len = TEST_BUF_SIZE; SVN_ERR(svn_stream_read_full(stream, buf, &len)); if (len > 0) svn_stringbuf_appendbytes(inbuf, buf, len); } if (! svn_stringbuf_compare(inbuf, origbuf)) return svn_error_create(SVN_ERR_TEST_FAILED, NULL, "Got unexpected result."); SVN_ERR(svn_stream_close(stream)); svn_pool_clear(subpool); } #undef NUM_TEST_STRINGS #undef TEST_BUF_SIZE #undef GENERATED_SIZE svn_pool_destroy(subpool); return SVN_NO_ERROR; }