/* 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); }
static svn_error_t * write_handler_tee(void *baton, const char *data, apr_size_t *len) { struct baton_tee *bt = baton; SVN_ERR(svn_stream_write(bt->out1, data, len)); SVN_ERR(svn_stream_write(bt->out2, data, len)); return SVN_NO_ERROR; }
/* Copies the data from ORIGINAL_STREAM to a temporary file, returning both the original and compressed size. */ static svn_error_t * create_compressed(apr_file_t **result, svn_filesize_t *full_size, svn_filesize_t *compressed_size, svn_stream_t *original_stream, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_stream_t *compressed; svn_filesize_t bytes_read = 0; apr_size_t rd; SVN_ERR(svn_io_open_uniquely_named(result, NULL, NULL, "diffgz", NULL, svn_io_file_del_on_pool_cleanup, result_pool, scratch_pool)); compressed = svn_stream_compressed( svn_stream_from_aprfile2(*result, TRUE, scratch_pool), scratch_pool); if (original_stream) do { char buffer[SVN__STREAM_CHUNK_SIZE]; rd = sizeof(buffer); if (cancel_func) SVN_ERR(cancel_func(cancel_baton)); SVN_ERR(svn_stream_read_full(original_stream, buffer, &rd)); bytes_read += rd; SVN_ERR(svn_stream_write(compressed, buffer, &rd)); } while(rd == SVN__STREAM_CHUNK_SIZE); else { apr_size_t zero = 0; SVN_ERR(svn_stream_write(compressed, NULL, &zero)); } SVN_ERR(svn_stream_close(compressed)); /* Flush compression */ *full_size = bytes_read; SVN_ERR(svn_io_file_size_get(compressed_size, *result, scratch_pool)); return SVN_NO_ERROR; }
static svn_error_t * cdata_handler(void *baton, int state, const char *cdata, size_t len) { replay_baton_t *rb = baton; apr_size_t nlen = len; switch (state) { case ELEM_apply_textdelta: SVN_ERR(svn_stream_write(rb->base64_decoder, cdata, &nlen)); if (nlen != len) return svn_error_createf (SVN_ERR_STREAM_UNEXPECTED_EOF, NULL, _("Error writing stream: unexpected EOF")); break; case ELEM_change_dir_prop: case ELEM_change_file_prop: if (! rb->prop_accum) return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, _("Got cdata content for a prop delete")); else svn_stringbuf_appendbytes(rb->prop_accum, cdata, len); break; } return SVN_NO_ERROR; }
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; }
/* Write a single change entry, path PATH, change CHANGE, to STREAM. All temporary allocations are in SCRATCH_POOL. */ static svn_error_t * write_change_entry(svn_stream_t *stream, svn_fs_x__change_t *change, apr_pool_t *scratch_pool) { const char *change_string = NULL; const char *kind_string = ""; svn_stringbuf_t *buf; apr_size_t len; switch (change->change_kind) { case svn_fs_path_change_modify: change_string = ACTION_MODIFY; break; case svn_fs_path_change_add: change_string = ACTION_ADD; break; case svn_fs_path_change_delete: change_string = ACTION_DELETE; break; case svn_fs_path_change_replace: change_string = ACTION_REPLACE; break; default: return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Invalid change type %d"), change->change_kind); } SVN_ERR_ASSERT(change->node_kind == svn_node_dir || change->node_kind == svn_node_file); kind_string = apr_psprintf(scratch_pool, "-%s", change->node_kind == svn_node_dir ? SVN_FS_X__KIND_DIR : SVN_FS_X__KIND_FILE); buf = svn_stringbuf_createf(scratch_pool, "%s%s %s %s %s %s\n", change_string, kind_string, change->text_mod ? FLAG_TRUE : FLAG_FALSE, change->prop_mod ? FLAG_TRUE : FLAG_FALSE, change->mergeinfo_mod == svn_tristate_true ? FLAG_TRUE : FLAG_FALSE, auto_escape_path(change->path.data, scratch_pool)); if (SVN_IS_VALID_REVNUM(change->copyfrom_rev)) { svn_stringbuf_appendcstr(buf, apr_psprintf(scratch_pool, "%ld %s", change->copyfrom_rev, auto_escape_path(change->copyfrom_path, scratch_pool))); } svn_stringbuf_appendbyte(buf, '\n'); /* Write all change info in one write call. */ len = buf->len; return svn_error_trace(svn_stream_write(stream, buf->data, &len)); }
svn_error_t * svn_stream_puts(svn_stream_t *stream, const char *str) { apr_size_t len; len = strlen(str); return svn_error_trace(svn_stream_write(stream, str, &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; }
svn_error_t * logger__write(logger_t *logger, const char *errstr, apr_size_t len) { SVN_MUTEX__WITH_LOCK(logger->mutex, svn_stream_write(logger->stream, errstr, &len)); return SVN_NO_ERROR; }
static svn_error_t * write_handler_checksum(void *baton, const char *buffer, apr_size_t *len) { struct checksum_stream_baton *btn = baton; if (btn->write_checksum && *len > 0) SVN_ERR(svn_checksum_update(btn->write_ctx, buffer, *len)); return svn_error_trace(svn_stream_write(btn->proxy, buffer, len)); }
svn_error_t * svn_fs_x__write_properties(svn_stream_t *stream, apr_hash_t *proplist, apr_pool_t *scratch_pool) { apr_byte_t buffer[SVN__MAX_ENCODED_UINT_LEN]; apr_size_t len; apr_hash_index_t *hi; /* Write the number of properties in this list. */ len = svn__encode_uint(buffer, apr_hash_count(proplist)) - buffer; SVN_ERR(svn_stream_write(stream, (const char *)buffer, &len)); /* Serialize each property as follows: <Prop-name> <NUL> <Value-len> <Prop-value> <NUL> */ for (hi = apr_hash_first(scratch_pool, proplist); hi; hi = apr_hash_next(hi)) { const char *key; apr_size_t key_len; svn_string_t *value; apr_hash_this(hi, (const void **)&key, (apr_ssize_t *)&key_len, (void **)&value); /* Include the terminating NUL. */ ++key_len; SVN_ERR(svn_stream_write(stream, key, &key_len)); len = svn__encode_uint(buffer, value->len) - buffer; SVN_ERR(svn_stream_write(stream, (const char *)buffer, &len)); SVN_ERR(svn_stream_write(stream, value->data, &value->len)); /* Terminate with NUL. */ len = 1; SVN_ERR(svn_stream_write(stream, "", &len)); } return SVN_NO_ERROR; }
/* Implements svn_write_fn_t */ static svn_error_t * write_handler_lazyopen(void *baton, const char *data, apr_size_t *len) { lazyopen_baton_t *b = baton; SVN_ERR(lazyopen_if_unopened(b)); SVN_ERR(svn_stream_write(b->real_stream, data, len)); 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 * stream_write(svn_stream_t *out, const char *data, apr_size_t len) { apr_size_t write_len = len; /* We're gonna bail on an incomplete write here only because we know that this stream is really stdout, which should never be blocking on us. */ SVN_ERR(svn_stream_write(out, data, &write_len)); if (write_len != len) return svn_error_create(SVN_ERR_STREAM_UNEXPECTED_EOF, NULL, _("Error writing to stream")); return SVN_NO_ERROR; }
svn_error_t * svn_stream_printf(svn_stream_t *stream, apr_pool_t *pool, const char *fmt, ...) { const char *message; va_list ap; apr_size_t len; va_start(ap, fmt); message = apr_pvsprintf(pool, fmt, ap); va_end(ap); len = strlen(message); return svn_stream_write(stream, message, &len); }
static svn_error_t *ra_svn_handle_textdelta_chunk(svn_ra_svn_conn_t *conn, apr_pool_t *pool, const apr_array_header_t *params, ra_svn_driver_state_t *ds) { const char *token; ra_svn_token_entry_t *entry; svn_string_t *str; /* Parse arguments and look up the token. */ SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "cs", &token, &str)); SVN_ERR(lookup_token(ds, token, TRUE, &entry)); if (!entry->dstream) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, _("Apply-textdelta not active")); SVN_CMD_ERR(svn_stream_write(entry->dstream, str->data, &str->len)); return SVN_NO_ERROR; }
/* Conforms to svn_ra_serf__xml_cdata_t */ static svn_error_t * blame_cdata(svn_ra_serf__xml_estate_t *xes, void *baton, int current_state, const char *data, apr_size_t len, apr_pool_t *scratch_pool) { blame_context_t *blame_ctx = baton; if (current_state == TXDELTA) { SVN_ERR(svn_stream_write(blame_ctx->stream, data, &len)); /* Ignore the returned LEN value. */ } return SVN_NO_ERROR; }
static svn_error_t * test_spillbuf_stream(apr_pool_t *pool) { svn_spillbuf_t *buf = svn_spillbuf__create(4 /* blocksize */, 100 /* maxsize */, pool); svn_stream_t *stream = svn_stream__from_spillbuf(buf, pool); char readbuf[256]; apr_size_t readlen; apr_size_t writelen; writelen = 6; SVN_ERR(svn_stream_write(stream, "abcdef", &writelen)); SVN_ERR(svn_stream_write(stream, "ghijkl", &writelen)); /* now: two blocks: 8 and 4 bytes */ readlen = 8; SVN_ERR(svn_stream_read_full(stream, readbuf, &readlen)); SVN_TEST_ASSERT(readlen == 8 && memcmp(readbuf, "abcdefgh", 8) == 0); /* now: one block: 4 bytes */ SVN_ERR(svn_stream_write(stream, "mnopqr", &writelen)); /* now: two blocks: 8 and 2 bytes */ SVN_ERR(svn_stream_read_full(stream, readbuf, &readlen)); SVN_TEST_ASSERT(readlen == 8 && memcmp(readbuf, "ijklmnop", 8) == 0); /* now: one block: 2 bytes */ SVN_ERR(svn_stream_write(stream, "stuvwx", &writelen)); SVN_ERR(svn_stream_write(stream, "ABCDEF", &writelen)); SVN_ERR(svn_stream_write(stream, "GHIJKL", &writelen)); /* now: two blocks: 8 and 6 bytes, and 6 bytes spilled to a file */ SVN_ERR(svn_stream_read_full(stream, readbuf, &readlen)); SVN_TEST_ASSERT(readlen == 8 && memcmp(readbuf, "qrstuvwx", 8) == 0); readlen = 6; SVN_ERR(svn_stream_read_full(stream, readbuf, &readlen)); SVN_TEST_ASSERT(readlen == 6 && memcmp(readbuf, "ABCDEF", 6) == 0); SVN_ERR(svn_stream_read_full(stream, readbuf, &readlen)); SVN_TEST_ASSERT(readlen == 6 && memcmp(readbuf, "GHIJKL", 6) == 0); return SVN_NO_ERROR; }
svn_error_t *svn_stream_copy3(svn_stream_t *from, svn_stream_t *to, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *scratch_pool) { char *buf = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE); svn_error_t *err; svn_error_t *err2; /* Read and write chunks until we get a short read, indicating the end of the stream. (We can't get a short write without an associated error.) */ while (1) { apr_size_t len = SVN__STREAM_CHUNK_SIZE; if (cancel_func) { err = cancel_func(cancel_baton); if (err) break; } err = svn_stream_read(from, buf, &len); if (err) break; if (len > 0) err = svn_stream_write(to, buf, &len); if (err || (len != SVN__STREAM_CHUNK_SIZE)) break; } err2 = svn_error_compose_create(svn_stream_close(from), svn_stream_close(to)); return svn_error_compose_create(err, err2); }
svn_error_t * svn_stream_printf_from_utf8(svn_stream_t *stream, const char *encoding, apr_pool_t *pool, const char *fmt, ...) { const char *message, *translated; va_list ap; apr_size_t len; va_start(ap, fmt); message = apr_pvsprintf(pool, fmt, ap); va_end(ap); SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated, message, encoding, pool)); len = strlen(translated); return svn_stream_write(stream, translated, &len); }
/* 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; }
/* Read CONTENT_LENGTH bytes from STREAM, and use PARSE_FNS->set_fulltext to push those bytes as replace fulltext for a node. Use BUFFER/BUFLEN to push the fulltext in "chunks". Use POOL for all allocations. */ static svn_error_t * parse_text_block(svn_stream_t *stream, svn_filesize_t content_length, svn_boolean_t is_delta, const svn_repos_parse_fns3_t *parse_fns, void *record_baton, char *buffer, apr_size_t buflen, apr_pool_t *pool) { svn_stream_t *text_stream = NULL; apr_size_t num_to_read, rlen, wlen; if (is_delta) { svn_txdelta_window_handler_t wh; void *whb; SVN_ERR(parse_fns->apply_textdelta(&wh, &whb, record_baton)); if (wh) text_stream = svn_txdelta_parse_svndiff(wh, whb, TRUE, pool); } else { /* Get a stream to which we can push the data. */ SVN_ERR(parse_fns->set_fulltext(&text_stream, record_baton)); } /* If there are no contents to read, just write an empty buffer through our callback. */ if (content_length == 0) { wlen = 0; if (text_stream) SVN_ERR(svn_stream_write(text_stream, "", &wlen)); } /* Regardless of whether or not we have a sink for our data, we need to read it. */ while (content_length) { if (content_length >= (svn_filesize_t)buflen) rlen = buflen; else rlen = (apr_size_t) content_length; num_to_read = rlen; SVN_ERR(svn_stream_read(stream, buffer, &rlen)); content_length -= rlen; if (rlen != num_to_read) return stream_ran_dry(); if (text_stream) { /* write however many bytes you read. */ wlen = rlen; SVN_ERR(svn_stream_write(text_stream, buffer, &wlen)); if (wlen != rlen) { /* Uh oh, didn't write as many bytes as we read. */ return svn_error_create(SVN_ERR_STREAM_UNEXPECTED_EOF, NULL, _("Unexpected EOF writing contents")); } } } /* If we opened a stream, we must close it. */ if (text_stream) SVN_ERR(svn_stream_close(text_stream)); return SVN_NO_ERROR; }
svn_error_t * svn_ra_svn__stream_write(svn_ra_svn__stream_t *stream, const char *data, apr_size_t *len) { return svn_error_trace(svn_stream_write(stream->out_stream, data, len)); }
/* 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_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; }
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; }
/* Apply WINDOW to the streams given by APPL. */ static svn_error_t * apply_window(svn_txdelta_window_t *window, void *baton) { struct apply_baton *ab = (struct apply_baton *) baton; apr_size_t len; svn_error_t *err; if (window == NULL) { /* We're done; just clean up. */ if (ab->result_digest) apr_md5_final(ab->result_digest, &(ab->md5_context)); err = svn_stream_close(ab->target); svn_pool_destroy(ab->pool); return err; } /* Make sure the source view didn't slide backwards. */ SVN_ERR_ASSERT(window->sview_len == 0 || (window->sview_offset >= ab->sbuf_offset && (window->sview_offset + window->sview_len >= ab->sbuf_offset + ab->sbuf_len))); /* Make sure there's enough room in the target buffer. */ SVN_ERR(size_buffer(&ab->tbuf, &ab->tbuf_size, window->tview_len, ab->pool)); /* Prepare the source buffer for reading from the input stream. */ if (window->sview_offset != ab->sbuf_offset || window->sview_len > ab->sbuf_size) { char *old_sbuf = ab->sbuf; /* Make sure there's enough room. */ SVN_ERR(size_buffer(&ab->sbuf, &ab->sbuf_size, window->sview_len, ab->pool)); /* If the existing view overlaps with the new view, copy the * overlap to the beginning of the new buffer. */ if (ab->sbuf_offset + ab->sbuf_len > window->sview_offset) { apr_size_t start = (apr_size_t)(window->sview_offset - ab->sbuf_offset); memmove(ab->sbuf, old_sbuf + start, ab->sbuf_len - start); ab->sbuf_len -= start; } else ab->sbuf_len = 0; ab->sbuf_offset = window->sview_offset; } /* Read the remainder of the source view into the buffer. */ if (ab->sbuf_len < window->sview_len) { len = window->sview_len - ab->sbuf_len; err = svn_stream_read(ab->source, ab->sbuf + ab->sbuf_len, &len); if (err == SVN_NO_ERROR && len != window->sview_len - ab->sbuf_len) err = svn_error_create(SVN_ERR_INCOMPLETE_DATA, NULL, "Delta source ended unexpectedly"); if (err != SVN_NO_ERROR) return err; ab->sbuf_len = window->sview_len; } /* Apply the window instructions to the source view to generate the target view. */ len = window->tview_len; svn_txdelta_apply_instructions(window, ab->sbuf, ab->tbuf, &len); SVN_ERR_ASSERT(len == window->tview_len); /* Write out the output. */ /* ### We've also considered just adding two (optionally null) arguments to svn_stream_create(): read_checksum and write_checksum. Then instead of every caller updating an md5 context when it calls svn_stream_write() or svn_stream_read(), streams would do it automatically, and verify the checksum in svn_stream_closed(). But this might be overkill for issue #689; so for now we just update the context here. */ if (ab->result_digest) apr_md5_update(&(ab->md5_context), ab->tbuf, len); return svn_stream_write(ab->target, ab->tbuf, &len); }
/* Write a single change entry, path PATH, change CHANGE, to STREAM. Only include the node kind field if INCLUDE_NODE_KIND is true. Only include the mergeinfo-mod field if INCLUDE_MERGEINFO_MODS is true. All temporary allocations are in SCRATCH_POOL. */ static svn_error_t * write_change_entry(svn_stream_t *stream, const char *path, svn_fs_path_change2_t *change, svn_boolean_t include_node_kind, svn_boolean_t include_mergeinfo_mods, apr_pool_t *scratch_pool) { const char *idstr; const char *change_string = NULL; const char *kind_string = ""; const char *mergeinfo_string = ""; svn_stringbuf_t *buf; apr_size_t len; switch (change->change_kind) { case svn_fs_path_change_modify: change_string = ACTION_MODIFY; break; case svn_fs_path_change_add: change_string = ACTION_ADD; break; case svn_fs_path_change_delete: change_string = ACTION_DELETE; break; case svn_fs_path_change_replace: change_string = ACTION_REPLACE; break; case svn_fs_path_change_reset: change_string = ACTION_RESET; break; default: return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Invalid change type %d"), change->change_kind); } if (change->node_rev_id) idstr = svn_fs_fs__id_unparse(change->node_rev_id, scratch_pool)->data; else idstr = ACTION_RESET; if (include_node_kind) { SVN_ERR_ASSERT(change->node_kind == svn_node_dir || change->node_kind == svn_node_file); kind_string = apr_psprintf(scratch_pool, "-%s", change->node_kind == svn_node_dir ? SVN_FS_FS__KIND_DIR : SVN_FS_FS__KIND_FILE); } if (include_mergeinfo_mods && change->mergeinfo_mod != svn_tristate_unknown) mergeinfo_string = apr_psprintf(scratch_pool, " %s", change->mergeinfo_mod == svn_tristate_true ? FLAG_TRUE : FLAG_FALSE); buf = svn_stringbuf_createf(scratch_pool, "%s %s%s %s %s%s %s\n", idstr, change_string, kind_string, change->text_mod ? FLAG_TRUE : FLAG_FALSE, change->prop_mod ? FLAG_TRUE : FLAG_FALSE, mergeinfo_string, path); if (SVN_IS_VALID_REVNUM(change->copyfrom_rev)) { svn_stringbuf_appendcstr(buf, apr_psprintf(scratch_pool, "%ld %s", change->copyfrom_rev, change->copyfrom_path)); } svn_stringbuf_appendbyte(buf, '\n'); /* Write all change info in one write call. */ len = buf->len; return svn_error_trace(svn_stream_write(stream, buf->data, &len)); }
/* Implements svn_hash_write2 and svn_hash_write_incremental. */ static svn_error_t * hash_write(apr_hash_t *hash, apr_hash_t *oldhash, svn_stream_t *stream, const char *terminator, apr_pool_t *pool) { apr_pool_t *subpool; apr_size_t len; apr_array_header_t *list; int i; subpool = svn_pool_create(pool); list = svn_sort__hash(hash, svn_sort_compare_items_lexically, pool); for (i = 0; i < list->nelts; i++) { svn_sort__item_t *item = &APR_ARRAY_IDX(list, i, svn_sort__item_t); svn_string_t *valstr = item->value; svn_pool_clear(subpool); /* Don't output entries equal to the ones in oldhash, if present. */ if (oldhash) { svn_string_t *oldstr = apr_hash_get(oldhash, item->key, item->klen); if (oldstr && svn_string_compare(valstr, oldstr)) continue; } /* Write it out. */ SVN_ERR(svn_stream_printf(stream, subpool, "K %" APR_SSIZE_T_FMT "\n%s\n" "V %" APR_SIZE_T_FMT "\n", item->klen, (const char *) item->key, valstr->len)); len = valstr->len; SVN_ERR(svn_stream_write(stream, valstr->data, &len)); SVN_ERR(svn_stream_printf(stream, subpool, "\n")); } if (oldhash) { /* Output a deletion entry for each property in oldhash but not hash. */ list = svn_sort__hash(oldhash, svn_sort_compare_items_lexically, pool); for (i = 0; i < list->nelts; i++) { svn_sort__item_t *item = &APR_ARRAY_IDX(list, i, svn_sort__item_t); svn_pool_clear(subpool); /* If it's not present in the new hash, write out a D entry. */ if (! apr_hash_get(hash, item->key, item->klen)) SVN_ERR(svn_stream_printf(stream, subpool, "D %" APR_SSIZE_T_FMT "\n%s\n", item->klen, (const char *) item->key)); } } if (terminator) SVN_ERR(svn_stream_printf(stream, subpool, "%s\n", terminator)); svn_pool_destroy(subpool); return SVN_NO_ERROR; }
/* Writes out a git-like literal output of the compressed data in COMPRESSED_DATA to OUTPUT_STREAM, describing that its normal length is UNCOMPRESSED_SIZE. */ static svn_error_t * write_literal(svn_filesize_t uncompressed_size, svn_stream_t *compressed_data, svn_stream_t *output_stream, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *scratch_pool) { apr_size_t rd; SVN_ERR(svn_stream_seek(compressed_data, NULL)); /* Seek to start */ SVN_ERR(svn_stream_printf(output_stream, scratch_pool, "literal %" SVN_FILESIZE_T_FMT APR_EOL_STR, uncompressed_size)); do { char chunk[GIT_BASE85_CHUNKSIZE]; const unsigned char *next; apr_size_t left; rd = sizeof(chunk); if (cancel_func) SVN_ERR(cancel_func(cancel_baton)); SVN_ERR(svn_stream_read_full(compressed_data, chunk, &rd)); { apr_size_t one = 1; SVN_ERR(svn_stream_write(output_stream, &b85lenstr[rd-1], &one)); } left = rd; next = (void*)chunk; while (left) { char five[5]; unsigned info = 0; int n; apr_size_t five_sz; /* Push 4 bytes into the 32 bit info, when available */ for (n = 24; n >= 0 && left; n -= 8, next++, left--) { info |= (*next) << n; } /* Write out info as base85 */ for (n = 4; n >= 0; n--) { five[n] = b85str[info % 85]; info /= 85; } five_sz = 5; SVN_ERR(svn_stream_write(output_stream, five, &five_sz)); } SVN_ERR(svn_stream_puts(output_stream, APR_EOL_STR)); } while (rd == GIT_BASE85_CHUNKSIZE); return SVN_NO_ERROR; }