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>
33 #include <apr_portable.h>
37 #include "svn_pools.h"
39 #include "svn_error.h"
40 #include "svn_string.h"
42 #include "svn_checksum.h"
44 #include "svn_private_config.h"
45 #include "svn_sorts.h"
46 #include "private/svn_atomic.h"
47 #include "private/svn_error_private.h"
48 #include "private/svn_eol_private.h"
49 #include "private/svn_io_private.h"
50 #include "private/svn_subr_private.h"
51 #include "private/svn_utf_private.h"
56 svn_read_fn_t read_fn
;
57 svn_read_fn_t read_full_fn
;
58 svn_stream_skip_fn_t skip_fn
;
59 svn_write_fn_t write_fn
;
60 svn_close_fn_t close_fn
;
61 svn_stream_mark_fn_t mark_fn
;
62 svn_stream_seek_fn_t seek_fn
;
63 svn_stream_data_available_fn_t data_available_fn
;
64 svn_stream_readline_fn_t readline_fn
;
65 apr_file_t
*file
; /* Maybe NULL */
69 /*** Forward declarations. ***/
72 skip_default_handler(void *baton
, apr_size_t len
, svn_read_fn_t read_full_fn
);
75 /*** Generic streams. ***/
78 svn_stream_create(void *baton
, apr_pool_t
*pool
)
82 stream
= apr_pcalloc(pool
, sizeof(*stream
));
83 stream
->baton
= baton
;
89 svn_stream_set_baton(svn_stream_t
*stream
, void *baton
)
91 stream
->baton
= baton
;
96 svn_stream_set_read2(svn_stream_t
*stream
,
97 svn_read_fn_t read_fn
,
98 svn_read_fn_t read_full_fn
)
100 stream
->read_fn
= read_fn
;
101 stream
->read_full_fn
= read_full_fn
;
105 svn_stream_set_skip(svn_stream_t
*stream
, svn_stream_skip_fn_t skip_fn
)
107 stream
->skip_fn
= skip_fn
;
111 svn_stream_set_write(svn_stream_t
*stream
, svn_write_fn_t write_fn
)
113 stream
->write_fn
= write_fn
;
117 svn_stream_set_close(svn_stream_t
*stream
, svn_close_fn_t close_fn
)
119 stream
->close_fn
= close_fn
;
123 svn_stream_set_mark(svn_stream_t
*stream
, svn_stream_mark_fn_t mark_fn
)
125 stream
->mark_fn
= mark_fn
;
129 svn_stream_set_seek(svn_stream_t
*stream
, svn_stream_seek_fn_t seek_fn
)
131 stream
->seek_fn
= seek_fn
;
135 svn_stream_set_data_available(svn_stream_t
*stream
,
136 svn_stream_data_available_fn_t data_available_fn
)
138 stream
->data_available_fn
= data_available_fn
;
142 svn_stream_set_readline(svn_stream_t
*stream
,
143 svn_stream_readline_fn_t readline_fn
)
145 stream
->readline_fn
= readline_fn
;
148 /* Standard implementation for svn_stream_read_full() based on
149 multiple svn_stream_read2() calls (in separate function to make
150 it more likely for svn_stream_read_full to be inlined) */
152 full_read_fallback(svn_stream_t
*stream
, char *buffer
, apr_size_t
*len
)
154 apr_size_t remaining
= *len
;
155 while (remaining
> 0)
157 apr_size_t length
= remaining
;
158 SVN_ERR(svn_stream_read2(stream
, buffer
, &length
));
174 svn_stream_supports_partial_read(svn_stream_t
*stream
)
176 return stream
->read_fn
!= NULL
;
180 svn_stream_read2(svn_stream_t
*stream
, char *buffer
, apr_size_t
*len
)
182 if (stream
->read_fn
== NULL
)
183 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED
, NULL
, NULL
);
185 return svn_error_trace(stream
->read_fn(stream
->baton
, buffer
, len
));
189 svn_stream_read_full(svn_stream_t
*stream
, char *buffer
, apr_size_t
*len
)
191 if (stream
->read_full_fn
== NULL
)
192 return svn_error_trace(full_read_fallback(stream
, buffer
, len
));
194 return svn_error_trace(stream
->read_full_fn(stream
->baton
, buffer
, len
));
198 svn_stream_skip(svn_stream_t
*stream
, apr_size_t len
)
200 if (stream
->skip_fn
== NULL
)
202 svn_read_fn_t read_fn
= stream
->read_full_fn
? stream
->read_full_fn
205 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED
, NULL
, NULL
);
207 return svn_error_trace(skip_default_handler(stream
->baton
, len
,
211 return svn_error_trace(stream
->skip_fn(stream
->baton
, len
));
216 svn_stream_write(svn_stream_t
*stream
, const char *data
, apr_size_t
*len
)
218 if (stream
->write_fn
== NULL
)
219 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED
, NULL
, NULL
);
221 return svn_error_trace(stream
->write_fn(stream
->baton
, data
, len
));
226 svn_stream_reset(svn_stream_t
*stream
)
228 return svn_error_trace(
229 svn_stream_seek(stream
, NULL
));
233 svn_stream_supports_mark(svn_stream_t
*stream
)
235 return stream
->mark_fn
!= NULL
;
239 svn_stream_supports_reset(svn_stream_t
*stream
)
241 return stream
->seek_fn
!= NULL
;
245 svn_stream_mark(svn_stream_t
*stream
, svn_stream_mark_t
**mark
,
248 if (stream
->mark_fn
== NULL
)
249 return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED
, NULL
, NULL
);
251 return svn_error_trace(stream
->mark_fn(stream
->baton
, mark
, pool
));
255 svn_stream_seek(svn_stream_t
*stream
, const svn_stream_mark_t
*mark
)
257 if (stream
->seek_fn
== NULL
)
258 return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED
, NULL
, NULL
);
260 return svn_error_trace(stream
->seek_fn(stream
->baton
, mark
));
264 svn_stream_data_available(svn_stream_t
*stream
,
265 svn_boolean_t
*data_available
)
267 if (stream
->data_available_fn
== NULL
)
268 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED
, NULL
, NULL
);
270 return svn_error_trace(stream
->data_available_fn(stream
->baton
,
275 svn_stream_close(svn_stream_t
*stream
)
277 if (stream
->close_fn
== NULL
)
279 return svn_error_trace(stream
->close_fn(stream
->baton
));
283 svn_stream_puts(svn_stream_t
*stream
,
288 return svn_error_trace(svn_stream_write(stream
, str
, &len
));
292 svn_stream_printf(svn_stream_t
*stream
,
301 message
= apr_pvsprintf(pool
, fmt
, ap
);
304 return svn_error_trace(svn_stream_puts(stream
, message
));
309 svn_stream_printf_from_utf8(svn_stream_t
*stream
,
310 const char *encoding
,
315 const char *message
, *translated
;
319 message
= apr_pvsprintf(pool
, fmt
, ap
);
322 SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated
, message
, encoding
,
325 return svn_error_trace(svn_stream_puts(stream
, translated
));
328 /* Default implementation for svn_stream_readline().
329 * Returns the line read from STREAM in *STRINGBUF, and indicates
330 * end-of-file in *EOF. EOL must point to the desired end-of-line
331 * indicator. STRINGBUF is allocated in POOL. */
333 stream_readline_bytewise(svn_stringbuf_t
**stringbuf
,
336 svn_stream_t
*stream
,
339 svn_stringbuf_t
*str
;
344 /* Since we're reading one character at a time, let's at least
345 optimize for the 90% case. 90% of the time, we can avoid the
346 stringbuf ever having to realloc() itself if we start it out at
348 str
= svn_stringbuf_create_ensure(SVN__LINE_CHUNK_SIZE
, pool
);
350 /* Read into STR up to and including the next EOL sequence. */
355 SVN_ERR(svn_stream_read_full(stream
, &c
, &numbytes
));
358 /* a 'short' read means the stream has run out. */
369 svn_stringbuf_appendbyte(str
, c
);
373 svn_stringbuf_chop(str
, match
- eol
);
380 svn_stream_readline(svn_stream_t
*stream
,
381 svn_stringbuf_t
**stringbuf
,
386 if (stream
->readline_fn
)
388 /* Use the specific implementation when it's available. */
389 SVN_ERR(stream
->readline_fn(stream
->baton
, stringbuf
, eol
, eof
, pool
));
393 /* Use the default implementation. */
394 SVN_ERR(stream_readline_bytewise(stringbuf
, eof
, eol
, stream
, pool
));
400 svn_error_t
*svn_stream_copy3(svn_stream_t
*from
, svn_stream_t
*to
,
401 svn_cancel_func_t cancel_func
,
403 apr_pool_t
*scratch_pool
)
405 char *buf
= apr_palloc(scratch_pool
, SVN__STREAM_CHUNK_SIZE
);
409 /* Read and write chunks until we get a short read, indicating the
410 end of the stream. (We can't get a short write without an
411 associated error.) */
414 apr_size_t len
= SVN__STREAM_CHUNK_SIZE
;
418 err
= cancel_func(cancel_baton
);
423 err
= svn_stream_read_full(from
, buf
, &len
);
428 err
= svn_stream_write(to
, buf
, &len
);
430 if (err
|| (len
!= SVN__STREAM_CHUNK_SIZE
))
434 err2
= svn_error_compose_create(svn_stream_close(from
),
435 svn_stream_close(to
));
437 return svn_error_compose_create(err
, err2
);
441 svn_stream_contents_same2(svn_boolean_t
*same
,
442 svn_stream_t
*stream1
,
443 svn_stream_t
*stream2
,
446 char *buf1
= apr_palloc(pool
, SVN__STREAM_CHUNK_SIZE
);
447 char *buf2
= apr_palloc(pool
, SVN__STREAM_CHUNK_SIZE
);
448 apr_size_t bytes_read1
= SVN__STREAM_CHUNK_SIZE
;
449 apr_size_t bytes_read2
= SVN__STREAM_CHUNK_SIZE
;
450 svn_error_t
*err
= NULL
;
452 *same
= TRUE
; /* assume TRUE, until disproved below */
453 while (bytes_read1
== SVN__STREAM_CHUNK_SIZE
454 && bytes_read2
== SVN__STREAM_CHUNK_SIZE
)
456 err
= svn_stream_read_full(stream1
, buf1
, &bytes_read1
);
459 err
= svn_stream_read_full(stream2
, buf2
, &bytes_read2
);
463 if ((bytes_read1
!= bytes_read2
)
464 || (memcmp(buf1
, buf2
, bytes_read1
)))
471 return svn_error_compose_create(err
,
472 svn_error_compose_create(
473 svn_stream_close(stream1
),
474 svn_stream_close(stream2
)));
478 /*** Stream implementation utilities ***/
480 /* Skip data from any stream by reading and simply discarding it. */
482 skip_default_handler(void *baton
, apr_size_t len
, svn_read_fn_t read_full_fn
)
484 apr_size_t bytes_read
= 1;
486 apr_size_t to_read
= len
;
488 while ((to_read
> 0) && (bytes_read
> 0))
490 bytes_read
= sizeof(buffer
) < to_read
? sizeof(buffer
) : to_read
;
491 SVN_ERR(read_full_fn(baton
, buffer
, &bytes_read
));
492 to_read
-= bytes_read
;
500 /*** Generic readable empty stream ***/
503 read_handler_empty(void *baton
, char *buffer
, apr_size_t
*len
)
510 write_handler_empty(void *baton
, const char *data
, apr_size_t
*len
)
516 mark_handler_empty(void *baton
, svn_stream_mark_t
**mark
, apr_pool_t
*pool
)
518 *mark
= NULL
; /* Seek to start of stream marker */
523 seek_handler_empty(void *baton
, const svn_stream_mark_t
*mark
)
531 svn_stream_empty(apr_pool_t
*pool
)
533 svn_stream_t
*stream
;
535 stream
= svn_stream_create(NULL
, pool
);
536 svn_stream_set_read2(stream
, read_handler_empty
, read_handler_empty
);
537 svn_stream_set_write(stream
, write_handler_empty
);
538 svn_stream_set_mark(stream
, mark_handler_empty
);
539 svn_stream_set_seek(stream
, seek_handler_empty
);
545 /*** Stream duplication support ***/
553 write_handler_tee(void *baton
, const char *data
, apr_size_t
*len
)
555 struct baton_tee
*bt
= baton
;
557 SVN_ERR(svn_stream_write(bt
->out1
, data
, len
));
558 SVN_ERR(svn_stream_write(bt
->out2
, data
, len
));
565 close_handler_tee(void *baton
)
567 struct baton_tee
*bt
= baton
;
569 SVN_ERR(svn_stream_close(bt
->out1
));
570 SVN_ERR(svn_stream_close(bt
->out2
));
577 svn_stream_tee(svn_stream_t
*out1
,
581 struct baton_tee
*baton
;
582 svn_stream_t
*stream
;
590 baton
= apr_palloc(pool
, sizeof(*baton
));
593 stream
= svn_stream_create(baton
, pool
);
594 svn_stream_set_write(stream
, write_handler_tee
);
595 svn_stream_set_close(stream
, close_handler_tee
);
602 /*** Ownership detaching stream ***/
605 read_handler_disown(void *baton
, char *buffer
, apr_size_t
*len
)
607 return svn_error_trace(svn_stream_read2(baton
, buffer
, len
));
611 read_full_handler_disown(void *baton
, char *buffer
, apr_size_t
*len
)
613 return svn_error_trace(svn_stream_read_full(baton
, buffer
, len
));
617 skip_handler_disown(void *baton
, apr_size_t len
)
619 return svn_error_trace(svn_stream_skip(baton
, len
));
623 write_handler_disown(void *baton
, const char *buffer
, apr_size_t
*len
)
625 return svn_error_trace(svn_stream_write(baton
, buffer
, len
));
629 mark_handler_disown(void *baton
, svn_stream_mark_t
**mark
, apr_pool_t
*pool
)
631 return svn_error_trace(svn_stream_mark(baton
, mark
, pool
));
635 seek_handler_disown(void *baton
, const svn_stream_mark_t
*mark
)
637 return svn_error_trace(svn_stream_seek(baton
, mark
));
641 data_available_disown(void *baton
, svn_boolean_t
*data_available
)
643 return svn_error_trace(svn_stream_data_available(baton
, data_available
));
647 readline_handler_disown(void *baton
,
648 svn_stringbuf_t
**stringbuf
,
653 return svn_error_trace(svn_stream_readline(baton
, stringbuf
, eol
,
658 svn_stream_disown(svn_stream_t
*stream
, apr_pool_t
*pool
)
660 svn_stream_t
*s
= svn_stream_create(stream
, pool
);
662 svn_stream_set_read2(s
, read_handler_disown
, read_full_handler_disown
);
663 svn_stream_set_skip(s
, skip_handler_disown
);
664 svn_stream_set_write(s
, write_handler_disown
);
665 svn_stream_set_mark(s
, mark_handler_disown
);
666 svn_stream_set_seek(s
, seek_handler_disown
);
667 svn_stream_set_data_available(s
, data_available_disown
);
668 svn_stream_set_readline(s
, readline_handler_disown
);
675 /*** Generic stream for APR files ***/
679 svn_boolean_t truncate_on_seek
;
682 /* svn_stream_mark_t for streams backed by APR files. */
688 read_handler_apr(void *baton
, char *buffer
, apr_size_t
*len
)
690 struct baton_apr
*btn
= baton
;
695 err
= svn_io_file_getc(buffer
, btn
->file
, btn
->pool
);
699 if (APR_STATUS_IS_EOF(err
->apr_err
))
701 svn_error_clear(err
);
708 err
= svn_io_file_read(btn
->file
, buffer
, len
, btn
->pool
);
709 if (err
&& APR_STATUS_IS_EOF(err
->apr_err
))
711 svn_error_clear(err
);
716 return svn_error_trace(err
);
720 read_full_handler_apr(void *baton
, char *buffer
, apr_size_t
*len
)
722 struct baton_apr
*btn
= baton
;
728 err
= svn_io_file_getc(buffer
, btn
->file
, btn
->pool
);
732 if (APR_STATUS_IS_EOF(err
->apr_err
))
734 svn_error_clear(err
);
740 err
= svn_io_file_read_full2(btn
->file
, buffer
, *len
, len
,
743 return svn_error_trace(err
);
747 skip_handler_apr(void *baton
, apr_size_t len
)
749 struct baton_apr
*btn
= baton
;
750 apr_off_t offset
= len
;
752 return svn_error_trace(
753 svn_io_file_seek(btn
->file
, APR_CUR
, &offset
, btn
->pool
));
757 write_handler_apr(void *baton
, const char *data
, apr_size_t
*len
)
759 struct baton_apr
*btn
= baton
;
764 err
= svn_io_file_putc(*data
, btn
->file
, btn
->pool
);
769 err
= svn_io_file_write_full(btn
->file
, data
, *len
, len
, btn
->pool
);
771 return svn_error_trace(err
);
775 close_handler_apr(void *baton
)
777 struct baton_apr
*btn
= baton
;
779 return svn_error_trace(svn_io_file_close(btn
->file
, btn
->pool
));
783 mark_handler_apr(void *baton
, svn_stream_mark_t
**mark
, apr_pool_t
*pool
)
785 struct baton_apr
*btn
= baton
;
786 struct mark_apr
*mark_apr
;
788 mark_apr
= apr_palloc(pool
, sizeof(*mark_apr
));
789 SVN_ERR(svn_io_file_get_offset(&mark_apr
->off
, btn
->file
, btn
->pool
));
790 *mark
= (svn_stream_mark_t
*)mark_apr
;
795 seek_handler_apr(void *baton
, const svn_stream_mark_t
*mark
)
797 struct baton_apr
*btn
= baton
;
798 apr_off_t offset
= (mark
!= NULL
) ? ((const struct mark_apr
*)mark
)->off
: 0;
800 if (btn
->truncate_on_seek
)
802 /* The apr_file_trunc() function always does seek + trunc,
803 * and this is documented, so don't seek when truncating. */
804 SVN_ERR(svn_io_file_trunc(btn
->file
, offset
, btn
->pool
));
808 SVN_ERR(svn_io_file_seek(btn
->file
, APR_SET
, &offset
, btn
->pool
));
815 data_available_handler_apr(void *baton
, svn_boolean_t
*data_available
)
817 struct baton_apr
*btn
= baton
;
819 #if !defined(WIN32) || APR_FILES_AS_SOCKETS
823 pfd
.desc_type
= APR_POLL_FILE
;
824 pfd
.desc
.f
= btn
->file
;
825 pfd
.p
= btn
->pool
; /* If we had a scratch pool... Luckily apr doesn't
826 store anything in this pool at this time */
827 pfd
.reqevents
= APR_POLLIN
;
829 status
= apr_poll(&pfd
, 1, &n
, 0);
831 if (status
== APR_SUCCESS
)
833 *data_available
= (n
> 0);
836 else if (APR_STATUS_IS_EOF(status
) || APR_STATUS_IS_TIMEUP(status
))
838 *data_available
= FALSE
;
843 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED
,
846 _("Polling for available data on filestream "
853 status
= apr_os_file_get(&h
, btn
->file
);
856 return svn_error_wrap_apr(status
, NULL
);
858 if (PeekNamedPipe(h
, NULL
, 0, NULL
, &dwAvail
, NULL
))
860 *data_available
= (dwAvail
> 0);
864 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED
,
865 svn_error_wrap_apr(apr_get_os_error(), NULL
),
866 _("Windows doesn't support polling on files"));
871 readline_apr_lf(apr_file_t
*file
,
872 svn_stringbuf_t
**stringbuf
,
876 svn_stringbuf_t
*buf
;
878 buf
= svn_stringbuf_create_ensure(SVN__LINE_CHUNK_SIZE
, pool
);
883 status
= apr_file_gets(buf
->data
+ buf
->len
,
884 (int) (buf
->blocksize
- buf
->len
),
886 buf
->len
+= strlen(buf
->data
+ buf
->len
);
888 if (APR_STATUS_IS_EOF(status
))
890 /* apr_file_gets() keeps the newline; strip it if necessary. */
891 if (buf
->len
> 0 && buf
->data
[buf
->len
- 1] == '\n')
892 svn_stringbuf_chop(buf
, 1);
898 else if (status
!= APR_SUCCESS
)
901 svn_error_t
*err
= svn_io_file_name_get(&fname
, file
, pool
);
904 svn_error_clear(err
);
907 return svn_error_wrap_apr(status
,
908 _("Can't read a line from file '%s'"),
909 svn_dirent_local_style(fname
, pool
));
911 return svn_error_wrap_apr(status
,
912 _("Can't read a line from stream"));
915 /* Do we have the EOL? If yes, strip it and return. */
916 if (buf
->len
> 0 && buf
->data
[buf
->len
- 1] == '\n')
918 svn_stringbuf_chop(buf
, 1);
924 /* Otherwise, prepare to read the next chunk. */
925 svn_stringbuf_ensure(buf
, buf
->blocksize
+ SVN__LINE_CHUNK_SIZE
);
930 readline_apr_generic(apr_file_t
*file
,
931 svn_stringbuf_t
**stringbuf
,
936 apr_size_t eol_len
= strlen(eol
);
938 svn_stringbuf_t
*buf
;
940 SVN_ERR(svn_io_file_get_offset(&offset
, file
, pool
));
942 buf
= svn_stringbuf_create_ensure(SVN__LINE_CHUNK_SIZE
, pool
);
945 apr_size_t bytes_read
;
946 svn_boolean_t hit_eof
;
947 const char *search_start
;
950 /* We look for the EOL in the new data plus the last part of the
951 previous chunk because the EOL may span over the boundary
952 between both chunks. */
953 if (buf
->len
< eol_len
)
954 search_start
= buf
->data
;
956 search_start
= buf
->data
+ buf
->len
- eol_len
;
958 SVN_ERR(svn_io_file_read_full2(file
, buf
->data
+ buf
->len
,
959 buf
->blocksize
- buf
->len
- 1,
960 &bytes_read
, &hit_eof
, pool
));
961 buf
->len
+= bytes_read
;
962 buf
->data
[buf
->len
] = '\0';
964 /* Do we have the EOL now? */
965 eol_pos
= strstr(search_start
, eol
);
968 svn_stringbuf_chop(buf
, buf
->data
+ buf
->len
- eol_pos
);
969 /* Seek to the first position behind the EOL. */
970 offset
+= (buf
->len
+ eol_len
);
971 SVN_ERR(svn_io_file_seek(file
, APR_SET
, &offset
, pool
));
977 else if (eol_pos
== NULL
&& hit_eof
)
984 /* Prepare to read the next chunk. */
985 svn_stringbuf_ensure(buf
, buf
->blocksize
+ SVN__LINE_CHUNK_SIZE
);
990 readline_handler_apr(void *baton
,
991 svn_stringbuf_t
**stringbuf
,
996 struct baton_apr
*btn
= baton
;
998 if (eol
[0] == '\n' && eol
[1] == '\0')
1000 /* Optimize the common case when we're looking for an LF ("\n")
1001 end-of-line sequence by using apr_file_gets(). */
1002 return svn_error_trace(readline_apr_lf(btn
->file
, stringbuf
,
1007 return svn_error_trace(readline_apr_generic(btn
->file
, stringbuf
,
1013 svn_stream_open_readonly(svn_stream_t
**stream
,
1015 apr_pool_t
*result_pool
,
1016 apr_pool_t
*scratch_pool
)
1020 SVN_ERR(svn_io_file_open(&file
, path
, APR_READ
| APR_BUFFERED
,
1021 APR_OS_DEFAULT
, result_pool
));
1022 *stream
= svn_stream_from_aprfile2(file
, FALSE
, result_pool
);
1024 return SVN_NO_ERROR
;
1029 svn_stream_open_writable(svn_stream_t
**stream
,
1031 apr_pool_t
*result_pool
,
1032 apr_pool_t
*scratch_pool
)
1036 SVN_ERR(svn_io_file_open(&file
, path
,
1041 APR_OS_DEFAULT
, result_pool
));
1042 *stream
= svn_stream_from_aprfile2(file
, FALSE
, result_pool
);
1044 return SVN_NO_ERROR
;
1049 svn_stream_open_unique(svn_stream_t
**stream
,
1050 const char **temp_path
,
1051 const char *dirpath
,
1052 svn_io_file_del_t delete_when
,
1053 apr_pool_t
*result_pool
,
1054 apr_pool_t
*scratch_pool
)
1058 SVN_ERR(svn_io_open_unique_file3(&file
, temp_path
, dirpath
,
1059 delete_when
, result_pool
, scratch_pool
));
1060 *stream
= svn_stream_from_aprfile2(file
, FALSE
, result_pool
);
1062 return SVN_NO_ERROR
;
1066 /* Helper function that creates a stream from an APR file. */
1067 static svn_stream_t
*
1068 make_stream_from_apr_file(apr_file_t
*file
,
1069 svn_boolean_t disown
,
1070 svn_boolean_t supports_seek
,
1071 svn_boolean_t truncate_on_seek
,
1074 struct baton_apr
*baton
;
1075 svn_stream_t
*stream
;
1078 return svn_stream_empty(pool
);
1080 baton
= apr_palloc(pool
, sizeof(*baton
));
1083 baton
->truncate_on_seek
= truncate_on_seek
;
1084 stream
= svn_stream_create(baton
, pool
);
1085 svn_stream_set_read2(stream
, read_handler_apr
, read_full_handler_apr
);
1086 svn_stream_set_write(stream
, write_handler_apr
);
1090 svn_stream_set_skip(stream
, skip_handler_apr
);
1091 svn_stream_set_mark(stream
, mark_handler_apr
);
1092 svn_stream_set_seek(stream
, seek_handler_apr
);
1093 svn_stream_set_readline(stream
, readline_handler_apr
);
1096 svn_stream_set_data_available(stream
, data_available_handler_apr
);
1097 stream
->file
= file
;
1100 svn_stream_set_close(stream
, close_handler_apr
);
1106 svn_stream__from_aprfile(apr_file_t
*file
,
1107 svn_boolean_t disown
,
1108 svn_boolean_t truncate_on_seek
,
1111 return make_stream_from_apr_file(file
, disown
, TRUE
, truncate_on_seek
, pool
);
1115 svn_stream_from_aprfile2(apr_file_t
*file
,
1116 svn_boolean_t disown
,
1119 return make_stream_from_apr_file(file
, disown
, TRUE
, FALSE
, pool
);
1123 svn_stream__aprfile(svn_stream_t
*stream
)
1125 return stream
->file
;
1129 /* Compressed stream support */
1131 #define ZBUFFER_SIZE 4096 /* The size of the buffer the
1132 compressed stream uses to read from
1133 the substream. Basically an
1134 arbitrary value, picked to be about
1138 z_stream
*in
; /* compressed stream for reading */
1139 z_stream
*out
; /* compressed stream for writing */
1140 void *substream
; /* The substream */
1141 void *read_buffer
; /* buffer used for reading from
1143 int read_flush
; /* what flush mode to use while
1145 apr_pool_t
*pool
; /* The pool this baton is allocated
1149 /* zlib alloc function. opaque is the pool we need. */
1151 zalloc(voidpf opaque
, uInt items
, uInt size
)
1153 apr_pool_t
*pool
= opaque
;
1155 return apr_palloc(pool
, items
* size
);
1158 /* zlib free function */
1160 zfree(voidpf opaque
, voidpf address
)
1162 /* Empty, since we allocate on the pool */
1165 /* Helper function to figure out the sync mode */
1166 static svn_error_t
*
1167 read_helper_gz(svn_stream_t
*substream
,
1169 uInt
*len
, int *zflush
)
1171 uInt orig_len
= *len
;
1173 /* There's no reason this value should grow bigger than the range of
1174 uInt, but Subversion's API requires apr_size_t. */
1175 apr_size_t apr_len
= (apr_size_t
) *len
;
1177 SVN_ERR(svn_stream_read_full(substream
, buffer
, &apr_len
));
1179 /* Type cast back to uInt type that zlib uses. On LP64 platforms
1180 apr_size_t will be bigger than uInt. */
1181 *len
= (uInt
) apr_len
;
1183 /* I wanted to use Z_FINISH here, but we need to know our buffer is
1185 *zflush
= (*len
) < orig_len
? Z_SYNC_FLUSH
: Z_SYNC_FLUSH
;
1187 return SVN_NO_ERROR
;
1190 /* Handle reading from a compressed stream */
1191 static svn_error_t
*
1192 read_handler_gz(void *baton
, char *buffer
, apr_size_t
*len
)
1194 struct zbaton
*btn
= baton
;
1197 if (btn
->in
== NULL
)
1199 btn
->in
= apr_palloc(btn
->pool
, sizeof(z_stream
));
1200 btn
->in
->zalloc
= zalloc
;
1201 btn
->in
->zfree
= zfree
;
1202 btn
->in
->opaque
= btn
->pool
;
1203 btn
->read_buffer
= apr_palloc(btn
->pool
, ZBUFFER_SIZE
);
1204 btn
->in
->next_in
= btn
->read_buffer
;
1205 btn
->in
->avail_in
= ZBUFFER_SIZE
;
1207 SVN_ERR(read_helper_gz(btn
->substream
, btn
->read_buffer
,
1208 &btn
->in
->avail_in
, &btn
->read_flush
));
1210 zerr
= inflateInit(btn
->in
);
1211 SVN_ERR(svn_error__wrap_zlib(zerr
, "inflateInit", btn
->in
->msg
));
1214 btn
->in
->next_out
= (Bytef
*) buffer
;
1215 btn
->in
->avail_out
= (uInt
) *len
;
1217 while (btn
->in
->avail_out
> 0)
1219 if (btn
->in
->avail_in
<= 0)
1221 btn
->in
->avail_in
= ZBUFFER_SIZE
;
1222 btn
->in
->next_in
= btn
->read_buffer
;
1223 SVN_ERR(read_helper_gz(btn
->substream
, btn
->read_buffer
,
1224 &btn
->in
->avail_in
, &btn
->read_flush
));
1227 /* Short read means underlying stream has run out. */
1228 if (btn
->in
->avail_in
== 0)
1231 return SVN_NO_ERROR
;
1234 zerr
= inflate(btn
->in
, btn
->read_flush
);
1235 if (zerr
== Z_STREAM_END
)
1237 else if (zerr
!= Z_OK
)
1238 return svn_error_trace(svn_error__wrap_zlib(zerr
, "inflate",
1242 *len
-= btn
->in
->avail_out
;
1243 return SVN_NO_ERROR
;
1246 /* Compress data and write it to the substream */
1247 static svn_error_t
*
1248 write_handler_gz(void *baton
, const char *buffer
, apr_size_t
*len
)
1250 struct zbaton
*btn
= baton
;
1251 apr_pool_t
*subpool
;
1253 apr_size_t buf_size
, write_len
;
1256 if (btn
->out
== NULL
)
1258 btn
->out
= apr_palloc(btn
->pool
, sizeof(z_stream
));
1259 btn
->out
->zalloc
= zalloc
;
1260 btn
->out
->zfree
= zfree
;
1261 btn
->out
->opaque
= btn
->pool
;
1263 zerr
= deflateInit(btn
->out
, Z_DEFAULT_COMPRESSION
);
1264 SVN_ERR(svn_error__wrap_zlib(zerr
, "deflateInit", btn
->out
->msg
));
1267 /* The largest buffer we should need is 0.1% larger than the
1268 compressed data, + 12 bytes. This info comes from zlib.h. */
1269 buf_size
= *len
+ (*len
/ 1000) + 13;
1270 subpool
= svn_pool_create(btn
->pool
);
1271 write_buf
= apr_palloc(subpool
, buf_size
);
1273 btn
->out
->next_in
= (Bytef
*) buffer
; /* Casting away const! */
1274 btn
->out
->avail_in
= (uInt
) *len
;
1276 while (btn
->out
->avail_in
> 0)
1278 btn
->out
->next_out
= write_buf
;
1279 btn
->out
->avail_out
= (uInt
) buf_size
;
1281 zerr
= deflate(btn
->out
, Z_NO_FLUSH
);
1282 SVN_ERR(svn_error__wrap_zlib(zerr
, "deflate", btn
->out
->msg
));
1283 write_len
= buf_size
- btn
->out
->avail_out
;
1285 SVN_ERR(svn_stream_write(btn
->substream
, write_buf
, &write_len
));
1288 svn_pool_destroy(subpool
);
1290 return SVN_NO_ERROR
;
1293 /* Handle flushing and closing the stream */
1294 static svn_error_t
*
1295 close_handler_gz(void *baton
)
1297 struct zbaton
*btn
= baton
;
1300 if (btn
->in
!= NULL
)
1302 zerr
= inflateEnd(btn
->in
);
1303 SVN_ERR(svn_error__wrap_zlib(zerr
, "inflateEnd", btn
->in
->msg
));
1306 if (btn
->out
!= NULL
)
1309 apr_size_t write_len
;
1311 buf
= apr_palloc(btn
->pool
, ZBUFFER_SIZE
);
1315 btn
->out
->next_out
= buf
;
1316 btn
->out
->avail_out
= ZBUFFER_SIZE
;
1318 zerr
= deflate(btn
->out
, Z_FINISH
);
1319 if (zerr
!= Z_STREAM_END
&& zerr
!= Z_OK
)
1320 return svn_error_trace(svn_error__wrap_zlib(zerr
, "deflate",
1322 write_len
= ZBUFFER_SIZE
- btn
->out
->avail_out
;
1324 SVN_ERR(svn_stream_write(btn
->substream
, buf
, &write_len
));
1325 if (zerr
== Z_STREAM_END
)
1329 zerr
= deflateEnd(btn
->out
);
1330 SVN_ERR(svn_error__wrap_zlib(zerr
, "deflateEnd", btn
->out
->msg
));
1333 return svn_error_trace(svn_stream_close(btn
->substream
));
1338 svn_stream_compressed(svn_stream_t
*stream
, apr_pool_t
*pool
)
1340 struct svn_stream_t
*zstream
;
1341 struct zbaton
*baton
;
1343 assert(stream
!= NULL
);
1345 baton
= apr_palloc(pool
, sizeof(*baton
));
1346 baton
->in
= baton
->out
= NULL
;
1347 baton
->substream
= stream
;
1349 baton
->read_buffer
= NULL
;
1350 baton
->read_flush
= Z_SYNC_FLUSH
;
1352 zstream
= svn_stream_create(baton
, pool
);
1353 svn_stream_set_read2(zstream
, NULL
/* only full read support */,
1355 svn_stream_set_write(zstream
, write_handler_gz
);
1356 svn_stream_set_close(zstream
, close_handler_gz
);
1362 /* Checksummed stream support */
1364 struct checksum_stream_baton
1366 svn_checksum_ctx_t
*read_ctx
, *write_ctx
;
1367 svn_checksum_t
**read_checksum
; /* Output value. */
1368 svn_checksum_t
**write_checksum
; /* Output value. */
1369 svn_stream_t
*proxy
;
1371 /* True if more data should be read when closing the stream. */
1372 svn_boolean_t read_more
;
1374 /* Pool to allocate read buffer and output values from. */
1378 static svn_error_t
*
1379 read_handler_checksum(void *baton
, char *buffer
, apr_size_t
*len
)
1381 struct checksum_stream_baton
*btn
= baton
;
1383 SVN_ERR(svn_stream_read2(btn
->proxy
, buffer
, len
));
1385 if (btn
->read_checksum
)
1386 SVN_ERR(svn_checksum_update(btn
->read_ctx
, buffer
, *len
));
1388 return SVN_NO_ERROR
;
1391 static svn_error_t
*
1392 read_full_handler_checksum(void *baton
, char *buffer
, apr_size_t
*len
)
1394 struct checksum_stream_baton
*btn
= baton
;
1395 apr_size_t saved_len
= *len
;
1397 SVN_ERR(svn_stream_read_full(btn
->proxy
, buffer
, len
));
1399 if (btn
->read_checksum
)
1400 SVN_ERR(svn_checksum_update(btn
->read_ctx
, buffer
, *len
));
1402 if (saved_len
!= *len
)
1403 btn
->read_more
= FALSE
;
1405 return SVN_NO_ERROR
;
1409 static svn_error_t
*
1410 write_handler_checksum(void *baton
, const char *buffer
, apr_size_t
*len
)
1412 struct checksum_stream_baton
*btn
= baton
;
1414 if (btn
->write_checksum
&& *len
> 0)
1415 SVN_ERR(svn_checksum_update(btn
->write_ctx
, buffer
, *len
));
1417 return svn_error_trace(svn_stream_write(btn
->proxy
, buffer
, len
));
1420 static svn_error_t
*
1421 data_available_handler_checksum(void *baton
, svn_boolean_t
*data_available
)
1423 struct checksum_stream_baton
*btn
= baton
;
1425 return svn_error_trace(svn_stream_data_available(btn
->proxy
,
1429 static svn_error_t
*
1430 close_handler_checksum(void *baton
)
1432 struct checksum_stream_baton
*btn
= baton
;
1434 /* If we're supposed to drain the stream, do so before finalizing the
1438 char *buf
= apr_palloc(btn
->pool
, SVN__STREAM_CHUNK_SIZE
);
1439 apr_size_t len
= SVN__STREAM_CHUNK_SIZE
;
1443 SVN_ERR(read_full_handler_checksum(baton
, buf
, &len
));
1445 while (btn
->read_more
);
1449 SVN_ERR(svn_checksum_final(btn
->read_checksum
, btn
->read_ctx
, btn
->pool
));
1452 SVN_ERR(svn_checksum_final(btn
->write_checksum
, btn
->write_ctx
, btn
->pool
));
1454 return svn_error_trace(svn_stream_close(btn
->proxy
));
1457 static svn_error_t
*
1458 seek_handler_checksum(void *baton
, const svn_stream_mark_t
*mark
)
1460 struct checksum_stream_baton
*btn
= baton
;
1462 /* Only reset support. */
1465 return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED
,
1471 SVN_ERR(svn_checksum_ctx_reset(btn
->read_ctx
));
1474 SVN_ERR(svn_checksum_ctx_reset(btn
->write_ctx
));
1476 SVN_ERR(svn_stream_reset(btn
->proxy
));
1479 return SVN_NO_ERROR
;
1484 svn_stream_checksummed2(svn_stream_t
*stream
,
1485 svn_checksum_t
**read_checksum
,
1486 svn_checksum_t
**write_checksum
,
1487 svn_checksum_kind_t checksum_kind
,
1488 svn_boolean_t read_all
,
1492 struct checksum_stream_baton
*baton
;
1494 if (read_checksum
== NULL
&& write_checksum
== NULL
)
1497 baton
= apr_palloc(pool
, sizeof(*baton
));
1499 baton
->read_ctx
= svn_checksum_ctx_create(checksum_kind
, pool
);
1501 baton
->read_ctx
= NULL
;
1504 baton
->write_ctx
= svn_checksum_ctx_create(checksum_kind
, pool
);
1506 baton
->write_ctx
= NULL
;
1508 baton
->read_checksum
= read_checksum
;
1509 baton
->write_checksum
= write_checksum
;
1510 baton
->proxy
= stream
;
1511 baton
->read_more
= read_all
;
1514 s
= svn_stream_create(baton
, pool
);
1515 svn_stream_set_read2(s
, read_handler_checksum
, read_full_handler_checksum
);
1516 svn_stream_set_write(s
, write_handler_checksum
);
1517 svn_stream_set_data_available(s
, data_available_handler_checksum
);
1518 svn_stream_set_close(s
, close_handler_checksum
);
1519 if (svn_stream_supports_reset(stream
))
1520 svn_stream_set_seek(s
, seek_handler_checksum
);
1524 /* Helper for svn_stream_contents_checksum() to compute checksum of
1525 * KIND of STREAM. This function doesn't close source stream. */
1526 static svn_error_t
*
1527 compute_stream_checksum(svn_checksum_t
**checksum
,
1528 svn_stream_t
*stream
,
1529 svn_checksum_kind_t kind
,
1530 apr_pool_t
*result_pool
,
1531 apr_pool_t
*scratch_pool
)
1533 svn_checksum_ctx_t
*ctx
= svn_checksum_ctx_create(kind
, scratch_pool
);
1534 char *buf
= apr_palloc(scratch_pool
, SVN__STREAM_CHUNK_SIZE
);
1538 apr_size_t len
= SVN__STREAM_CHUNK_SIZE
;
1540 SVN_ERR(svn_stream_read_full(stream
, buf
, &len
));
1543 SVN_ERR(svn_checksum_update(ctx
, buf
, len
));
1545 if (len
!= SVN__STREAM_CHUNK_SIZE
)
1548 SVN_ERR(svn_checksum_final(checksum
, ctx
, result_pool
));
1550 return SVN_NO_ERROR
;
1554 svn_stream_contents_checksum(svn_checksum_t
**checksum
,
1555 svn_stream_t
*stream
,
1556 svn_checksum_kind_t kind
,
1557 apr_pool_t
*result_pool
,
1558 apr_pool_t
*scratch_pool
)
1562 err
= compute_stream_checksum(checksum
, stream
, kind
,
1563 result_pool
, scratch_pool
);
1565 /* Close source stream in all cases. */
1566 return svn_error_compose_create(err
, svn_stream_close(stream
));
1569 /* Miscellaneous stream functions. */
1572 * [JAF] By considering the buffer size doubling algorithm we use, I think
1573 * the performance characteristics of this implementation are as follows:
1575 * When the effective hint is big enough for the actual data, it uses
1576 * minimal time and allocates space roughly equal to the effective hint.
1577 * Otherwise, it incurs a time overhead for copying an additional 1x to 2x
1578 * the actual length of data, and a space overhead of an additional 2x to
1579 * 3x the actual length.
1582 svn_stringbuf_from_stream(svn_stringbuf_t
**result
,
1583 svn_stream_t
*stream
,
1584 apr_size_t len_hint
,
1585 apr_pool_t
*result_pool
)
1587 #define MIN_READ_SIZE 64
1588 svn_stringbuf_t
*text
1589 = svn_stringbuf_create_ensure(MAX(len_hint
+ 1, MIN_READ_SIZE
),
1594 apr_size_t to_read
= text
->blocksize
- 1 - text
->len
;
1595 apr_size_t actually_read
= to_read
;
1597 SVN_ERR(svn_stream_read_full(stream
, text
->data
+ text
->len
, &actually_read
));
1598 text
->len
+= actually_read
;
1600 if (actually_read
< to_read
)
1603 if (text
->blocksize
- text
->len
< MIN_READ_SIZE
)
1604 svn_stringbuf_ensure(text
, text
->blocksize
* 2);
1607 text
->data
[text
->len
] = '\0';
1610 return SVN_NO_ERROR
;
1613 struct stringbuf_stream_baton
1615 svn_stringbuf_t
*str
;
1616 apr_size_t amt_read
;
1619 /* svn_stream_mark_t for streams backed by stringbufs. */
1620 struct stringbuf_stream_mark
{
1624 static svn_error_t
*
1625 read_handler_stringbuf(void *baton
, char *buffer
, apr_size_t
*len
)
1627 struct stringbuf_stream_baton
*btn
= baton
;
1628 apr_size_t left_to_read
= btn
->str
->len
- btn
->amt_read
;
1630 *len
= (*len
> left_to_read
) ? left_to_read
: *len
;
1631 memcpy(buffer
, btn
->str
->data
+ btn
->amt_read
, *len
);
1632 btn
->amt_read
+= *len
;
1633 return SVN_NO_ERROR
;
1636 static svn_error_t
*
1637 skip_handler_stringbuf(void *baton
, apr_size_t len
)
1639 struct stringbuf_stream_baton
*btn
= baton
;
1640 apr_size_t left_to_read
= btn
->str
->len
- btn
->amt_read
;
1642 len
= (len
> left_to_read
) ? left_to_read
: len
;
1643 btn
->amt_read
+= len
;
1644 return SVN_NO_ERROR
;
1647 static svn_error_t
*
1648 write_handler_stringbuf(void *baton
, const char *data
, apr_size_t
*len
)
1650 struct stringbuf_stream_baton
*btn
= baton
;
1652 svn_stringbuf_appendbytes(btn
->str
, data
, *len
);
1653 return SVN_NO_ERROR
;
1656 static svn_error_t
*
1657 mark_handler_stringbuf(void *baton
, svn_stream_mark_t
**mark
, apr_pool_t
*pool
)
1659 struct stringbuf_stream_baton
*btn
;
1660 struct stringbuf_stream_mark
*stringbuf_stream_mark
;
1664 stringbuf_stream_mark
= apr_palloc(pool
, sizeof(*stringbuf_stream_mark
));
1665 stringbuf_stream_mark
->pos
= btn
->amt_read
;
1666 *mark
= (svn_stream_mark_t
*)stringbuf_stream_mark
;
1667 return SVN_NO_ERROR
;
1670 static svn_error_t
*
1671 seek_handler_stringbuf(void *baton
, const svn_stream_mark_t
*mark
)
1673 struct stringbuf_stream_baton
*btn
= baton
;
1677 const struct stringbuf_stream_mark
*stringbuf_stream_mark
;
1679 stringbuf_stream_mark
= (const struct stringbuf_stream_mark
*)mark
;
1680 btn
->amt_read
= stringbuf_stream_mark
->pos
;
1685 return SVN_NO_ERROR
;
1688 static svn_error_t
*
1689 data_available_handler_stringbuf(void *baton
, svn_boolean_t
*data_available
)
1691 struct stringbuf_stream_baton
*btn
= baton
;
1693 *data_available
= ((btn
->str
->len
- btn
->amt_read
) > 0);
1694 return SVN_NO_ERROR
;
1697 static svn_error_t
*
1698 readline_handler_stringbuf(void *baton
,
1699 svn_stringbuf_t
**stringbuf
,
1704 struct stringbuf_stream_baton
*btn
= baton
;
1705 const char *pos
= btn
->str
->data
+ btn
->amt_read
;
1706 const char *eol_pos
;
1708 eol_pos
= strstr(pos
, eol
);
1711 apr_size_t eol_len
= strlen(eol
);
1714 *stringbuf
= svn_stringbuf_ncreate(pos
, eol_pos
- pos
, pool
);
1715 btn
->amt_read
+= (eol_pos
- pos
+ eol_len
);
1720 *stringbuf
= svn_stringbuf_ncreate(pos
, btn
->str
->len
- btn
->amt_read
,
1722 btn
->amt_read
= btn
->str
->len
;
1725 return SVN_NO_ERROR
;
1729 svn_stream_from_stringbuf(svn_stringbuf_t
*str
,
1732 svn_stream_t
*stream
;
1733 struct stringbuf_stream_baton
*baton
;
1736 return svn_stream_empty(pool
);
1738 baton
= apr_palloc(pool
, sizeof(*baton
));
1740 baton
->amt_read
= 0;
1741 stream
= svn_stream_create(baton
, pool
);
1742 svn_stream_set_read2(stream
, read_handler_stringbuf
, read_handler_stringbuf
);
1743 svn_stream_set_skip(stream
, skip_handler_stringbuf
);
1744 svn_stream_set_write(stream
, write_handler_stringbuf
);
1745 svn_stream_set_mark(stream
, mark_handler_stringbuf
);
1746 svn_stream_set_seek(stream
, seek_handler_stringbuf
);
1747 svn_stream_set_data_available(stream
, data_available_handler_stringbuf
);
1748 svn_stream_set_readline(stream
, readline_handler_stringbuf
);
1752 struct string_stream_baton
1754 const svn_string_t
*str
;
1755 apr_size_t amt_read
;
1758 /* svn_stream_mark_t for streams backed by stringbufs. */
1759 struct string_stream_mark
{
1763 static svn_error_t
*
1764 read_handler_string(void *baton
, char *buffer
, apr_size_t
*len
)
1766 struct string_stream_baton
*btn
= baton
;
1767 apr_size_t left_to_read
= btn
->str
->len
- btn
->amt_read
;
1769 *len
= (*len
> left_to_read
) ? left_to_read
: *len
;
1770 memcpy(buffer
, btn
->str
->data
+ btn
->amt_read
, *len
);
1771 btn
->amt_read
+= *len
;
1772 return SVN_NO_ERROR
;
1775 static svn_error_t
*
1776 mark_handler_string(void *baton
, svn_stream_mark_t
**mark
, apr_pool_t
*pool
)
1778 struct string_stream_baton
*btn
;
1779 struct string_stream_mark
*marker
;
1783 marker
= apr_palloc(pool
, sizeof(*marker
));
1784 marker
->pos
= btn
->amt_read
;
1785 *mark
= (svn_stream_mark_t
*)marker
;
1786 return SVN_NO_ERROR
;
1789 static svn_error_t
*
1790 seek_handler_string(void *baton
, const svn_stream_mark_t
*mark
)
1792 struct string_stream_baton
*btn
= baton
;
1796 const struct string_stream_mark
*marker
;
1798 marker
= (const struct string_stream_mark
*)mark
;
1799 btn
->amt_read
= marker
->pos
;
1804 return SVN_NO_ERROR
;
1807 static svn_error_t
*
1808 skip_handler_string(void *baton
, apr_size_t len
)
1810 struct string_stream_baton
*btn
= baton
;
1811 apr_size_t left_to_read
= btn
->str
->len
- btn
->amt_read
;
1813 len
= (len
> left_to_read
) ? left_to_read
: len
;
1814 btn
->amt_read
+= len
;
1815 return SVN_NO_ERROR
;
1818 static svn_error_t
*
1819 data_available_handler_string(void *baton
, svn_boolean_t
*data_available
)
1821 struct string_stream_baton
*btn
= baton
;
1823 *data_available
= ((btn
->str
->len
- btn
->amt_read
) > 0);
1824 return SVN_NO_ERROR
;
1827 static svn_error_t
*
1828 readline_handler_string(void *baton
,
1829 svn_stringbuf_t
**stringbuf
,
1834 struct string_stream_baton
*btn
= baton
;
1835 const char *pos
= btn
->str
->data
+ btn
->amt_read
;
1836 const char *eol_pos
;
1838 eol_pos
= strstr(pos
, eol
);
1841 apr_size_t eol_len
= strlen(eol
);
1844 *stringbuf
= svn_stringbuf_ncreate(pos
, eol_pos
- pos
, pool
);
1845 btn
->amt_read
+= (eol_pos
- pos
+ eol_len
);
1850 *stringbuf
= svn_stringbuf_ncreate(pos
, btn
->str
->len
- btn
->amt_read
,
1852 btn
->amt_read
= btn
->str
->len
;
1855 return SVN_NO_ERROR
;
1859 svn_stream_from_string(const svn_string_t
*str
,
1862 svn_stream_t
*stream
;
1863 struct string_stream_baton
*baton
;
1866 return svn_stream_empty(pool
);
1868 baton
= apr_palloc(pool
, sizeof(*baton
));
1870 baton
->amt_read
= 0;
1871 stream
= svn_stream_create(baton
, pool
);
1872 svn_stream_set_read2(stream
, read_handler_string
, read_handler_string
);
1873 svn_stream_set_mark(stream
, mark_handler_string
);
1874 svn_stream_set_seek(stream
, seek_handler_string
);
1875 svn_stream_set_skip(stream
, skip_handler_string
);
1876 svn_stream_set_data_available(stream
, data_available_handler_string
);
1877 svn_stream_set_readline(stream
, readline_handler_string
);
1883 svn_stream_for_stdin2(svn_stream_t
**in
,
1884 svn_boolean_t buffered
,
1887 apr_file_t
*stdin_file
;
1888 apr_status_t apr_err
;
1890 apr_uint32_t flags
= buffered
? APR_BUFFERED
: 0;
1891 apr_err
= apr_file_open_flags_stdin(&stdin_file
, flags
, pool
);
1893 return svn_error_wrap_apr(apr_err
, "Can't open stdin");
1895 /* STDIN may or may not support positioning requests, but generally
1896 it does not, or the behavior is implementation-specific. Hence,
1897 we cannot safely advertise mark(), seek() and non-default skip()
1899 *in
= make_stream_from_apr_file(stdin_file
, TRUE
, FALSE
, FALSE
, pool
);
1901 return SVN_NO_ERROR
;
1906 svn_stream_for_stdout(svn_stream_t
**out
, apr_pool_t
*pool
)
1908 apr_file_t
*stdout_file
;
1909 apr_status_t apr_err
;
1911 apr_err
= apr_file_open_stdout(&stdout_file
, pool
);
1913 return svn_error_wrap_apr(apr_err
, "Can't open stdout");
1915 /* STDOUT may or may not support positioning requests, but generally
1916 it does not, or the behavior is implementation-specific. Hence,
1917 we cannot safely advertise mark(), seek() and non-default skip()
1919 *out
= make_stream_from_apr_file(stdout_file
, TRUE
, FALSE
, FALSE
, pool
);
1921 return SVN_NO_ERROR
;
1926 svn_stream_for_stderr(svn_stream_t
**err
, apr_pool_t
*pool
)
1928 apr_file_t
*stderr_file
;
1929 apr_status_t apr_err
;
1931 apr_err
= apr_file_open_stderr(&stderr_file
, pool
);
1933 return svn_error_wrap_apr(apr_err
, "Can't open stderr");
1935 /* STDERR may or may not support positioning requests, but generally
1936 it does not, or the behavior is implementation-specific. Hence,
1937 we cannot safely advertise mark(), seek() and non-default skip()
1939 *err
= make_stream_from_apr_file(stderr_file
, TRUE
, FALSE
, FALSE
, pool
);
1941 return SVN_NO_ERROR
;
1946 svn_string_from_stream2(svn_string_t
**result
,
1947 svn_stream_t
*stream
,
1948 apr_size_t len_hint
,
1949 apr_pool_t
*result_pool
)
1951 svn_stringbuf_t
*buf
;
1953 SVN_ERR(svn_stringbuf_from_stream(&buf
, stream
, len_hint
, result_pool
));
1954 *result
= svn_stringbuf__morph_into_string(buf
);
1956 SVN_ERR(svn_stream_close(stream
));
1958 return SVN_NO_ERROR
;
1962 /* These are somewhat arbitrary, if we ever get good empirical data as to
1963 actually valid values, feel free to update them. */
1964 #define BUFFER_BLOCK_SIZE 1024
1965 #define BUFFER_MAX_SIZE 100000
1968 svn_stream_buffered(apr_pool_t
*result_pool
)
1970 return svn_stream__from_spillbuf(svn_spillbuf__create(BUFFER_BLOCK_SIZE
,
1978 /*** Lazyopen Streams ***/
1980 /* Custom baton for lazyopen-style wrapper streams. */
1981 typedef struct lazyopen_baton_t
{
1983 /* Callback function and baton for opening the wrapped stream. */
1984 svn_stream_lazyopen_func_t open_func
;
1987 /* The wrapped stream, or NULL if the stream hasn't yet been
1989 svn_stream_t
*real_stream
;
1992 /* Whether to open the wrapped stream on a close call. */
1993 svn_boolean_t open_on_close
;
1998 /* Use B->open_func/baton to create and set B->real_stream iff it
1999 isn't already set. */
2000 static svn_error_t
*
2001 lazyopen_if_unopened(lazyopen_baton_t
*b
)
2003 if (b
->real_stream
== NULL
)
2005 svn_stream_t
*stream
;
2006 apr_pool_t
*scratch_pool
= svn_pool_create(b
->pool
);
2008 SVN_ERR(b
->open_func(&stream
, b
->open_baton
,
2009 b
->pool
, scratch_pool
));
2011 svn_pool_destroy(scratch_pool
);
2013 b
->real_stream
= stream
;
2016 return SVN_NO_ERROR
;
2019 /* Implements svn_read_fn_t */
2020 static svn_error_t
*
2021 read_handler_lazyopen(void *baton
,
2025 lazyopen_baton_t
*b
= baton
;
2027 SVN_ERR(lazyopen_if_unopened(b
));
2028 SVN_ERR(svn_stream_read2(b
->real_stream
, buffer
, len
));
2030 return SVN_NO_ERROR
;
2033 /* Implements svn_read_fn_t */
2034 static svn_error_t
*
2035 read_full_handler_lazyopen(void *baton
,
2039 lazyopen_baton_t
*b
= baton
;
2041 SVN_ERR(lazyopen_if_unopened(b
));
2042 SVN_ERR(svn_stream_read_full(b
->real_stream
, buffer
, len
));
2044 return SVN_NO_ERROR
;
2047 /* Implements svn_stream_skip_fn_t */
2048 static svn_error_t
*
2049 skip_handler_lazyopen(void *baton
,
2052 lazyopen_baton_t
*b
= baton
;
2054 SVN_ERR(lazyopen_if_unopened(b
));
2055 SVN_ERR(svn_stream_skip(b
->real_stream
, len
));
2057 return SVN_NO_ERROR
;
2060 /* Implements svn_write_fn_t */
2061 static svn_error_t
*
2062 write_handler_lazyopen(void *baton
,
2066 lazyopen_baton_t
*b
= baton
;
2068 SVN_ERR(lazyopen_if_unopened(b
));
2069 SVN_ERR(svn_stream_write(b
->real_stream
, data
, len
));
2071 return SVN_NO_ERROR
;
2074 /* Implements svn_close_fn_t */
2075 static svn_error_t
*
2076 close_handler_lazyopen(void *baton
)
2078 lazyopen_baton_t
*b
= baton
;
2080 if (b
->open_on_close
)
2081 SVN_ERR(lazyopen_if_unopened(b
));
2083 SVN_ERR(svn_stream_close(b
->real_stream
));
2085 return SVN_NO_ERROR
;
2088 /* Implements svn_stream_mark_fn_t */
2089 static svn_error_t
*
2090 mark_handler_lazyopen(void *baton
,
2091 svn_stream_mark_t
**mark
,
2094 lazyopen_baton_t
*b
= baton
;
2096 SVN_ERR(lazyopen_if_unopened(b
));
2097 SVN_ERR(svn_stream_mark(b
->real_stream
, mark
, pool
));
2099 return SVN_NO_ERROR
;
2102 /* Implements svn_stream_seek_fn_t */
2103 static svn_error_t
*
2104 seek_handler_lazyopen(void *baton
,
2105 const svn_stream_mark_t
*mark
)
2107 lazyopen_baton_t
*b
= baton
;
2109 SVN_ERR(lazyopen_if_unopened(b
));
2110 SVN_ERR(svn_stream_seek(b
->real_stream
, mark
));
2112 return SVN_NO_ERROR
;
2115 static svn_error_t
*
2116 data_available_handler_lazyopen(void *baton
,
2117 svn_boolean_t
*data_available
)
2119 lazyopen_baton_t
*b
= baton
;
2121 SVN_ERR(lazyopen_if_unopened(b
));
2122 return svn_error_trace(svn_stream_data_available(b
->real_stream
,
2126 /* Implements svn_stream_readline_fn_t */
2127 static svn_error_t
*
2128 readline_handler_lazyopen(void *baton
,
2129 svn_stringbuf_t
**stringbuf
,
2134 lazyopen_baton_t
*b
= baton
;
2136 SVN_ERR(lazyopen_if_unopened(b
));
2137 return svn_error_trace(svn_stream_readline(b
->real_stream
, stringbuf
,
2142 svn_stream_lazyopen_create(svn_stream_lazyopen_func_t open_func
,
2144 svn_boolean_t open_on_close
,
2145 apr_pool_t
*result_pool
)
2147 lazyopen_baton_t
*lob
= apr_pcalloc(result_pool
, sizeof(*lob
));
2148 svn_stream_t
*stream
;
2150 lob
->open_func
= open_func
;
2151 lob
->open_baton
= open_baton
;
2152 lob
->real_stream
= NULL
;
2153 lob
->pool
= result_pool
;
2154 lob
->open_on_close
= open_on_close
;
2156 stream
= svn_stream_create(lob
, result_pool
);
2157 svn_stream_set_read2(stream
, read_handler_lazyopen
,
2158 read_full_handler_lazyopen
);
2159 svn_stream_set_skip(stream
, skip_handler_lazyopen
);
2160 svn_stream_set_write(stream
, write_handler_lazyopen
);
2161 svn_stream_set_close(stream
, close_handler_lazyopen
);
2162 svn_stream_set_mark(stream
, mark_handler_lazyopen
);
2163 svn_stream_set_seek(stream
, seek_handler_lazyopen
);
2164 svn_stream_set_data_available(stream
, data_available_handler_lazyopen
);
2165 svn_stream_set_readline(stream
, readline_handler_lazyopen
);
2170 /* Baton for install streams */
2171 struct install_baton_t
2173 struct baton_apr baton_apr
;
2174 const char *tmp_path
;
2179 /* Create and open a tempfile in DIRECTORY. Return its handle and path */
2180 static svn_error_t
*
2181 create_tempfile(HANDLE
*hFile
,
2182 const char **file_path
,
2183 const char *directory
,
2184 apr_pool_t
*result_pool
,
2185 apr_pool_t
*scratch_pool
)
2187 const char *unique_name
;
2188 apr_pool_t
*iterpool
= svn_pool_create(scratch_pool
);
2189 static svn_atomic_t tempname_counter
;
2190 int baseNr
= (GetTickCount() << 11) + 13 * svn_atomic_inc(&tempname_counter
)
2191 + GetCurrentProcessId();
2195 /* Shares common idea with io.c's temp_file_create */
2199 apr_uint32_t unique_nr
;
2202 /* Generate a number that should be unique for this application and
2203 usually for the entire computer to reduce the number of cycles
2204 through this loop. (A bit of calculation is much cheaper than
2206 unique_nr
= baseNr
+ 7 * i
++;
2209 svn_pool_clear(iterpool
);
2210 unique_name
= svn_dirent_join(directory
,
2211 apr_psprintf(iterpool
, "svn-%X",
2215 SVN_ERR(svn_io__utf8_to_unicode_longpath(&w_name
, unique_name
,
2218 /* Create a completely not-sharable file to avoid indexers, and other
2219 filesystem watchers locking the file while we are still writing.
2221 We need DELETE privileges to move the file. */
2222 h
= CreateFileW(w_name
, GENERIC_WRITE
| DELETE
, 0 /* share */,
2223 NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
2225 if (h
== INVALID_HANDLE_VALUE
)
2227 apr_status_t status
= apr_get_os_error();
2229 return svn_error_createf(SVN_ERR_IO_UNIQUE_NAMES_EXHAUSTED
,
2230 svn_error_wrap_apr(status
, NULL
),
2231 _("Unable to make name in '%s'"),
2232 svn_dirent_local_style(directory
, scratch_pool
));
2234 if (!APR_STATUS_IS_EEXIST(status
) && !APR_STATUS_IS_EACCES(status
))
2235 return svn_error_wrap_apr(status
, NULL
);
2238 while (h
== INVALID_HANDLE_VALUE
);
2241 *file_path
= apr_pstrdup(result_pool
, unique_name
);
2242 svn_pool_destroy(iterpool
);
2244 return SVN_NO_ERROR
;
2249 /* Implements svn_close_fn_t */
2250 static svn_error_t
*
2251 install_close(void *baton
)
2253 struct install_baton_t
*ib
= baton
;
2255 /* Flush the data cached in APR, but don't close the file yet */
2256 SVN_ERR(svn_io_file_flush(ib
->baton_apr
.file
, ib
->baton_apr
.pool
));
2258 return SVN_NO_ERROR
;
2262 svn_stream__create_for_install(svn_stream_t
**install_stream
,
2263 const char *tmp_abspath
,
2264 apr_pool_t
*result_pool
,
2265 apr_pool_t
*scratch_pool
)
2268 struct install_baton_t
*ib
;
2269 const char *tmp_path
;
2273 apr_status_t status
;
2275 SVN_ERR_ASSERT(svn_dirent_is_absolute(tmp_abspath
));
2277 SVN_ERR(create_tempfile(&hInstall
, &tmp_path
, tmp_abspath
,
2278 scratch_pool
, scratch_pool
));
2280 /* Wrap as a standard APR file to allow sharing implementation.
2282 But do note that some file functions (such as retrieving the name)
2283 don't work on this wrapper.
2284 Use buffered mode to match svn_io_open_unique_file3() behavior. */
2285 status
= apr_os_file_put(&file
, &hInstall
,
2286 APR_WRITE
| APR_BINARY
| APR_BUFFERED
,
2291 CloseHandle(hInstall
);
2292 return svn_error_wrap_apr(status
, NULL
);
2295 tmp_path
= svn_dirent_internal_style(tmp_path
, result_pool
);
2298 SVN_ERR_ASSERT(svn_dirent_is_absolute(tmp_abspath
));
2300 SVN_ERR(svn_io_open_unique_file3(&file
, &tmp_path
, tmp_abspath
,
2301 svn_io_file_del_none
,
2302 result_pool
, scratch_pool
));
2304 /* Set the temporary file to be truncated on seeks. */
2305 *install_stream
= svn_stream__from_aprfile(file
, FALSE
, TRUE
,
2308 ib
= apr_pcalloc(result_pool
, sizeof(*ib
));
2309 ib
->baton_apr
= *(struct baton_apr
*)(*install_stream
)->baton
;
2311 assert((void*)&ib
->baton_apr
== (void*)ib
); /* baton pointer is the same */
2313 (*install_stream
)->baton
= ib
;
2315 ib
->tmp_path
= tmp_path
;
2317 /* Don't close the file on stream close; flush instead */
2318 svn_stream_set_close(*install_stream
, install_close
);
2320 return SVN_NO_ERROR
;
2324 svn_stream__install_stream(svn_stream_t
*install_stream
,
2325 const char *final_abspath
,
2326 svn_boolean_t make_parents
,
2327 apr_pool_t
*scratch_pool
)
2329 struct install_baton_t
*ib
= install_stream
->baton
;
2332 SVN_ERR_ASSERT(svn_dirent_is_absolute(final_abspath
));
2334 err
= svn_io__win_rename_open_file(ib
->baton_apr
.file
, ib
->tmp_path
,
2335 final_abspath
, scratch_pool
);
2336 if (make_parents
&& err
&& APR_STATUS_IS_ENOENT(err
->apr_err
))
2340 err2
= svn_io_make_dir_recursively(svn_dirent_dirname(final_abspath
,
2345 return svn_error_trace(svn_error_compose_create(err
, err2
));
2347 svn_error_clear(err
);
2349 err
= svn_io__win_rename_open_file(ib
->baton_apr
.file
, ib
->tmp_path
,
2350 final_abspath
, scratch_pool
);
2353 /* ### rhuijben: I wouldn't be surprised if we later find out that we
2354 have to fall back to close+rename on some specific
2355 error values here, to support some non standard NAS
2356 and filesystem scenarios. */
2357 if (err
&& err
->apr_err
== SVN_ERR_UNSUPPORTED_FEATURE
)
2359 /* Rename open files is not supported on this platform: fallback to
2360 svn_io_file_rename2(). */
2361 svn_error_clear(err
);
2366 return svn_error_compose_create(err
,
2367 svn_io_file_close(ib
->baton_apr
.file
,
2372 /* Close temporary file. */
2373 SVN_ERR(svn_io_file_close(ib
->baton_apr
.file
, scratch_pool
));
2375 err
= svn_io_file_rename2(ib
->tmp_path
, final_abspath
, FALSE
, scratch_pool
);
2377 /* A missing directory is too common to not cover here. */
2378 if (make_parents
&& err
&& APR_STATUS_IS_ENOENT(err
->apr_err
))
2382 err2
= svn_io_make_dir_recursively(svn_dirent_dirname(final_abspath
,
2387 /* Creating directory didn't work: Return all errors */
2388 return svn_error_trace(svn_error_compose_create(err
, err2
));
2390 /* We could create a directory: retry install */
2391 svn_error_clear(err
);
2393 SVN_ERR(svn_io_file_rename2(ib
->tmp_path
, final_abspath
, FALSE
, scratch_pool
));
2398 return SVN_NO_ERROR
;
2402 svn_stream__install_get_info(apr_finfo_t
*finfo
,
2403 svn_stream_t
*install_stream
,
2405 apr_pool_t
*scratch_pool
)
2407 struct install_baton_t
*ib
= install_stream
->baton
;
2408 apr_status_t status
;
2410 status
= apr_file_info_get(finfo
, wanted
, ib
->baton_apr
.file
);
2413 return svn_error_wrap_apr(status
, NULL
);
2415 return SVN_NO_ERROR
;
2419 svn_stream__install_delete(svn_stream_t
*install_stream
,
2420 apr_pool_t
*scratch_pool
)
2422 struct install_baton_t
*ib
= install_stream
->baton
;
2427 /* Mark the file as delete on close to avoid having to reopen
2428 the file as part of the delete handling. */
2429 err
= svn_io__win_delete_file_on_close(ib
->baton_apr
.file
, ib
->tmp_path
,
2431 if (err
== SVN_NO_ERROR
)
2433 SVN_ERR(svn_io_file_close(ib
->baton_apr
.file
, scratch_pool
));
2434 return SVN_NO_ERROR
; /* File is already gone */
2437 /* Deleting file on close may be unsupported, so ignore errors and
2438 fallback to svn_io_remove_file2(). */
2439 svn_error_clear(err
);
2442 SVN_ERR(svn_io_file_close(ib
->baton_apr
.file
, scratch_pool
));
2444 return svn_error_trace(svn_io_remove_file2(ib
->tmp_path
, FALSE
,