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
;
62 /*** Forward declarations. ***/
65 skip_default_handler(void *baton
, apr_size_t len
, svn_read_fn_t read_fn
);
68 /*** Generic streams. ***/
71 svn_stream_create(void *baton
, apr_pool_t
*pool
)
75 stream
= apr_palloc(pool
, sizeof(*stream
));
76 stream
->baton
= baton
;
77 stream
->read_fn
= NULL
;
78 stream
->skip_fn
= NULL
;
79 stream
->write_fn
= NULL
;
80 stream
->close_fn
= NULL
;
81 stream
->mark_fn
= NULL
;
82 stream
->seek_fn
= NULL
;
83 stream
->is_buffered_fn
= NULL
;
89 svn_stream_set_baton(svn_stream_t
*stream
, void *baton
)
91 stream
->baton
= baton
;
96 svn_stream_set_read(svn_stream_t
*stream
, svn_read_fn_t read_fn
)
98 stream
->read_fn
= read_fn
;
102 svn_stream_set_skip(svn_stream_t
*stream
, svn_stream_skip_fn_t skip_fn
)
104 stream
->skip_fn
= skip_fn
;
108 svn_stream_set_write(svn_stream_t
*stream
, svn_write_fn_t write_fn
)
110 stream
->write_fn
= write_fn
;
114 svn_stream_set_close(svn_stream_t
*stream
, svn_close_fn_t close_fn
)
116 stream
->close_fn
= close_fn
;
120 svn_stream_set_mark(svn_stream_t
*stream
, svn_stream_mark_fn_t mark_fn
)
122 stream
->mark_fn
= mark_fn
;
126 svn_stream_set_seek(svn_stream_t
*stream
, svn_stream_seek_fn_t seek_fn
)
128 stream
->seek_fn
= seek_fn
;
132 svn_stream__set_is_buffered(svn_stream_t
*stream
,
133 svn_stream__is_buffered_fn_t is_buffered_fn
)
135 stream
->is_buffered_fn
= is_buffered_fn
;
139 svn_stream_read(svn_stream_t
*stream
, char *buffer
, apr_size_t
*len
)
141 SVN_ERR_ASSERT(stream
->read_fn
!= NULL
);
142 return svn_error_trace(stream
->read_fn(stream
->baton
, buffer
, len
));
147 svn_stream_skip(svn_stream_t
*stream
, apr_size_t len
)
149 if (stream
->skip_fn
== NULL
)
150 return svn_error_trace(
151 skip_default_handler(stream
->baton
, len
, stream
->read_fn
));
153 return svn_error_trace(stream
->skip_fn(stream
->baton
, len
));
158 svn_stream_write(svn_stream_t
*stream
, const char *data
, apr_size_t
*len
)
160 SVN_ERR_ASSERT(stream
->write_fn
!= NULL
);
161 return svn_error_trace(stream
->write_fn(stream
->baton
, data
, len
));
166 svn_stream_reset(svn_stream_t
*stream
)
168 return svn_error_trace(
169 svn_stream_seek(stream
, NULL
));
173 svn_stream_supports_mark(svn_stream_t
*stream
)
175 return stream
->mark_fn
!= NULL
;
179 svn_stream_mark(svn_stream_t
*stream
, svn_stream_mark_t
**mark
,
182 if (stream
->mark_fn
== NULL
)
183 return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED
, NULL
, NULL
);
185 return svn_error_trace(stream
->mark_fn(stream
->baton
, mark
, pool
));
189 svn_stream_seek(svn_stream_t
*stream
, const svn_stream_mark_t
*mark
)
191 if (stream
->seek_fn
== NULL
)
192 return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED
, NULL
, NULL
);
194 return svn_error_trace(stream
->seek_fn(stream
->baton
, mark
));
198 svn_stream__is_buffered(svn_stream_t
*stream
)
200 if (stream
->is_buffered_fn
== NULL
)
203 return stream
->is_buffered_fn(stream
->baton
);
207 svn_stream_close(svn_stream_t
*stream
)
209 if (stream
->close_fn
== NULL
)
211 return svn_error_trace(stream
->close_fn(stream
->baton
));
215 svn_stream_puts(svn_stream_t
*stream
,
220 return svn_error_trace(svn_stream_write(stream
, str
, &len
));
224 svn_stream_printf(svn_stream_t
*stream
,
233 message
= apr_pvsprintf(pool
, fmt
, ap
);
236 return svn_error_trace(svn_stream_puts(stream
, message
));
241 svn_stream_printf_from_utf8(svn_stream_t
*stream
,
242 const char *encoding
,
247 const char *message
, *translated
;
251 message
= apr_pvsprintf(pool
, fmt
, ap
);
254 SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated
, message
, encoding
,
257 return svn_error_trace(svn_stream_puts(stream
, translated
));
260 /* Size that 90% of the lines we encounter will be not longer than.
261 used by stream_readline_bytewise() and stream_readline_chunky().
263 #define LINE_CHUNK_SIZE 80
265 /* Guts of svn_stream_readline().
266 * Returns the line read from STREAM in *STRINGBUF, and indicates
267 * end-of-file in *EOF. If DETECT_EOL is TRUE, the end-of-line indicator
268 * is detected automatically and returned in *EOL.
269 * If DETECT_EOL is FALSE, *EOL must point to the desired end-of-line
270 * indicator. STRINGBUF is allocated in POOL. */
272 stream_readline_bytewise(svn_stringbuf_t
**stringbuf
,
275 svn_stream_t
*stream
,
278 svn_stringbuf_t
*str
;
283 /* Since we're reading one character at a time, let's at least
284 optimize for the 90% case. 90% of the time, we can avoid the
285 stringbuf ever having to realloc() itself if we start it out at
287 str
= svn_stringbuf_create_ensure(LINE_CHUNK_SIZE
, pool
);
289 /* Read into STR up to and including the next EOL sequence. */
294 SVN_ERR(svn_stream_read(stream
, &c
, &numbytes
));
297 /* a 'short' read means the stream has run out. */
308 svn_stringbuf_appendbyte(str
, c
);
312 svn_stringbuf_chop(str
, match
- eol
);
319 stream_readline_chunky(svn_stringbuf_t
**stringbuf
,
322 svn_stream_t
*stream
,
325 /* Read larger chunks of data at once into this buffer and scan
326 * that for EOL. A good chunk size should be about 80 chars since
327 * most text lines will be shorter. However, don't use a much
328 * larger value because filling the buffer from the stream takes
331 char buffer
[LINE_CHUNK_SIZE
+1];
334 svn_stream_mark_t
*mark
;
337 apr_size_t total_parsed
= 0;
339 /* invariant for this call */
340 const size_t eol_len
= strlen(eol
);
342 /* Remember the line start so this plus the line length will be
343 * the position to move to at the end of this function.
345 SVN_ERR(svn_stream_mark(stream
, &mark
, pool
));
347 /* Read the first chunk. */
348 numbytes
= LINE_CHUNK_SIZE
;
349 SVN_ERR(svn_stream_read(stream
, buffer
, &numbytes
));
350 buffer
[numbytes
] = '\0';
352 /* Look for the EOL in this first chunk. If we find it, we are done here.
354 eol_pos
= strstr(buffer
, eol
);
357 *stringbuf
= svn_stringbuf_ncreate(buffer
, eol_pos
- buffer
, pool
);
358 total_parsed
= eol_pos
- buffer
+ eol_len
;
360 else if (numbytes
< LINE_CHUNK_SIZE
)
362 /* We hit EOF but not EOL.
364 *stringbuf
= svn_stringbuf_ncreate(buffer
, numbytes
, pool
);
370 /* A larger buffer for the string is needed. */
371 svn_stringbuf_t
*str
;
372 str
= svn_stringbuf_create_ensure(2*LINE_CHUNK_SIZE
, pool
);
373 svn_stringbuf_appendbytes(str
, buffer
, numbytes
);
376 /* Loop reading chunks until an EOL was found. If we hit EOF, fall
377 * back to the standard implementation. */
380 /* Append the next chunk to the string read so far.
382 svn_stringbuf_ensure(str
, str
->len
+ LINE_CHUNK_SIZE
);
383 numbytes
= LINE_CHUNK_SIZE
;
384 SVN_ERR(svn_stream_read(stream
, str
->data
+ str
->len
, &numbytes
));
385 str
->len
+= numbytes
;
386 str
->data
[str
->len
] = '\0';
388 /* Look for the EOL in the new data plus the last part of the
389 * previous chunk because the EOL may span over the boundary
390 * between both chunks.
392 eol_pos
= strstr(str
->data
+ str
->len
- numbytes
- (eol_len
-1), eol
);
394 if ((numbytes
< LINE_CHUNK_SIZE
) && (eol_pos
== NULL
))
396 /* We hit EOF instead of EOL. */
401 while (eol_pos
== NULL
);
403 /* Number of bytes we actually consumed (i.e. line + EOF).
404 * We need to "return" the rest to the stream by moving its
407 total_parsed
= eol_pos
- str
->data
+ eol_len
;
409 /* Terminate the string at the EOL postion and return it. */
410 str
->len
= eol_pos
- str
->data
;
411 str
->data
[str
->len
] = 0;
414 /* Move the stream read pointer to the first position behind the EOL.
416 SVN_ERR(svn_stream_seek(stream
, mark
));
417 return svn_error_trace(svn_stream_skip(stream
, total_parsed
));
420 /* Guts of svn_stream_readline().
421 * Returns the line read from STREAM in *STRINGBUF, and indicates
422 * end-of-file in *EOF. EOL must point to the desired end-of-line
423 * indicator. STRINGBUF is allocated in POOL. */
425 stream_readline(svn_stringbuf_t
**stringbuf
,
428 svn_stream_t
*stream
,
433 /* Often, we operate on APR file or string-based streams and know what
434 * EOL we are looking for. Optimize that common case.
436 if (svn_stream_supports_mark(stream
) &&
437 svn_stream__is_buffered(stream
))
439 /* We can efficiently read chunks speculatively and reposition the
440 * stream pointer to the end of the line once we found that.
442 SVN_ERR(stream_readline_chunky(stringbuf
,
450 /* Use the standard byte-byte implementation.
452 SVN_ERR(stream_readline_bytewise(stringbuf
,
463 svn_stream_readline(svn_stream_t
*stream
,
464 svn_stringbuf_t
**stringbuf
,
469 return svn_error_trace(stream_readline(stringbuf
, eof
, eol
, stream
,
473 svn_error_t
*svn_stream_copy3(svn_stream_t
*from
, svn_stream_t
*to
,
474 svn_cancel_func_t cancel_func
,
476 apr_pool_t
*scratch_pool
)
478 char *buf
= apr_palloc(scratch_pool
, SVN__STREAM_CHUNK_SIZE
);
482 /* Read and write chunks until we get a short read, indicating the
483 end of the stream. (We can't get a short write without an
484 associated error.) */
487 apr_size_t len
= SVN__STREAM_CHUNK_SIZE
;
491 err
= cancel_func(cancel_baton
);
496 err
= svn_stream_read(from
, buf
, &len
);
501 err
= svn_stream_write(to
, buf
, &len
);
503 if (err
|| (len
!= SVN__STREAM_CHUNK_SIZE
))
507 err2
= svn_error_compose_create(svn_stream_close(from
),
508 svn_stream_close(to
));
510 return svn_error_compose_create(err
, err2
);
514 svn_stream_contents_same2(svn_boolean_t
*same
,
515 svn_stream_t
*stream1
,
516 svn_stream_t
*stream2
,
519 char *buf1
= apr_palloc(pool
, SVN__STREAM_CHUNK_SIZE
);
520 char *buf2
= apr_palloc(pool
, SVN__STREAM_CHUNK_SIZE
);
521 apr_size_t bytes_read1
= SVN__STREAM_CHUNK_SIZE
;
522 apr_size_t bytes_read2
= SVN__STREAM_CHUNK_SIZE
;
523 svn_error_t
*err
= NULL
;
525 *same
= TRUE
; /* assume TRUE, until disproved below */
526 while (bytes_read1
== SVN__STREAM_CHUNK_SIZE
527 && bytes_read2
== SVN__STREAM_CHUNK_SIZE
)
529 err
= svn_stream_read(stream1
, buf1
, &bytes_read1
);
532 err
= svn_stream_read(stream2
, buf2
, &bytes_read2
);
536 if ((bytes_read1
!= bytes_read2
)
537 || (memcmp(buf1
, buf2
, bytes_read1
)))
544 return svn_error_compose_create(err
,
545 svn_error_compose_create(
546 svn_stream_close(stream1
),
547 svn_stream_close(stream2
)));
551 /*** Stream implementation utilities ***/
553 /* Skip data from any stream by reading and simply discarding it. */
555 skip_default_handler(void *baton
, apr_size_t len
, svn_read_fn_t read_fn
)
557 apr_size_t bytes_read
= 1;
559 apr_size_t to_read
= len
;
561 while ((to_read
> 0) && (bytes_read
> 0))
563 bytes_read
= sizeof(buffer
) < to_read
? sizeof(buffer
) : to_read
;
564 SVN_ERR(read_fn(baton
, buffer
, &bytes_read
));
565 to_read
-= bytes_read
;
573 /*** Generic readable empty stream ***/
576 read_handler_empty(void *baton
, char *buffer
, apr_size_t
*len
)
583 write_handler_empty(void *baton
, const char *data
, apr_size_t
*len
)
589 mark_handler_empty(void *baton
, svn_stream_mark_t
**mark
, apr_pool_t
*pool
)
591 *mark
= NULL
; /* Seek to start of stream marker */
596 seek_handler_empty(void *baton
, const svn_stream_mark_t
*mark
)
602 is_buffered_handler_empty(void *baton
)
609 svn_stream_empty(apr_pool_t
*pool
)
611 svn_stream_t
*stream
;
613 stream
= svn_stream_create(NULL
, pool
);
614 svn_stream_set_read(stream
, read_handler_empty
);
615 svn_stream_set_write(stream
, write_handler_empty
);
616 svn_stream_set_mark(stream
, mark_handler_empty
);
617 svn_stream_set_seek(stream
, seek_handler_empty
);
618 svn_stream__set_is_buffered(stream
, is_buffered_handler_empty
);
624 /*** Stream duplication support ***/
632 write_handler_tee(void *baton
, const char *data
, apr_size_t
*len
)
634 struct baton_tee
*bt
= baton
;
636 SVN_ERR(svn_stream_write(bt
->out1
, data
, len
));
637 SVN_ERR(svn_stream_write(bt
->out2
, data
, len
));
644 close_handler_tee(void *baton
)
646 struct baton_tee
*bt
= baton
;
648 SVN_ERR(svn_stream_close(bt
->out1
));
649 SVN_ERR(svn_stream_close(bt
->out2
));
656 svn_stream_tee(svn_stream_t
*out1
,
660 struct baton_tee
*baton
;
661 svn_stream_t
*stream
;
669 baton
= apr_palloc(pool
, sizeof(*baton
));
672 stream
= svn_stream_create(baton
, pool
);
673 svn_stream_set_write(stream
, write_handler_tee
);
674 svn_stream_set_close(stream
, close_handler_tee
);
681 /*** Ownership detaching stream ***/
684 read_handler_disown(void *baton
, char *buffer
, apr_size_t
*len
)
686 return svn_error_trace(svn_stream_read(baton
, buffer
, len
));
690 skip_handler_disown(void *baton
, apr_size_t len
)
692 return svn_error_trace(svn_stream_skip(baton
, len
));
696 write_handler_disown(void *baton
, const char *buffer
, apr_size_t
*len
)
698 return svn_error_trace(svn_stream_write(baton
, buffer
, len
));
702 mark_handler_disown(void *baton
, svn_stream_mark_t
**mark
, apr_pool_t
*pool
)
704 return svn_error_trace(svn_stream_mark(baton
, mark
, pool
));
708 seek_handler_disown(void *baton
, const svn_stream_mark_t
*mark
)
710 return svn_error_trace(svn_stream_seek(baton
, mark
));
714 is_buffered_handler_disown(void *baton
)
716 return svn_stream__is_buffered(baton
);
720 svn_stream_disown(svn_stream_t
*stream
, apr_pool_t
*pool
)
722 svn_stream_t
*s
= svn_stream_create(stream
, pool
);
724 svn_stream_set_read(s
, read_handler_disown
);
725 svn_stream_set_skip(s
, skip_handler_disown
);
726 svn_stream_set_write(s
, write_handler_disown
);
727 svn_stream_set_mark(s
, mark_handler_disown
);
728 svn_stream_set_seek(s
, seek_handler_disown
);
729 svn_stream__set_is_buffered(s
, is_buffered_handler_disown
);
736 /*** Generic stream for APR files ***/
742 /* svn_stream_mark_t for streams backed by APR files. */
748 read_handler_apr(void *baton
, char *buffer
, apr_size_t
*len
)
750 struct baton_apr
*btn
= baton
;
756 err
= svn_io_file_getc(buffer
, btn
->file
, btn
->pool
);
760 if (APR_STATUS_IS_EOF(err
->apr_err
))
762 svn_error_clear(err
);
768 err
= svn_io_file_read_full2(btn
->file
, buffer
, *len
, len
,
771 return svn_error_trace(err
);
775 skip_handler_apr(void *baton
, apr_size_t len
)
777 struct baton_apr
*btn
= baton
;
778 apr_off_t offset
= len
;
780 return svn_error_trace(
781 svn_io_file_seek(btn
->file
, APR_CUR
, &offset
, btn
->pool
));
785 write_handler_apr(void *baton
, const char *data
, apr_size_t
*len
)
787 struct baton_apr
*btn
= baton
;
792 err
= svn_io_file_putc(*data
, btn
->file
, btn
->pool
);
797 err
= svn_io_file_write_full(btn
->file
, data
, *len
, len
, btn
->pool
);
799 return svn_error_trace(err
);
803 close_handler_apr(void *baton
)
805 struct baton_apr
*btn
= baton
;
807 return svn_error_trace(svn_io_file_close(btn
->file
, btn
->pool
));
811 mark_handler_apr(void *baton
, svn_stream_mark_t
**mark
, apr_pool_t
*pool
)
813 struct baton_apr
*btn
= baton
;
814 struct mark_apr
*mark_apr
;
816 mark_apr
= apr_palloc(pool
, sizeof(*mark_apr
));
818 SVN_ERR(svn_io_file_seek(btn
->file
, APR_CUR
, &mark_apr
->off
, btn
->pool
));
819 *mark
= (svn_stream_mark_t
*)mark_apr
;
824 seek_handler_apr(void *baton
, const svn_stream_mark_t
*mark
)
826 struct baton_apr
*btn
= baton
;
827 apr_off_t offset
= (mark
!= NULL
) ? ((const struct mark_apr
*)mark
)->off
: 0;
829 SVN_ERR(svn_io_file_seek(btn
->file
, APR_SET
, &offset
, btn
->pool
));
835 is_buffered_handler_apr(void *baton
)
837 struct baton_apr
*btn
= baton
;
838 return (apr_file_flags_get(btn
->file
) & APR_BUFFERED
) != 0;
842 svn_stream_open_readonly(svn_stream_t
**stream
,
844 apr_pool_t
*result_pool
,
845 apr_pool_t
*scratch_pool
)
849 SVN_ERR(svn_io_file_open(&file
, path
, APR_READ
| APR_BUFFERED
,
850 APR_OS_DEFAULT
, result_pool
));
851 *stream
= svn_stream_from_aprfile2(file
, FALSE
, result_pool
);
858 svn_stream_open_writable(svn_stream_t
**stream
,
860 apr_pool_t
*result_pool
,
861 apr_pool_t
*scratch_pool
)
865 SVN_ERR(svn_io_file_open(&file
, path
,
870 APR_OS_DEFAULT
, result_pool
));
871 *stream
= svn_stream_from_aprfile2(file
, FALSE
, result_pool
);
878 svn_stream_open_unique(svn_stream_t
**stream
,
879 const char **temp_path
,
881 svn_io_file_del_t delete_when
,
882 apr_pool_t
*result_pool
,
883 apr_pool_t
*scratch_pool
)
887 SVN_ERR(svn_io_open_unique_file3(&file
, temp_path
, dirpath
,
888 delete_when
, result_pool
, scratch_pool
));
889 *stream
= svn_stream_from_aprfile2(file
, FALSE
, result_pool
);
896 svn_stream_from_aprfile2(apr_file_t
*file
,
897 svn_boolean_t disown
,
900 struct baton_apr
*baton
;
901 svn_stream_t
*stream
;
904 return svn_stream_empty(pool
);
906 baton
= apr_palloc(pool
, sizeof(*baton
));
909 stream
= svn_stream_create(baton
, pool
);
910 svn_stream_set_read(stream
, read_handler_apr
);
911 svn_stream_set_write(stream
, write_handler_apr
);
912 svn_stream_set_skip(stream
, skip_handler_apr
);
913 svn_stream_set_mark(stream
, mark_handler_apr
);
914 svn_stream_set_seek(stream
, seek_handler_apr
);
915 svn_stream__set_is_buffered(stream
, is_buffered_handler_apr
);
918 svn_stream_set_close(stream
, close_handler_apr
);
924 /* Compressed stream support */
926 #define ZBUFFER_SIZE 4096 /* The size of the buffer the
927 compressed stream uses to read from
928 the substream. Basically an
929 arbitrary value, picked to be about
933 z_stream
*in
; /* compressed stream for reading */
934 z_stream
*out
; /* compressed stream for writing */
935 svn_read_fn_t read
; /* substream's read function */
936 svn_write_fn_t write
; /* substream's write function */
937 svn_close_fn_t close
; /* substream's close function */
938 void *read_buffer
; /* buffer used for reading from
940 int read_flush
; /* what flush mode to use while
942 apr_pool_t
*pool
; /* The pool this baton is allocated
944 void *subbaton
; /* The substream's baton */
947 /* zlib alloc function. opaque is the pool we need. */
949 zalloc(voidpf opaque
, uInt items
, uInt size
)
951 apr_pool_t
*pool
= opaque
;
953 return apr_palloc(pool
, items
* size
);
956 /* zlib free function */
958 zfree(voidpf opaque
, voidpf address
)
960 /* Empty, since we allocate on the pool */
963 /* Helper function to figure out the sync mode */
965 read_helper_gz(svn_read_fn_t read_fn
,
968 uInt
*len
, int *zflush
)
970 uInt orig_len
= *len
;
972 /* There's no reason this value should grow bigger than the range of
973 uInt, but Subversion's API requires apr_size_t. */
974 apr_size_t apr_len
= (apr_size_t
) *len
;
976 SVN_ERR((*read_fn
)(baton
, buffer
, &apr_len
));
978 /* Type cast back to uInt type that zlib uses. On LP64 platforms
979 apr_size_t will be bigger than uInt. */
980 *len
= (uInt
) apr_len
;
982 /* I wanted to use Z_FINISH here, but we need to know our buffer is
984 *zflush
= (*len
) < orig_len
? Z_SYNC_FLUSH
: Z_SYNC_FLUSH
;
989 /* Handle reading from a compressed stream */
991 read_handler_gz(void *baton
, char *buffer
, apr_size_t
*len
)
993 struct zbaton
*btn
= baton
;
998 btn
->in
= apr_palloc(btn
->pool
, sizeof(z_stream
));
999 btn
->in
->zalloc
= zalloc
;
1000 btn
->in
->zfree
= zfree
;
1001 btn
->in
->opaque
= btn
->pool
;
1002 btn
->read_buffer
= apr_palloc(btn
->pool
, ZBUFFER_SIZE
);
1003 btn
->in
->next_in
= btn
->read_buffer
;
1004 btn
->in
->avail_in
= ZBUFFER_SIZE
;
1006 SVN_ERR(read_helper_gz(btn
->read
, btn
->subbaton
, btn
->read_buffer
,
1007 &btn
->in
->avail_in
, &btn
->read_flush
));
1009 zerr
= inflateInit(btn
->in
);
1010 SVN_ERR(svn_error__wrap_zlib(zerr
, "inflateInit", btn
->in
->msg
));
1013 btn
->in
->next_out
= (Bytef
*) buffer
;
1014 btn
->in
->avail_out
= (uInt
) *len
;
1016 while (btn
->in
->avail_out
> 0)
1018 if (btn
->in
->avail_in
<= 0)
1020 btn
->in
->avail_in
= ZBUFFER_SIZE
;
1021 btn
->in
->next_in
= btn
->read_buffer
;
1022 SVN_ERR(read_helper_gz(btn
->read
, btn
->subbaton
, btn
->read_buffer
,
1023 &btn
->in
->avail_in
, &btn
->read_flush
));
1026 /* Short read means underlying stream has run out. */
1027 if (btn
->in
->avail_in
== 0)
1030 return SVN_NO_ERROR
;
1033 zerr
= inflate(btn
->in
, btn
->read_flush
);
1034 if (zerr
== Z_STREAM_END
)
1036 else if (zerr
!= Z_OK
)
1037 return svn_error_trace(svn_error__wrap_zlib(zerr
, "inflate",
1041 *len
-= btn
->in
->avail_out
;
1042 return SVN_NO_ERROR
;
1045 /* Compress data and write it to the substream */
1046 static svn_error_t
*
1047 write_handler_gz(void *baton
, const char *buffer
, apr_size_t
*len
)
1049 struct zbaton
*btn
= baton
;
1050 apr_pool_t
*subpool
;
1052 apr_size_t buf_size
, write_len
;
1055 if (btn
->out
== NULL
)
1057 btn
->out
= apr_palloc(btn
->pool
, sizeof(z_stream
));
1058 btn
->out
->zalloc
= zalloc
;
1059 btn
->out
->zfree
= zfree
;
1060 btn
->out
->opaque
= btn
->pool
;
1062 zerr
= deflateInit(btn
->out
, Z_DEFAULT_COMPRESSION
);
1063 SVN_ERR(svn_error__wrap_zlib(zerr
, "deflateInit", btn
->out
->msg
));
1066 /* The largest buffer we should need is 0.1% larger than the
1067 compressed data, + 12 bytes. This info comes from zlib.h. */
1068 buf_size
= *len
+ (*len
/ 1000) + 13;
1069 subpool
= svn_pool_create(btn
->pool
);
1070 write_buf
= apr_palloc(subpool
, buf_size
);
1072 btn
->out
->next_in
= (Bytef
*) buffer
; /* Casting away const! */
1073 btn
->out
->avail_in
= (uInt
) *len
;
1075 while (btn
->out
->avail_in
> 0)
1077 btn
->out
->next_out
= write_buf
;
1078 btn
->out
->avail_out
= (uInt
) buf_size
;
1080 zerr
= deflate(btn
->out
, Z_NO_FLUSH
);
1081 SVN_ERR(svn_error__wrap_zlib(zerr
, "deflate", btn
->out
->msg
));
1082 write_len
= buf_size
- btn
->out
->avail_out
;
1084 SVN_ERR(btn
->write(btn
->subbaton
, write_buf
, &write_len
));
1087 svn_pool_destroy(subpool
);
1089 return SVN_NO_ERROR
;
1092 /* Handle flushing and closing the stream */
1093 static svn_error_t
*
1094 close_handler_gz(void *baton
)
1096 struct zbaton
*btn
= baton
;
1099 if (btn
->in
!= NULL
)
1101 zerr
= inflateEnd(btn
->in
);
1102 SVN_ERR(svn_error__wrap_zlib(zerr
, "inflateEnd", btn
->in
->msg
));
1105 if (btn
->out
!= NULL
)
1108 apr_size_t write_len
;
1110 buf
= apr_palloc(btn
->pool
, ZBUFFER_SIZE
);
1114 btn
->out
->next_out
= buf
;
1115 btn
->out
->avail_out
= ZBUFFER_SIZE
;
1117 zerr
= deflate(btn
->out
, Z_FINISH
);
1118 if (zerr
!= Z_STREAM_END
&& zerr
!= Z_OK
)
1119 return svn_error_trace(svn_error__wrap_zlib(zerr
, "deflate",
1121 write_len
= ZBUFFER_SIZE
- btn
->out
->avail_out
;
1123 SVN_ERR(btn
->write(btn
->subbaton
, buf
, &write_len
));
1124 if (zerr
== Z_STREAM_END
)
1128 zerr
= deflateEnd(btn
->out
);
1129 SVN_ERR(svn_error__wrap_zlib(zerr
, "deflateEnd", btn
->out
->msg
));
1132 if (btn
->close
!= NULL
)
1133 return svn_error_trace(btn
->close(btn
->subbaton
));
1135 return SVN_NO_ERROR
;
1140 svn_stream_compressed(svn_stream_t
*stream
, apr_pool_t
*pool
)
1142 struct svn_stream_t
*zstream
;
1143 struct zbaton
*baton
;
1145 assert(stream
!= NULL
);
1147 baton
= apr_palloc(pool
, sizeof(*baton
));
1148 baton
->in
= baton
->out
= NULL
;
1149 baton
->read
= stream
->read_fn
;
1150 baton
->write
= stream
->write_fn
;
1151 baton
->close
= stream
->close_fn
;
1152 baton
->subbaton
= stream
->baton
;
1154 baton
->read_buffer
= NULL
;
1155 baton
->read_flush
= Z_SYNC_FLUSH
;
1157 zstream
= svn_stream_create(baton
, pool
);
1158 svn_stream_set_read(zstream
, read_handler_gz
);
1159 svn_stream_set_write(zstream
, write_handler_gz
);
1160 svn_stream_set_close(zstream
, close_handler_gz
);
1166 /* Checksummed stream support */
1168 struct checksum_stream_baton
1170 svn_checksum_ctx_t
*read_ctx
, *write_ctx
;
1171 svn_checksum_t
**read_checksum
; /* Output value. */
1172 svn_checksum_t
**write_checksum
; /* Output value. */
1173 svn_stream_t
*proxy
;
1175 /* True if more data should be read when closing the stream. */
1176 svn_boolean_t read_more
;
1178 /* Pool to allocate read buffer and output values from. */
1182 static svn_error_t
*
1183 read_handler_checksum(void *baton
, char *buffer
, apr_size_t
*len
)
1185 struct checksum_stream_baton
*btn
= baton
;
1186 apr_size_t saved_len
= *len
;
1188 SVN_ERR(svn_stream_read(btn
->proxy
, buffer
, len
));
1190 if (btn
->read_checksum
)
1191 SVN_ERR(svn_checksum_update(btn
->read_ctx
, buffer
, *len
));
1193 if (saved_len
!= *len
)
1194 btn
->read_more
= FALSE
;
1196 return SVN_NO_ERROR
;
1200 static svn_error_t
*
1201 write_handler_checksum(void *baton
, const char *buffer
, apr_size_t
*len
)
1203 struct checksum_stream_baton
*btn
= baton
;
1205 if (btn
->write_checksum
&& *len
> 0)
1206 SVN_ERR(svn_checksum_update(btn
->write_ctx
, buffer
, *len
));
1208 return svn_error_trace(svn_stream_write(btn
->proxy
, buffer
, len
));
1212 static svn_error_t
*
1213 close_handler_checksum(void *baton
)
1215 struct checksum_stream_baton
*btn
= baton
;
1217 /* If we're supposed to drain the stream, do so before finalizing the
1221 char *buf
= apr_palloc(btn
->pool
, SVN__STREAM_CHUNK_SIZE
);
1222 apr_size_t len
= SVN__STREAM_CHUNK_SIZE
;
1226 SVN_ERR(read_handler_checksum(baton
, buf
, &len
));
1228 while (btn
->read_more
);
1232 SVN_ERR(svn_checksum_final(btn
->read_checksum
, btn
->read_ctx
, btn
->pool
));
1235 SVN_ERR(svn_checksum_final(btn
->write_checksum
, btn
->write_ctx
, btn
->pool
));
1237 return svn_error_trace(svn_stream_close(btn
->proxy
));
1242 svn_stream_checksummed2(svn_stream_t
*stream
,
1243 svn_checksum_t
**read_checksum
,
1244 svn_checksum_t
**write_checksum
,
1245 svn_checksum_kind_t checksum_kind
,
1246 svn_boolean_t read_all
,
1250 struct checksum_stream_baton
*baton
;
1252 if (read_checksum
== NULL
&& write_checksum
== NULL
)
1255 baton
= apr_palloc(pool
, sizeof(*baton
));
1257 baton
->read_ctx
= svn_checksum_ctx_create(checksum_kind
, pool
);
1259 baton
->read_ctx
= NULL
;
1262 baton
->write_ctx
= svn_checksum_ctx_create(checksum_kind
, pool
);
1264 baton
->write_ctx
= NULL
;
1266 baton
->read_checksum
= read_checksum
;
1267 baton
->write_checksum
= write_checksum
;
1268 baton
->proxy
= stream
;
1269 baton
->read_more
= read_all
;
1272 s
= svn_stream_create(baton
, pool
);
1273 svn_stream_set_read(s
, read_handler_checksum
);
1274 svn_stream_set_write(s
, write_handler_checksum
);
1275 svn_stream_set_close(s
, close_handler_checksum
);
1279 struct md5_stream_baton
1281 const unsigned char **read_digest
;
1282 const unsigned char **write_digest
;
1283 svn_checksum_t
*read_checksum
;
1284 svn_checksum_t
*write_checksum
;
1285 svn_stream_t
*proxy
;
1289 static svn_error_t
*
1290 read_handler_md5(void *baton
, char *buffer
, apr_size_t
*len
)
1292 struct md5_stream_baton
*btn
= baton
;
1293 return svn_error_trace(svn_stream_read(btn
->proxy
, buffer
, len
));
1296 static svn_error_t
*
1297 skip_handler_md5(void *baton
, apr_size_t len
)
1299 struct md5_stream_baton
*btn
= baton
;
1300 return svn_error_trace(svn_stream_skip(btn
->proxy
, len
));
1303 static svn_error_t
*
1304 write_handler_md5(void *baton
, const char *buffer
, apr_size_t
*len
)
1306 struct md5_stream_baton
*btn
= baton
;
1307 return svn_error_trace(svn_stream_write(btn
->proxy
, buffer
, len
));
1310 static svn_error_t
*
1311 close_handler_md5(void *baton
)
1313 struct md5_stream_baton
*btn
= baton
;
1315 SVN_ERR(svn_stream_close(btn
->proxy
));
1317 if (btn
->read_digest
)
1319 = apr_pmemdup(btn
->pool
, btn
->read_checksum
->digest
,
1320 APR_MD5_DIGESTSIZE
);
1322 if (btn
->write_digest
)
1324 = apr_pmemdup(btn
->pool
, btn
->write_checksum
->digest
,
1325 APR_MD5_DIGESTSIZE
);
1327 return SVN_NO_ERROR
;
1332 svn_stream_checksummed(svn_stream_t
*stream
,
1333 const unsigned char **read_digest
,
1334 const unsigned char **write_digest
,
1335 svn_boolean_t read_all
,
1339 struct md5_stream_baton
*baton
;
1341 if (! read_digest
&& ! write_digest
)
1344 baton
= apr_palloc(pool
, sizeof(*baton
));
1345 baton
->read_digest
= read_digest
;
1346 baton
->write_digest
= write_digest
;
1349 /* Set BATON->proxy to a stream that will fill in BATON->read_checksum
1350 * and BATON->write_checksum (if we want them) when it is closed. */
1352 = svn_stream_checksummed2(stream
,
1353 read_digest
? &baton
->read_checksum
: NULL
,
1354 write_digest
? &baton
->write_checksum
: NULL
,
1358 /* Create a stream that will forward its read/write/close operations to
1359 * BATON->proxy and will fill in *READ_DIGEST and *WRITE_DIGEST (if we
1360 * want them) after it closes BATON->proxy. */
1361 s
= svn_stream_create(baton
, pool
);
1362 svn_stream_set_read(s
, read_handler_md5
);
1363 svn_stream_set_skip(s
, skip_handler_md5
);
1364 svn_stream_set_write(s
, write_handler_md5
);
1365 svn_stream_set_close(s
, close_handler_md5
);
1372 /* Miscellaneous stream functions. */
1373 struct stringbuf_stream_baton
1375 svn_stringbuf_t
*str
;
1376 apr_size_t amt_read
;
1379 /* svn_stream_mark_t for streams backed by stringbufs. */
1380 struct stringbuf_stream_mark
{
1384 static svn_error_t
*
1385 read_handler_stringbuf(void *baton
, char *buffer
, apr_size_t
*len
)
1387 struct stringbuf_stream_baton
*btn
= baton
;
1388 apr_size_t left_to_read
= btn
->str
->len
- btn
->amt_read
;
1390 *len
= (*len
> left_to_read
) ? left_to_read
: *len
;
1391 memcpy(buffer
, btn
->str
->data
+ btn
->amt_read
, *len
);
1392 btn
->amt_read
+= *len
;
1393 return SVN_NO_ERROR
;
1396 static svn_error_t
*
1397 skip_handler_stringbuf(void *baton
, apr_size_t len
)
1399 struct stringbuf_stream_baton
*btn
= baton
;
1400 apr_size_t left_to_read
= btn
->str
->len
- btn
->amt_read
;
1402 len
= (len
> left_to_read
) ? left_to_read
: len
;
1403 btn
->amt_read
+= len
;
1404 return SVN_NO_ERROR
;
1407 static svn_error_t
*
1408 write_handler_stringbuf(void *baton
, const char *data
, apr_size_t
*len
)
1410 struct stringbuf_stream_baton
*btn
= baton
;
1412 svn_stringbuf_appendbytes(btn
->str
, data
, *len
);
1413 return SVN_NO_ERROR
;
1416 static svn_error_t
*
1417 mark_handler_stringbuf(void *baton
, svn_stream_mark_t
**mark
, apr_pool_t
*pool
)
1419 struct stringbuf_stream_baton
*btn
;
1420 struct stringbuf_stream_mark
*stringbuf_stream_mark
;
1424 stringbuf_stream_mark
= apr_palloc(pool
, sizeof(*stringbuf_stream_mark
));
1425 stringbuf_stream_mark
->pos
= btn
->amt_read
;
1426 *mark
= (svn_stream_mark_t
*)stringbuf_stream_mark
;
1427 return SVN_NO_ERROR
;
1430 static svn_error_t
*
1431 seek_handler_stringbuf(void *baton
, const svn_stream_mark_t
*mark
)
1433 struct stringbuf_stream_baton
*btn
= baton
;
1437 const struct stringbuf_stream_mark
*stringbuf_stream_mark
;
1439 stringbuf_stream_mark
= (const struct stringbuf_stream_mark
*)mark
;
1440 btn
->amt_read
= stringbuf_stream_mark
->pos
;
1445 return SVN_NO_ERROR
;
1448 static svn_boolean_t
1449 is_buffered_handler_stringbuf(void *baton
)
1455 svn_stream_from_stringbuf(svn_stringbuf_t
*str
,
1458 svn_stream_t
*stream
;
1459 struct stringbuf_stream_baton
*baton
;
1462 return svn_stream_empty(pool
);
1464 baton
= apr_palloc(pool
, sizeof(*baton
));
1466 baton
->amt_read
= 0;
1467 stream
= svn_stream_create(baton
, pool
);
1468 svn_stream_set_read(stream
, read_handler_stringbuf
);
1469 svn_stream_set_skip(stream
, skip_handler_stringbuf
);
1470 svn_stream_set_write(stream
, write_handler_stringbuf
);
1471 svn_stream_set_mark(stream
, mark_handler_stringbuf
);
1472 svn_stream_set_seek(stream
, seek_handler_stringbuf
);
1473 svn_stream__set_is_buffered(stream
, is_buffered_handler_stringbuf
);
1477 struct string_stream_baton
1479 const svn_string_t
*str
;
1480 apr_size_t amt_read
;
1483 /* svn_stream_mark_t for streams backed by stringbufs. */
1484 struct string_stream_mark
{
1488 static svn_error_t
*
1489 read_handler_string(void *baton
, char *buffer
, apr_size_t
*len
)
1491 struct string_stream_baton
*btn
= baton
;
1492 apr_size_t left_to_read
= btn
->str
->len
- btn
->amt_read
;
1494 *len
= (*len
> left_to_read
) ? left_to_read
: *len
;
1495 memcpy(buffer
, btn
->str
->data
+ btn
->amt_read
, *len
);
1496 btn
->amt_read
+= *len
;
1497 return SVN_NO_ERROR
;
1500 static svn_error_t
*
1501 mark_handler_string(void *baton
, svn_stream_mark_t
**mark
, apr_pool_t
*pool
)
1503 struct string_stream_baton
*btn
;
1504 struct string_stream_mark
*marker
;
1508 marker
= apr_palloc(pool
, sizeof(*marker
));
1509 marker
->pos
= btn
->amt_read
;
1510 *mark
= (svn_stream_mark_t
*)marker
;
1511 return SVN_NO_ERROR
;
1514 static svn_error_t
*
1515 seek_handler_string(void *baton
, const svn_stream_mark_t
*mark
)
1517 struct string_stream_baton
*btn
= baton
;
1521 const struct string_stream_mark
*marker
;
1523 marker
= (const struct string_stream_mark
*)mark
;
1524 btn
->amt_read
= marker
->pos
;
1529 return SVN_NO_ERROR
;
1532 static svn_error_t
*
1533 skip_handler_string(void *baton
, apr_size_t len
)
1535 struct string_stream_baton
*btn
= baton
;
1536 apr_size_t left_to_read
= btn
->str
->len
- btn
->amt_read
;
1538 len
= (len
> left_to_read
) ? left_to_read
: len
;
1539 btn
->amt_read
+= len
;
1540 return SVN_NO_ERROR
;
1543 static svn_boolean_t
1544 is_buffered_handler_string(void *baton
)
1550 svn_stream_from_string(const svn_string_t
*str
,
1553 svn_stream_t
*stream
;
1554 struct string_stream_baton
*baton
;
1557 return svn_stream_empty(pool
);
1559 baton
= apr_palloc(pool
, sizeof(*baton
));
1561 baton
->amt_read
= 0;
1562 stream
= svn_stream_create(baton
, pool
);
1563 svn_stream_set_read(stream
, read_handler_string
);
1564 svn_stream_set_mark(stream
, mark_handler_string
);
1565 svn_stream_set_seek(stream
, seek_handler_string
);
1566 svn_stream_set_skip(stream
, skip_handler_string
);
1567 svn_stream__set_is_buffered(stream
, is_buffered_handler_string
);
1573 svn_stream_for_stdin(svn_stream_t
**in
, apr_pool_t
*pool
)
1575 apr_file_t
*stdin_file
;
1576 apr_status_t apr_err
;
1578 apr_err
= apr_file_open_stdin(&stdin_file
, pool
);
1580 return svn_error_wrap_apr(apr_err
, "Can't open stdin");
1582 *in
= svn_stream_from_aprfile2(stdin_file
, TRUE
, pool
);
1584 return SVN_NO_ERROR
;
1589 svn_stream_for_stdout(svn_stream_t
**out
, apr_pool_t
*pool
)
1591 apr_file_t
*stdout_file
;
1592 apr_status_t apr_err
;
1594 apr_err
= apr_file_open_stdout(&stdout_file
, pool
);
1596 return svn_error_wrap_apr(apr_err
, "Can't open stdout");
1598 *out
= svn_stream_from_aprfile2(stdout_file
, TRUE
, pool
);
1600 return SVN_NO_ERROR
;
1605 svn_stream_for_stderr(svn_stream_t
**err
, apr_pool_t
*pool
)
1607 apr_file_t
*stderr_file
;
1608 apr_status_t apr_err
;
1610 apr_err
= apr_file_open_stderr(&stderr_file
, pool
);
1612 return svn_error_wrap_apr(apr_err
, "Can't open stderr");
1614 *err
= svn_stream_from_aprfile2(stderr_file
, TRUE
, pool
);
1616 return SVN_NO_ERROR
;
1621 svn_string_from_stream(svn_string_t
**result
,
1622 svn_stream_t
*stream
,
1623 apr_pool_t
*result_pool
,
1624 apr_pool_t
*scratch_pool
)
1626 svn_stringbuf_t
*work
= svn_stringbuf_create_ensure(SVN__STREAM_CHUNK_SIZE
,
1628 char *buffer
= apr_palloc(scratch_pool
, SVN__STREAM_CHUNK_SIZE
);
1632 apr_size_t len
= SVN__STREAM_CHUNK_SIZE
;
1634 SVN_ERR(svn_stream_read(stream
, buffer
, &len
));
1635 svn_stringbuf_appendbytes(work
, buffer
, len
);
1637 if (len
< SVN__STREAM_CHUNK_SIZE
)
1641 SVN_ERR(svn_stream_close(stream
));
1643 *result
= apr_palloc(result_pool
, sizeof(**result
));
1644 (*result
)->data
= work
->data
;
1645 (*result
)->len
= work
->len
;
1647 return SVN_NO_ERROR
;
1651 /* These are somewhat arbirary, if we ever get good empirical data as to
1652 actually valid values, feel free to update them. */
1653 #define BUFFER_BLOCK_SIZE 1024
1654 #define BUFFER_MAX_SIZE 100000
1657 svn_stream_buffered(apr_pool_t
*result_pool
)
1659 return svn_stream__from_spillbuf(BUFFER_BLOCK_SIZE
, BUFFER_MAX_SIZE
,
1665 /*** Lazyopen Streams ***/
1667 /* Custom baton for lazyopen-style wrapper streams. */
1668 typedef struct lazyopen_baton_t
{
1670 /* Callback function and baton for opening the wrapped stream. */
1671 svn_stream_lazyopen_func_t open_func
;
1674 /* The wrapped stream, or NULL if the stream hasn't yet been
1676 svn_stream_t
*real_stream
;
1679 /* Whether to open the wrapped stream on a close call. */
1680 svn_boolean_t open_on_close
;
1685 /* Use B->open_func/baton to create and set B->real_stream iff it
1686 isn't already set. */
1687 static svn_error_t
*
1688 lazyopen_if_unopened(lazyopen_baton_t
*b
)
1690 if (b
->real_stream
== NULL
)
1692 svn_stream_t
*stream
;
1693 apr_pool_t
*scratch_pool
= svn_pool_create(b
->pool
);
1695 SVN_ERR(b
->open_func(&stream
, b
->open_baton
,
1696 b
->pool
, scratch_pool
));
1698 svn_pool_destroy(scratch_pool
);
1700 b
->real_stream
= stream
;
1703 return SVN_NO_ERROR
;
1706 /* Implements svn_read_fn_t */
1707 static svn_error_t
*
1708 read_handler_lazyopen(void *baton
,
1712 lazyopen_baton_t
*b
= baton
;
1714 SVN_ERR(lazyopen_if_unopened(b
));
1715 SVN_ERR(svn_stream_read(b
->real_stream
, buffer
, len
));
1717 return SVN_NO_ERROR
;
1720 /* Implements svn_stream_skip_fn_t */
1721 static svn_error_t
*
1722 skip_handler_lazyopen(void *baton
,
1725 lazyopen_baton_t
*b
= baton
;
1727 SVN_ERR(lazyopen_if_unopened(b
));
1728 SVN_ERR(svn_stream_skip(b
->real_stream
, len
));
1730 return SVN_NO_ERROR
;
1733 /* Implements svn_write_fn_t */
1734 static svn_error_t
*
1735 write_handler_lazyopen(void *baton
,
1739 lazyopen_baton_t
*b
= baton
;
1741 SVN_ERR(lazyopen_if_unopened(b
));
1742 SVN_ERR(svn_stream_write(b
->real_stream
, data
, len
));
1744 return SVN_NO_ERROR
;
1747 /* Implements svn_close_fn_t */
1748 static svn_error_t
*
1749 close_handler_lazyopen(void *baton
)
1751 lazyopen_baton_t
*b
= baton
;
1753 if (b
->open_on_close
)
1754 SVN_ERR(lazyopen_if_unopened(b
));
1756 SVN_ERR(svn_stream_close(b
->real_stream
));
1758 return SVN_NO_ERROR
;
1761 /* Implements svn_stream_mark_fn_t */
1762 static svn_error_t
*
1763 mark_handler_lazyopen(void *baton
,
1764 svn_stream_mark_t
**mark
,
1767 lazyopen_baton_t
*b
= baton
;
1769 SVN_ERR(lazyopen_if_unopened(b
));
1770 SVN_ERR(svn_stream_mark(b
->real_stream
, mark
, pool
));
1772 return SVN_NO_ERROR
;
1775 /* Implements svn_stream_seek_fn_t */
1776 static svn_error_t
*
1777 seek_handler_lazyopen(void *baton
,
1778 const svn_stream_mark_t
*mark
)
1780 lazyopen_baton_t
*b
= baton
;
1782 SVN_ERR(lazyopen_if_unopened(b
));
1783 SVN_ERR(svn_stream_seek(b
->real_stream
, mark
));
1785 return SVN_NO_ERROR
;
1788 /* Implements svn_stream__is_buffered_fn_t */
1789 static svn_boolean_t
1790 is_buffered_lazyopen(void *baton
)
1792 lazyopen_baton_t
*b
= baton
;
1794 /* No lazy open as we cannot handle an open error. */
1795 if (!b
->real_stream
)
1798 return svn_stream__is_buffered(b
->real_stream
);
1802 svn_stream_lazyopen_create(svn_stream_lazyopen_func_t open_func
,
1804 svn_boolean_t open_on_close
,
1805 apr_pool_t
*result_pool
)
1807 lazyopen_baton_t
*lob
= apr_pcalloc(result_pool
, sizeof(*lob
));
1808 svn_stream_t
*stream
;
1810 lob
->open_func
= open_func
;
1811 lob
->open_baton
= open_baton
;
1812 lob
->real_stream
= NULL
;
1813 lob
->pool
= result_pool
;
1814 lob
->open_on_close
= open_on_close
;
1816 stream
= svn_stream_create(lob
, result_pool
);
1817 svn_stream_set_read(stream
, read_handler_lazyopen
);
1818 svn_stream_set_skip(stream
, skip_handler_lazyopen
);
1819 svn_stream_set_write(stream
, write_handler_lazyopen
);
1820 svn_stream_set_close(stream
, close_handler_lazyopen
);
1821 svn_stream_set_mark(stream
, mark_handler_lazyopen
);
1822 svn_stream_set_seek(stream
, seek_handler_lazyopen
);
1823 svn_stream__set_is_buffered(stream
, is_buffered_lazyopen
);