2 * stream.c: svn_stream operations
4 * ====================================================================
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
21 * ====================================================================
28 #include <apr_pools.h>
29 #include <apr_strings.h>
30 #include <apr_file_io.h>
31 #include <apr_errno.h>
36 #include "svn_pools.h"
38 #include "svn_error.h"
39 #include "svn_string.h"
41 #include "svn_checksum.h"
43 #include "svn_private_config.h"
44 #include "private/svn_error_private.h"
45 #include "private/svn_eol_private.h"
46 #include "private/svn_io_private.h"
47 #include "private/svn_subr_private.h"
52 svn_read_fn_t read_fn;
53 svn_stream_skip_fn_t skip_fn;
54 svn_write_fn_t write_fn;
55 svn_close_fn_t close_fn;
56 svn_stream_mark_fn_t mark_fn;
57 svn_stream_seek_fn_t seek_fn;
58 svn_stream__is_buffered_fn_t is_buffered_fn;
59 apr_file_t *file; /* Maybe NULL */
63 /*** Forward declarations. ***/
66 skip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_fn);
69 /*** Generic streams. ***/
72 svn_stream_create(void *baton, apr_pool_t *pool)
76 stream = apr_palloc(pool, sizeof(*stream));
77 stream->baton = baton;
78 stream->read_fn = NULL;
79 stream->skip_fn = NULL;
80 stream->write_fn = NULL;
81 stream->close_fn = NULL;
82 stream->mark_fn = NULL;
83 stream->seek_fn = NULL;
84 stream->is_buffered_fn = NULL;
91 svn_stream_set_baton(svn_stream_t *stream, void *baton)
93 stream->baton = baton;
98 svn_stream_set_read(svn_stream_t *stream, svn_read_fn_t read_fn)
100 stream->read_fn = read_fn;
104 svn_stream_set_skip(svn_stream_t *stream, svn_stream_skip_fn_t skip_fn)
106 stream->skip_fn = skip_fn;
110 svn_stream_set_write(svn_stream_t *stream, svn_write_fn_t write_fn)
112 stream->write_fn = write_fn;
116 svn_stream_set_close(svn_stream_t *stream, svn_close_fn_t close_fn)
118 stream->close_fn = close_fn;
122 svn_stream_set_mark(svn_stream_t *stream, svn_stream_mark_fn_t mark_fn)
124 stream->mark_fn = mark_fn;
128 svn_stream_set_seek(svn_stream_t *stream, svn_stream_seek_fn_t seek_fn)
130 stream->seek_fn = seek_fn;
134 svn_stream__set_is_buffered(svn_stream_t *stream,
135 svn_stream__is_buffered_fn_t is_buffered_fn)
137 stream->is_buffered_fn = is_buffered_fn;
141 svn_stream_read(svn_stream_t *stream, char *buffer, apr_size_t *len)
143 SVN_ERR_ASSERT(stream->read_fn != NULL);
144 return svn_error_trace(stream->read_fn(stream->baton, buffer, len));
149 svn_stream_skip(svn_stream_t *stream, apr_size_t len)
151 if (stream->skip_fn == NULL)
152 return svn_error_trace(
153 skip_default_handler(stream->baton, len, stream->read_fn));
155 return svn_error_trace(stream->skip_fn(stream->baton, len));
160 svn_stream_write(svn_stream_t *stream, const char *data, apr_size_t *len)
162 SVN_ERR_ASSERT(stream->write_fn != NULL);
163 return svn_error_trace(stream->write_fn(stream->baton, data, len));
168 svn_stream_reset(svn_stream_t *stream)
170 return svn_error_trace(
171 svn_stream_seek(stream, NULL));
175 svn_stream_supports_mark(svn_stream_t *stream)
177 return stream->mark_fn != NULL;
181 svn_stream_mark(svn_stream_t *stream, svn_stream_mark_t **mark,
184 if (stream->mark_fn == NULL)
185 return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
187 return svn_error_trace(stream->mark_fn(stream->baton, mark, pool));
191 svn_stream_seek(svn_stream_t *stream, const svn_stream_mark_t *mark)
193 if (stream->seek_fn == NULL)
194 return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
196 return svn_error_trace(stream->seek_fn(stream->baton, mark));
200 svn_stream__is_buffered(svn_stream_t *stream)
202 if (stream->is_buffered_fn == NULL)
205 return stream->is_buffered_fn(stream->baton);
209 svn_stream_close(svn_stream_t *stream)
211 if (stream->close_fn == NULL)
213 return svn_error_trace(stream->close_fn(stream->baton));
217 svn_stream_puts(svn_stream_t *stream,
222 return svn_error_trace(svn_stream_write(stream, str, &len));
226 svn_stream_printf(svn_stream_t *stream,
235 message = apr_pvsprintf(pool, fmt, ap);
238 return svn_error_trace(svn_stream_puts(stream, message));
243 svn_stream_printf_from_utf8(svn_stream_t *stream,
244 const char *encoding,
249 const char *message, *translated;
253 message = apr_pvsprintf(pool, fmt, ap);
256 SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated, message, encoding,
259 return svn_error_trace(svn_stream_puts(stream, translated));
262 /* Size that 90% of the lines we encounter will be not longer than.
263 used by stream_readline_bytewise() and stream_readline_chunky().
265 #define LINE_CHUNK_SIZE 80
267 /* Guts of svn_stream_readline().
268 * Returns the line read from STREAM in *STRINGBUF, and indicates
269 * end-of-file in *EOF. If DETECT_EOL is TRUE, the end-of-line indicator
270 * is detected automatically and returned in *EOL.
271 * If DETECT_EOL is FALSE, *EOL must point to the desired end-of-line
272 * indicator. STRINGBUF is allocated in POOL. */
274 stream_readline_bytewise(svn_stringbuf_t **stringbuf,
277 svn_stream_t *stream,
280 svn_stringbuf_t *str;
285 /* Since we're reading one character at a time, let's at least
286 optimize for the 90% case. 90% of the time, we can avoid the
287 stringbuf ever having to realloc() itself if we start it out at
289 str = svn_stringbuf_create_ensure(LINE_CHUNK_SIZE, pool);
291 /* Read into STR up to and including the next EOL sequence. */
296 SVN_ERR(svn_stream_read(stream, &c, &numbytes));
299 /* a 'short' read means the stream has run out. */
310 svn_stringbuf_appendbyte(str, c);
314 svn_stringbuf_chop(str, match - eol);
321 stream_readline_chunky(svn_stringbuf_t **stringbuf,
324 svn_stream_t *stream,
327 /* Read larger chunks of data at once into this buffer and scan
328 * that for EOL. A good chunk size should be about 80 chars since
329 * most text lines will be shorter. However, don't use a much
330 * larger value because filling the buffer from the stream takes
333 char buffer[LINE_CHUNK_SIZE+1];
336 svn_stream_mark_t *mark;
339 apr_size_t total_parsed = 0;
341 /* invariant for this call */
342 const size_t eol_len = strlen(eol);
344 /* Remember the line start so this plus the line length will be
345 * the position to move to at the end of this function.
347 SVN_ERR(svn_stream_mark(stream, &mark, pool));
349 /* Read the first chunk. */
350 numbytes = LINE_CHUNK_SIZE;
351 SVN_ERR(svn_stream_read(stream, buffer, &numbytes));
352 buffer[numbytes] = '\0';
354 /* Look for the EOL in this first chunk. If we find it, we are done here.
356 eol_pos = strstr(buffer, eol);
359 *stringbuf = svn_stringbuf_ncreate(buffer, eol_pos - buffer, pool);
360 total_parsed = eol_pos - buffer + eol_len;
362 else if (numbytes < LINE_CHUNK_SIZE)
364 /* We hit EOF but not EOL.
366 *stringbuf = svn_stringbuf_ncreate(buffer, numbytes, pool);
372 /* A larger buffer for the string is needed. */
373 svn_stringbuf_t *str;
374 str = svn_stringbuf_create_ensure(2*LINE_CHUNK_SIZE, pool);
375 svn_stringbuf_appendbytes(str, buffer, numbytes);
378 /* Loop reading chunks until an EOL was found. If we hit EOF, fall
379 * back to the standard implementation. */
382 /* Append the next chunk to the string read so far.
384 svn_stringbuf_ensure(str, str->len + LINE_CHUNK_SIZE);
385 numbytes = LINE_CHUNK_SIZE;
386 SVN_ERR(svn_stream_read(stream, str->data + str->len, &numbytes));
387 str->len += numbytes;
388 str->data[str->len] = '\0';
390 /* Look for the EOL in the new data plus the last part of the
391 * previous chunk because the EOL may span over the boundary
392 * between both chunks.
394 eol_pos = strstr(str->data + str->len - numbytes - (eol_len-1), eol);
396 if ((numbytes < LINE_CHUNK_SIZE) && (eol_pos == NULL))
398 /* We hit EOF instead of EOL. */
403 while (eol_pos == NULL);
405 /* Number of bytes we actually consumed (i.e. line + EOF).
406 * We need to "return" the rest to the stream by moving its
409 total_parsed = eol_pos - str->data + eol_len;
411 /* Terminate the string at the EOL postion and return it. */
412 str->len = eol_pos - str->data;
413 str->data[str->len] = 0;
416 /* Move the stream read pointer to the first position behind the EOL.
418 SVN_ERR(svn_stream_seek(stream, mark));
419 return svn_error_trace(svn_stream_skip(stream, total_parsed));
422 /* Guts of svn_stream_readline().
423 * Returns the line read from STREAM in *STRINGBUF, and indicates
424 * end-of-file in *EOF. EOL must point to the desired end-of-line
425 * indicator. STRINGBUF is allocated in POOL. */
427 stream_readline(svn_stringbuf_t **stringbuf,
430 svn_stream_t *stream,
435 /* Often, we operate on APR file or string-based streams and know what
436 * EOL we are looking for. Optimize that common case.
438 if (svn_stream_supports_mark(stream) &&
439 svn_stream__is_buffered(stream))
441 /* We can efficiently read chunks speculatively and reposition the
442 * stream pointer to the end of the line once we found that.
444 SVN_ERR(stream_readline_chunky(stringbuf,
452 /* Use the standard byte-byte implementation.
454 SVN_ERR(stream_readline_bytewise(stringbuf,
465 svn_stream_readline(svn_stream_t *stream,
466 svn_stringbuf_t **stringbuf,
471 return svn_error_trace(stream_readline(stringbuf, eof, eol, stream,
475 svn_error_t *svn_stream_copy3(svn_stream_t *from, svn_stream_t *to,
476 svn_cancel_func_t cancel_func,
478 apr_pool_t *scratch_pool)
480 char *buf = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE);
484 /* Read and write chunks until we get a short read, indicating the
485 end of the stream. (We can't get a short write without an
486 associated error.) */
489 apr_size_t len = SVN__STREAM_CHUNK_SIZE;
493 err = cancel_func(cancel_baton);
498 err = svn_stream_read(from, buf, &len);
503 err = svn_stream_write(to, buf, &len);
505 if (err || (len != SVN__STREAM_CHUNK_SIZE))
509 err2 = svn_error_compose_create(svn_stream_close(from),
510 svn_stream_close(to));
512 return svn_error_compose_create(err, err2);
516 svn_stream_contents_same2(svn_boolean_t *same,
517 svn_stream_t *stream1,
518 svn_stream_t *stream2,
521 char *buf1 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
522 char *buf2 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
523 apr_size_t bytes_read1 = SVN__STREAM_CHUNK_SIZE;
524 apr_size_t bytes_read2 = SVN__STREAM_CHUNK_SIZE;
525 svn_error_t *err = NULL;
527 *same = TRUE; /* assume TRUE, until disproved below */
528 while (bytes_read1 == SVN__STREAM_CHUNK_SIZE
529 && bytes_read2 == SVN__STREAM_CHUNK_SIZE)
531 err = svn_stream_read(stream1, buf1, &bytes_read1);
534 err = svn_stream_read(stream2, buf2, &bytes_read2);
538 if ((bytes_read1 != bytes_read2)
539 || (memcmp(buf1, buf2, bytes_read1)))
546 return svn_error_compose_create(err,
547 svn_error_compose_create(
548 svn_stream_close(stream1),
549 svn_stream_close(stream2)));
553 /*** Stream implementation utilities ***/
555 /* Skip data from any stream by reading and simply discarding it. */
557 skip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_fn)
559 apr_size_t bytes_read = 1;
561 apr_size_t to_read = len;
563 while ((to_read > 0) && (bytes_read > 0))
565 bytes_read = sizeof(buffer) < to_read ? sizeof(buffer) : to_read;
566 SVN_ERR(read_fn(baton, buffer, &bytes_read));
567 to_read -= bytes_read;
575 /*** Generic readable empty stream ***/
578 read_handler_empty(void *baton, char *buffer, apr_size_t *len)
585 write_handler_empty(void *baton, const char *data, apr_size_t *len)
591 mark_handler_empty(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
593 *mark = NULL; /* Seek to start of stream marker */
598 seek_handler_empty(void *baton, const svn_stream_mark_t *mark)
604 is_buffered_handler_empty(void *baton)
611 svn_stream_empty(apr_pool_t *pool)
613 svn_stream_t *stream;
615 stream = svn_stream_create(NULL, pool);
616 svn_stream_set_read(stream, read_handler_empty);
617 svn_stream_set_write(stream, write_handler_empty);
618 svn_stream_set_mark(stream, mark_handler_empty);
619 svn_stream_set_seek(stream, seek_handler_empty);
620 svn_stream__set_is_buffered(stream, is_buffered_handler_empty);
626 /*** Stream duplication support ***/
634 write_handler_tee(void *baton, const char *data, apr_size_t *len)
636 struct baton_tee *bt = baton;
638 SVN_ERR(svn_stream_write(bt->out1, data, len));
639 SVN_ERR(svn_stream_write(bt->out2, data, len));
646 close_handler_tee(void *baton)
648 struct baton_tee *bt = baton;
650 SVN_ERR(svn_stream_close(bt->out1));
651 SVN_ERR(svn_stream_close(bt->out2));
658 svn_stream_tee(svn_stream_t *out1,
662 struct baton_tee *baton;
663 svn_stream_t *stream;
671 baton = apr_palloc(pool, sizeof(*baton));
674 stream = svn_stream_create(baton, pool);
675 svn_stream_set_write(stream, write_handler_tee);
676 svn_stream_set_close(stream, close_handler_tee);
683 /*** Ownership detaching stream ***/
686 read_handler_disown(void *baton, char *buffer, apr_size_t *len)
688 return svn_error_trace(svn_stream_read(baton, buffer, len));
692 skip_handler_disown(void *baton, apr_size_t len)
694 return svn_error_trace(svn_stream_skip(baton, len));
698 write_handler_disown(void *baton, const char *buffer, apr_size_t *len)
700 return svn_error_trace(svn_stream_write(baton, buffer, len));
704 mark_handler_disown(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
706 return svn_error_trace(svn_stream_mark(baton, mark, pool));
710 seek_handler_disown(void *baton, const svn_stream_mark_t *mark)
712 return svn_error_trace(svn_stream_seek(baton, mark));
716 is_buffered_handler_disown(void *baton)
718 return svn_stream__is_buffered(baton);
722 svn_stream_disown(svn_stream_t *stream, apr_pool_t *pool)
724 svn_stream_t *s = svn_stream_create(stream, pool);
726 svn_stream_set_read(s, read_handler_disown);
727 svn_stream_set_skip(s, skip_handler_disown);
728 svn_stream_set_write(s, write_handler_disown);
729 svn_stream_set_mark(s, mark_handler_disown);
730 svn_stream_set_seek(s, seek_handler_disown);
731 svn_stream__set_is_buffered(s, is_buffered_handler_disown);
738 /*** Generic stream for APR files ***/
744 /* svn_stream_mark_t for streams backed by APR files. */
750 read_handler_apr(void *baton, char *buffer, apr_size_t *len)
752 struct baton_apr *btn = baton;
758 err = svn_io_file_getc(buffer, btn->file, btn->pool);
762 if (APR_STATUS_IS_EOF(err->apr_err))
764 svn_error_clear(err);
770 err = svn_io_file_read_full2(btn->file, buffer, *len, len,
773 return svn_error_trace(err);
777 skip_handler_apr(void *baton, apr_size_t len)
779 struct baton_apr *btn = baton;
780 apr_off_t offset = len;
782 return svn_error_trace(
783 svn_io_file_seek(btn->file, APR_CUR, &offset, btn->pool));
787 write_handler_apr(void *baton, const char *data, apr_size_t *len)
789 struct baton_apr *btn = baton;
794 err = svn_io_file_putc(*data, btn->file, btn->pool);
799 err = svn_io_file_write_full(btn->file, data, *len, len, btn->pool);
801 return svn_error_trace(err);
805 close_handler_apr(void *baton)
807 struct baton_apr *btn = baton;
809 return svn_error_trace(svn_io_file_close(btn->file, btn->pool));
813 mark_handler_apr(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
815 struct baton_apr *btn = baton;
816 struct mark_apr *mark_apr;
818 mark_apr = apr_palloc(pool, sizeof(*mark_apr));
820 SVN_ERR(svn_io_file_seek(btn->file, APR_CUR, &mark_apr->off, btn->pool));
821 *mark = (svn_stream_mark_t *)mark_apr;
826 seek_handler_apr(void *baton, const svn_stream_mark_t *mark)
828 struct baton_apr *btn = baton;
829 apr_off_t offset = (mark != NULL) ? ((const struct mark_apr *)mark)->off : 0;
831 SVN_ERR(svn_io_file_seek(btn->file, APR_SET, &offset, btn->pool));
837 is_buffered_handler_apr(void *baton)
839 struct baton_apr *btn = baton;
840 return (apr_file_flags_get(btn->file) & APR_BUFFERED) != 0;
844 svn_stream_open_readonly(svn_stream_t **stream,
846 apr_pool_t *result_pool,
847 apr_pool_t *scratch_pool)
851 SVN_ERR(svn_io_file_open(&file, path, APR_READ | APR_BUFFERED,
852 APR_OS_DEFAULT, result_pool));
853 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
860 svn_stream_open_writable(svn_stream_t **stream,
862 apr_pool_t *result_pool,
863 apr_pool_t *scratch_pool)
867 SVN_ERR(svn_io_file_open(&file, path,
872 APR_OS_DEFAULT, result_pool));
873 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
880 svn_stream_open_unique(svn_stream_t **stream,
881 const char **temp_path,
883 svn_io_file_del_t delete_when,
884 apr_pool_t *result_pool,
885 apr_pool_t *scratch_pool)
889 SVN_ERR(svn_io_open_unique_file3(&file, temp_path, dirpath,
890 delete_when, result_pool, scratch_pool));
891 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
898 svn_stream_from_aprfile2(apr_file_t *file,
899 svn_boolean_t disown,
902 struct baton_apr *baton;
903 svn_stream_t *stream;
906 return svn_stream_empty(pool);
908 baton = apr_palloc(pool, sizeof(*baton));
911 stream = svn_stream_create(baton, pool);
912 svn_stream_set_read(stream, read_handler_apr);
913 svn_stream_set_write(stream, write_handler_apr);
914 svn_stream_set_skip(stream, skip_handler_apr);
915 svn_stream_set_mark(stream, mark_handler_apr);
916 svn_stream_set_seek(stream, seek_handler_apr);
917 svn_stream__set_is_buffered(stream, is_buffered_handler_apr);
921 svn_stream_set_close(stream, close_handler_apr);
927 svn_stream__aprfile(svn_stream_t *stream)
933 /* Compressed stream support */
935 #define ZBUFFER_SIZE 4096 /* The size of the buffer the
936 compressed stream uses to read from
937 the substream. Basically an
938 arbitrary value, picked to be about
942 z_stream *in; /* compressed stream for reading */
943 z_stream *out; /* compressed stream for writing */
944 svn_read_fn_t read; /* substream's read function */
945 svn_write_fn_t write; /* substream's write function */
946 svn_close_fn_t close; /* substream's close function */
947 void *read_buffer; /* buffer used for reading from
949 int read_flush; /* what flush mode to use while
951 apr_pool_t *pool; /* The pool this baton is allocated
953 void *subbaton; /* The substream's baton */
956 /* zlib alloc function. opaque is the pool we need. */
958 zalloc(voidpf opaque, uInt items, uInt size)
960 apr_pool_t *pool = opaque;
962 return apr_palloc(pool, items * size);
965 /* zlib free function */
967 zfree(voidpf opaque, voidpf address)
969 /* Empty, since we allocate on the pool */
972 /* Helper function to figure out the sync mode */
974 read_helper_gz(svn_read_fn_t read_fn,
977 uInt *len, int *zflush)
979 uInt orig_len = *len;
981 /* There's no reason this value should grow bigger than the range of
982 uInt, but Subversion's API requires apr_size_t. */
983 apr_size_t apr_len = (apr_size_t) *len;
985 SVN_ERR((*read_fn)(baton, buffer, &apr_len));
987 /* Type cast back to uInt type that zlib uses. On LP64 platforms
988 apr_size_t will be bigger than uInt. */
989 *len = (uInt) apr_len;
991 /* I wanted to use Z_FINISH here, but we need to know our buffer is
993 *zflush = (*len) < orig_len ? Z_SYNC_FLUSH : Z_SYNC_FLUSH;
998 /* Handle reading from a compressed stream */
1000 read_handler_gz(void *baton, char *buffer, apr_size_t *len)
1002 struct zbaton *btn = baton;
1005 if (btn->in == NULL)
1007 btn->in = apr_palloc(btn->pool, sizeof(z_stream));
1008 btn->in->zalloc = zalloc;
1009 btn->in->zfree = zfree;
1010 btn->in->opaque = btn->pool;
1011 btn->read_buffer = apr_palloc(btn->pool, ZBUFFER_SIZE);
1012 btn->in->next_in = btn->read_buffer;
1013 btn->in->avail_in = ZBUFFER_SIZE;
1015 SVN_ERR(read_helper_gz(btn->read, btn->subbaton, btn->read_buffer,
1016 &btn->in->avail_in, &btn->read_flush));
1018 zerr = inflateInit(btn->in);
1019 SVN_ERR(svn_error__wrap_zlib(zerr, "inflateInit", btn->in->msg));
1022 btn->in->next_out = (Bytef *) buffer;
1023 btn->in->avail_out = (uInt) *len;
1025 while (btn->in->avail_out > 0)
1027 if (btn->in->avail_in <= 0)
1029 btn->in->avail_in = ZBUFFER_SIZE;
1030 btn->in->next_in = btn->read_buffer;
1031 SVN_ERR(read_helper_gz(btn->read, btn->subbaton, btn->read_buffer,
1032 &btn->in->avail_in, &btn->read_flush));
1035 /* Short read means underlying stream has run out. */
1036 if (btn->in->avail_in == 0)
1039 return SVN_NO_ERROR;
1042 zerr = inflate(btn->in, btn->read_flush);
1043 if (zerr == Z_STREAM_END)
1045 else if (zerr != Z_OK)
1046 return svn_error_trace(svn_error__wrap_zlib(zerr, "inflate",
1050 *len -= btn->in->avail_out;
1051 return SVN_NO_ERROR;
1054 /* Compress data and write it to the substream */
1055 static svn_error_t *
1056 write_handler_gz(void *baton, const char *buffer, apr_size_t *len)
1058 struct zbaton *btn = baton;
1059 apr_pool_t *subpool;
1061 apr_size_t buf_size, write_len;
1064 if (btn->out == NULL)
1066 btn->out = apr_palloc(btn->pool, sizeof(z_stream));
1067 btn->out->zalloc = zalloc;
1068 btn->out->zfree = zfree;
1069 btn->out->opaque = btn->pool;
1071 zerr = deflateInit(btn->out, Z_DEFAULT_COMPRESSION);
1072 SVN_ERR(svn_error__wrap_zlib(zerr, "deflateInit", btn->out->msg));
1075 /* The largest buffer we should need is 0.1% larger than the
1076 compressed data, + 12 bytes. This info comes from zlib.h. */
1077 buf_size = *len + (*len / 1000) + 13;
1078 subpool = svn_pool_create(btn->pool);
1079 write_buf = apr_palloc(subpool, buf_size);
1081 btn->out->next_in = (Bytef *) buffer; /* Casting away const! */
1082 btn->out->avail_in = (uInt) *len;
1084 while (btn->out->avail_in > 0)
1086 btn->out->next_out = write_buf;
1087 btn->out->avail_out = (uInt) buf_size;
1089 zerr = deflate(btn->out, Z_NO_FLUSH);
1090 SVN_ERR(svn_error__wrap_zlib(zerr, "deflate", btn->out->msg));
1091 write_len = buf_size - btn->out->avail_out;
1093 SVN_ERR(btn->write(btn->subbaton, write_buf, &write_len));
1096 svn_pool_destroy(subpool);
1098 return SVN_NO_ERROR;
1101 /* Handle flushing and closing the stream */
1102 static svn_error_t *
1103 close_handler_gz(void *baton)
1105 struct zbaton *btn = baton;
1108 if (btn->in != NULL)
1110 zerr = inflateEnd(btn->in);
1111 SVN_ERR(svn_error__wrap_zlib(zerr, "inflateEnd", btn->in->msg));
1114 if (btn->out != NULL)
1117 apr_size_t write_len;
1119 buf = apr_palloc(btn->pool, ZBUFFER_SIZE);
1123 btn->out->next_out = buf;
1124 btn->out->avail_out = ZBUFFER_SIZE;
1126 zerr = deflate(btn->out, Z_FINISH);
1127 if (zerr != Z_STREAM_END && zerr != Z_OK)
1128 return svn_error_trace(svn_error__wrap_zlib(zerr, "deflate",
1130 write_len = ZBUFFER_SIZE - btn->out->avail_out;
1132 SVN_ERR(btn->write(btn->subbaton, buf, &write_len));
1133 if (zerr == Z_STREAM_END)
1137 zerr = deflateEnd(btn->out);
1138 SVN_ERR(svn_error__wrap_zlib(zerr, "deflateEnd", btn->out->msg));
1141 if (btn->close != NULL)
1142 return svn_error_trace(btn->close(btn->subbaton));
1144 return SVN_NO_ERROR;
1149 svn_stream_compressed(svn_stream_t *stream, apr_pool_t *pool)
1151 struct svn_stream_t *zstream;
1152 struct zbaton *baton;
1154 assert(stream != NULL);
1156 baton = apr_palloc(pool, sizeof(*baton));
1157 baton->in = baton->out = NULL;
1158 baton->read = stream->read_fn;
1159 baton->write = stream->write_fn;
1160 baton->close = stream->close_fn;
1161 baton->subbaton = stream->baton;
1163 baton->read_buffer = NULL;
1164 baton->read_flush = Z_SYNC_FLUSH;
1166 zstream = svn_stream_create(baton, pool);
1167 svn_stream_set_read(zstream, read_handler_gz);
1168 svn_stream_set_write(zstream, write_handler_gz);
1169 svn_stream_set_close(zstream, close_handler_gz);
1175 /* Checksummed stream support */
1177 struct checksum_stream_baton
1179 svn_checksum_ctx_t *read_ctx, *write_ctx;
1180 svn_checksum_t **read_checksum; /* Output value. */
1181 svn_checksum_t **write_checksum; /* Output value. */
1182 svn_stream_t *proxy;
1184 /* True if more data should be read when closing the stream. */
1185 svn_boolean_t read_more;
1187 /* Pool to allocate read buffer and output values from. */
1191 static svn_error_t *
1192 read_handler_checksum(void *baton, char *buffer, apr_size_t *len)
1194 struct checksum_stream_baton *btn = baton;
1195 apr_size_t saved_len = *len;
1197 SVN_ERR(svn_stream_read(btn->proxy, buffer, len));
1199 if (btn->read_checksum)
1200 SVN_ERR(svn_checksum_update(btn->read_ctx, buffer, *len));
1202 if (saved_len != *len)
1203 btn->read_more = FALSE;
1205 return SVN_NO_ERROR;
1209 static svn_error_t *
1210 write_handler_checksum(void *baton, const char *buffer, apr_size_t *len)
1212 struct checksum_stream_baton *btn = baton;
1214 if (btn->write_checksum && *len > 0)
1215 SVN_ERR(svn_checksum_update(btn->write_ctx, buffer, *len));
1217 return svn_error_trace(svn_stream_write(btn->proxy, buffer, len));
1221 static svn_error_t *
1222 close_handler_checksum(void *baton)
1224 struct checksum_stream_baton *btn = baton;
1226 /* If we're supposed to drain the stream, do so before finalizing the
1230 char *buf = apr_palloc(btn->pool, SVN__STREAM_CHUNK_SIZE);
1231 apr_size_t len = SVN__STREAM_CHUNK_SIZE;
1235 SVN_ERR(read_handler_checksum(baton, buf, &len));
1237 while (btn->read_more);
1241 SVN_ERR(svn_checksum_final(btn->read_checksum, btn->read_ctx, btn->pool));
1244 SVN_ERR(svn_checksum_final(btn->write_checksum, btn->write_ctx, btn->pool));
1246 return svn_error_trace(svn_stream_close(btn->proxy));
1251 svn_stream_checksummed2(svn_stream_t *stream,
1252 svn_checksum_t **read_checksum,
1253 svn_checksum_t **write_checksum,
1254 svn_checksum_kind_t checksum_kind,
1255 svn_boolean_t read_all,
1259 struct checksum_stream_baton *baton;
1261 if (read_checksum == NULL && write_checksum == NULL)
1264 baton = apr_palloc(pool, sizeof(*baton));
1266 baton->read_ctx = svn_checksum_ctx_create(checksum_kind, pool);
1268 baton->read_ctx = NULL;
1271 baton->write_ctx = svn_checksum_ctx_create(checksum_kind, pool);
1273 baton->write_ctx = NULL;
1275 baton->read_checksum = read_checksum;
1276 baton->write_checksum = write_checksum;
1277 baton->proxy = stream;
1278 baton->read_more = read_all;
1281 s = svn_stream_create(baton, pool);
1282 svn_stream_set_read(s, read_handler_checksum);
1283 svn_stream_set_write(s, write_handler_checksum);
1284 svn_stream_set_close(s, close_handler_checksum);
1288 struct md5_stream_baton
1290 const unsigned char **read_digest;
1291 const unsigned char **write_digest;
1292 svn_checksum_t *read_checksum;
1293 svn_checksum_t *write_checksum;
1294 svn_stream_t *proxy;
1298 static svn_error_t *
1299 read_handler_md5(void *baton, char *buffer, apr_size_t *len)
1301 struct md5_stream_baton *btn = baton;
1302 return svn_error_trace(svn_stream_read(btn->proxy, buffer, len));
1305 static svn_error_t *
1306 skip_handler_md5(void *baton, apr_size_t len)
1308 struct md5_stream_baton *btn = baton;
1309 return svn_error_trace(svn_stream_skip(btn->proxy, len));
1312 static svn_error_t *
1313 write_handler_md5(void *baton, const char *buffer, apr_size_t *len)
1315 struct md5_stream_baton *btn = baton;
1316 return svn_error_trace(svn_stream_write(btn->proxy, buffer, len));
1319 static svn_error_t *
1320 close_handler_md5(void *baton)
1322 struct md5_stream_baton *btn = baton;
1324 SVN_ERR(svn_stream_close(btn->proxy));
1326 if (btn->read_digest)
1328 = apr_pmemdup(btn->pool, btn->read_checksum->digest,
1329 APR_MD5_DIGESTSIZE);
1331 if (btn->write_digest)
1333 = apr_pmemdup(btn->pool, btn->write_checksum->digest,
1334 APR_MD5_DIGESTSIZE);
1336 return SVN_NO_ERROR;
1341 svn_stream_checksummed(svn_stream_t *stream,
1342 const unsigned char **read_digest,
1343 const unsigned char **write_digest,
1344 svn_boolean_t read_all,
1348 struct md5_stream_baton *baton;
1350 if (! read_digest && ! write_digest)
1353 baton = apr_palloc(pool, sizeof(*baton));
1354 baton->read_digest = read_digest;
1355 baton->write_digest = write_digest;
1358 /* Set BATON->proxy to a stream that will fill in BATON->read_checksum
1359 * and BATON->write_checksum (if we want them) when it is closed. */
1361 = svn_stream_checksummed2(stream,
1362 read_digest ? &baton->read_checksum : NULL,
1363 write_digest ? &baton->write_checksum : NULL,
1367 /* Create a stream that will forward its read/write/close operations to
1368 * BATON->proxy and will fill in *READ_DIGEST and *WRITE_DIGEST (if we
1369 * want them) after it closes BATON->proxy. */
1370 s = svn_stream_create(baton, pool);
1371 svn_stream_set_read(s, read_handler_md5);
1372 svn_stream_set_skip(s, skip_handler_md5);
1373 svn_stream_set_write(s, write_handler_md5);
1374 svn_stream_set_close(s, close_handler_md5);
1381 /* Miscellaneous stream functions. */
1382 struct stringbuf_stream_baton
1384 svn_stringbuf_t *str;
1385 apr_size_t amt_read;
1388 /* svn_stream_mark_t for streams backed by stringbufs. */
1389 struct stringbuf_stream_mark {
1393 static svn_error_t *
1394 read_handler_stringbuf(void *baton, char *buffer, apr_size_t *len)
1396 struct stringbuf_stream_baton *btn = baton;
1397 apr_size_t left_to_read = btn->str->len - btn->amt_read;
1399 *len = (*len > left_to_read) ? left_to_read : *len;
1400 memcpy(buffer, btn->str->data + btn->amt_read, *len);
1401 btn->amt_read += *len;
1402 return SVN_NO_ERROR;
1405 static svn_error_t *
1406 skip_handler_stringbuf(void *baton, apr_size_t len)
1408 struct stringbuf_stream_baton *btn = baton;
1409 apr_size_t left_to_read = btn->str->len - btn->amt_read;
1411 len = (len > left_to_read) ? left_to_read : len;
1412 btn->amt_read += len;
1413 return SVN_NO_ERROR;
1416 static svn_error_t *
1417 write_handler_stringbuf(void *baton, const char *data, apr_size_t *len)
1419 struct stringbuf_stream_baton *btn = baton;
1421 svn_stringbuf_appendbytes(btn->str, data, *len);
1422 return SVN_NO_ERROR;
1425 static svn_error_t *
1426 mark_handler_stringbuf(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
1428 struct stringbuf_stream_baton *btn;
1429 struct stringbuf_stream_mark *stringbuf_stream_mark;
1433 stringbuf_stream_mark = apr_palloc(pool, sizeof(*stringbuf_stream_mark));
1434 stringbuf_stream_mark->pos = btn->amt_read;
1435 *mark = (svn_stream_mark_t *)stringbuf_stream_mark;
1436 return SVN_NO_ERROR;
1439 static svn_error_t *
1440 seek_handler_stringbuf(void *baton, const svn_stream_mark_t *mark)
1442 struct stringbuf_stream_baton *btn = baton;
1446 const struct stringbuf_stream_mark *stringbuf_stream_mark;
1448 stringbuf_stream_mark = (const struct stringbuf_stream_mark *)mark;
1449 btn->amt_read = stringbuf_stream_mark->pos;
1454 return SVN_NO_ERROR;
1457 static svn_boolean_t
1458 is_buffered_handler_stringbuf(void *baton)
1464 svn_stream_from_stringbuf(svn_stringbuf_t *str,
1467 svn_stream_t *stream;
1468 struct stringbuf_stream_baton *baton;
1471 return svn_stream_empty(pool);
1473 baton = apr_palloc(pool, sizeof(*baton));
1475 baton->amt_read = 0;
1476 stream = svn_stream_create(baton, pool);
1477 svn_stream_set_read(stream, read_handler_stringbuf);
1478 svn_stream_set_skip(stream, skip_handler_stringbuf);
1479 svn_stream_set_write(stream, write_handler_stringbuf);
1480 svn_stream_set_mark(stream, mark_handler_stringbuf);
1481 svn_stream_set_seek(stream, seek_handler_stringbuf);
1482 svn_stream__set_is_buffered(stream, is_buffered_handler_stringbuf);
1486 struct string_stream_baton
1488 const svn_string_t *str;
1489 apr_size_t amt_read;
1492 /* svn_stream_mark_t for streams backed by stringbufs. */
1493 struct string_stream_mark {
1497 static svn_error_t *
1498 read_handler_string(void *baton, char *buffer, apr_size_t *len)
1500 struct string_stream_baton *btn = baton;
1501 apr_size_t left_to_read = btn->str->len - btn->amt_read;
1503 *len = (*len > left_to_read) ? left_to_read : *len;
1504 memcpy(buffer, btn->str->data + btn->amt_read, *len);
1505 btn->amt_read += *len;
1506 return SVN_NO_ERROR;
1509 static svn_error_t *
1510 mark_handler_string(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
1512 struct string_stream_baton *btn;
1513 struct string_stream_mark *marker;
1517 marker = apr_palloc(pool, sizeof(*marker));
1518 marker->pos = btn->amt_read;
1519 *mark = (svn_stream_mark_t *)marker;
1520 return SVN_NO_ERROR;
1523 static svn_error_t *
1524 seek_handler_string(void *baton, const svn_stream_mark_t *mark)
1526 struct string_stream_baton *btn = baton;
1530 const struct string_stream_mark *marker;
1532 marker = (const struct string_stream_mark *)mark;
1533 btn->amt_read = marker->pos;
1538 return SVN_NO_ERROR;
1541 static svn_error_t *
1542 skip_handler_string(void *baton, apr_size_t len)
1544 struct string_stream_baton *btn = baton;
1545 apr_size_t left_to_read = btn->str->len - btn->amt_read;
1547 len = (len > left_to_read) ? left_to_read : len;
1548 btn->amt_read += len;
1549 return SVN_NO_ERROR;
1552 static svn_boolean_t
1553 is_buffered_handler_string(void *baton)
1559 svn_stream_from_string(const svn_string_t *str,
1562 svn_stream_t *stream;
1563 struct string_stream_baton *baton;
1566 return svn_stream_empty(pool);
1568 baton = apr_palloc(pool, sizeof(*baton));
1570 baton->amt_read = 0;
1571 stream = svn_stream_create(baton, pool);
1572 svn_stream_set_read(stream, read_handler_string);
1573 svn_stream_set_mark(stream, mark_handler_string);
1574 svn_stream_set_seek(stream, seek_handler_string);
1575 svn_stream_set_skip(stream, skip_handler_string);
1576 svn_stream__set_is_buffered(stream, is_buffered_handler_string);
1582 svn_stream_for_stdin(svn_stream_t **in, apr_pool_t *pool)
1584 apr_file_t *stdin_file;
1585 apr_status_t apr_err;
1587 apr_err = apr_file_open_stdin(&stdin_file, pool);
1589 return svn_error_wrap_apr(apr_err, "Can't open stdin");
1591 *in = svn_stream_from_aprfile2(stdin_file, TRUE, pool);
1593 return SVN_NO_ERROR;
1598 svn_stream_for_stdout(svn_stream_t **out, apr_pool_t *pool)
1600 apr_file_t *stdout_file;
1601 apr_status_t apr_err;
1603 apr_err = apr_file_open_stdout(&stdout_file, pool);
1605 return svn_error_wrap_apr(apr_err, "Can't open stdout");
1607 *out = svn_stream_from_aprfile2(stdout_file, TRUE, pool);
1609 return SVN_NO_ERROR;
1614 svn_stream_for_stderr(svn_stream_t **err, apr_pool_t *pool)
1616 apr_file_t *stderr_file;
1617 apr_status_t apr_err;
1619 apr_err = apr_file_open_stderr(&stderr_file, pool);
1621 return svn_error_wrap_apr(apr_err, "Can't open stderr");
1623 *err = svn_stream_from_aprfile2(stderr_file, TRUE, pool);
1625 return SVN_NO_ERROR;
1630 svn_string_from_stream(svn_string_t **result,
1631 svn_stream_t *stream,
1632 apr_pool_t *result_pool,
1633 apr_pool_t *scratch_pool)
1635 svn_stringbuf_t *work = svn_stringbuf_create_ensure(SVN__STREAM_CHUNK_SIZE,
1637 char *buffer = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE);
1641 apr_size_t len = SVN__STREAM_CHUNK_SIZE;
1643 SVN_ERR(svn_stream_read(stream, buffer, &len));
1644 svn_stringbuf_appendbytes(work, buffer, len);
1646 if (len < SVN__STREAM_CHUNK_SIZE)
1650 SVN_ERR(svn_stream_close(stream));
1652 *result = apr_palloc(result_pool, sizeof(**result));
1653 (*result)->data = work->data;
1654 (*result)->len = work->len;
1656 return SVN_NO_ERROR;
1660 /* These are somewhat arbirary, if we ever get good empirical data as to
1661 actually valid values, feel free to update them. */
1662 #define BUFFER_BLOCK_SIZE 1024
1663 #define BUFFER_MAX_SIZE 100000
1666 svn_stream_buffered(apr_pool_t *result_pool)
1668 return svn_stream__from_spillbuf(BUFFER_BLOCK_SIZE, BUFFER_MAX_SIZE,
1674 /*** Lazyopen Streams ***/
1676 /* Custom baton for lazyopen-style wrapper streams. */
1677 typedef struct lazyopen_baton_t {
1679 /* Callback function and baton for opening the wrapped stream. */
1680 svn_stream_lazyopen_func_t open_func;
1683 /* The wrapped stream, or NULL if the stream hasn't yet been
1685 svn_stream_t *real_stream;
1688 /* Whether to open the wrapped stream on a close call. */
1689 svn_boolean_t open_on_close;
1694 /* Use B->open_func/baton to create and set B->real_stream iff it
1695 isn't already set. */
1696 static svn_error_t *
1697 lazyopen_if_unopened(lazyopen_baton_t *b)
1699 if (b->real_stream == NULL)
1701 svn_stream_t *stream;
1702 apr_pool_t *scratch_pool = svn_pool_create(b->pool);
1704 SVN_ERR(b->open_func(&stream, b->open_baton,
1705 b->pool, scratch_pool));
1707 svn_pool_destroy(scratch_pool);
1709 b->real_stream = stream;
1712 return SVN_NO_ERROR;
1715 /* Implements svn_read_fn_t */
1716 static svn_error_t *
1717 read_handler_lazyopen(void *baton,
1721 lazyopen_baton_t *b = baton;
1723 SVN_ERR(lazyopen_if_unopened(b));
1724 SVN_ERR(svn_stream_read(b->real_stream, buffer, len));
1726 return SVN_NO_ERROR;
1729 /* Implements svn_stream_skip_fn_t */
1730 static svn_error_t *
1731 skip_handler_lazyopen(void *baton,
1734 lazyopen_baton_t *b = baton;
1736 SVN_ERR(lazyopen_if_unopened(b));
1737 SVN_ERR(svn_stream_skip(b->real_stream, len));
1739 return SVN_NO_ERROR;
1742 /* Implements svn_write_fn_t */
1743 static svn_error_t *
1744 write_handler_lazyopen(void *baton,
1748 lazyopen_baton_t *b = baton;
1750 SVN_ERR(lazyopen_if_unopened(b));
1751 SVN_ERR(svn_stream_write(b->real_stream, data, len));
1753 return SVN_NO_ERROR;
1756 /* Implements svn_close_fn_t */
1757 static svn_error_t *
1758 close_handler_lazyopen(void *baton)
1760 lazyopen_baton_t *b = baton;
1762 if (b->open_on_close)
1763 SVN_ERR(lazyopen_if_unopened(b));
1765 SVN_ERR(svn_stream_close(b->real_stream));
1767 return SVN_NO_ERROR;
1770 /* Implements svn_stream_mark_fn_t */
1771 static svn_error_t *
1772 mark_handler_lazyopen(void *baton,
1773 svn_stream_mark_t **mark,
1776 lazyopen_baton_t *b = baton;
1778 SVN_ERR(lazyopen_if_unopened(b));
1779 SVN_ERR(svn_stream_mark(b->real_stream, mark, pool));
1781 return SVN_NO_ERROR;
1784 /* Implements svn_stream_seek_fn_t */
1785 static svn_error_t *
1786 seek_handler_lazyopen(void *baton,
1787 const svn_stream_mark_t *mark)
1789 lazyopen_baton_t *b = baton;
1791 SVN_ERR(lazyopen_if_unopened(b));
1792 SVN_ERR(svn_stream_seek(b->real_stream, mark));
1794 return SVN_NO_ERROR;
1797 /* Implements svn_stream__is_buffered_fn_t */
1798 static svn_boolean_t
1799 is_buffered_lazyopen(void *baton)
1801 lazyopen_baton_t *b = baton;
1803 /* No lazy open as we cannot handle an open error. */
1804 if (!b->real_stream)
1807 return svn_stream__is_buffered(b->real_stream);
1811 svn_stream_lazyopen_create(svn_stream_lazyopen_func_t open_func,
1813 svn_boolean_t open_on_close,
1814 apr_pool_t *result_pool)
1816 lazyopen_baton_t *lob = apr_pcalloc(result_pool, sizeof(*lob));
1817 svn_stream_t *stream;
1819 lob->open_func = open_func;
1820 lob->open_baton = open_baton;
1821 lob->real_stream = NULL;
1822 lob->pool = result_pool;
1823 lob->open_on_close = open_on_close;
1825 stream = svn_stream_create(lob, result_pool);
1826 svn_stream_set_read(stream, read_handler_lazyopen);
1827 svn_stream_set_skip(stream, skip_handler_lazyopen);
1828 svn_stream_set_write(stream, write_handler_lazyopen);
1829 svn_stream_set_close(stream, close_handler_lazyopen);
1830 svn_stream_set_mark(stream, mark_handler_lazyopen);
1831 svn_stream_set_seek(stream, seek_handler_lazyopen);
1832 svn_stream__set_is_buffered(stream, is_buffered_lazyopen);