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 "private/svn_atomic.h"
46 #include "private/svn_error_private.h"
47 #include "private/svn_eol_private.h"
48 #include "private/svn_io_private.h"
49 #include "private/svn_subr_private.h"
50 #include "private/svn_utf_private.h"
55 svn_read_fn_t read_fn;
56 svn_read_fn_t read_full_fn;
57 svn_stream_skip_fn_t skip_fn;
58 svn_write_fn_t write_fn;
59 svn_close_fn_t close_fn;
60 svn_stream_mark_fn_t mark_fn;
61 svn_stream_seek_fn_t seek_fn;
62 svn_stream_data_available_fn_t data_available_fn;
63 svn_stream__is_buffered_fn_t is_buffered_fn;
64 apr_file_t *file; /* Maybe NULL */
68 /*** Forward declarations. ***/
71 skip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_full_fn);
74 /*** Generic streams. ***/
77 svn_stream_create(void *baton, apr_pool_t *pool)
81 stream = apr_pcalloc(pool, sizeof(*stream));
82 stream->baton = baton;
88 svn_stream_set_baton(svn_stream_t *stream, void *baton)
90 stream->baton = baton;
95 svn_stream_set_read2(svn_stream_t *stream,
96 svn_read_fn_t read_fn,
97 svn_read_fn_t read_full_fn)
99 stream->read_fn = read_fn;
100 stream->read_full_fn = read_full_fn;
104 svn_stream_set_skip(svn_stream_t *stream, svn_stream_skip_fn_t skip_fn)
106 stream->skip_fn = skip_fn;
110 svn_stream_set_write(svn_stream_t *stream, svn_write_fn_t write_fn)
112 stream->write_fn = write_fn;
116 svn_stream_set_close(svn_stream_t *stream, svn_close_fn_t close_fn)
118 stream->close_fn = close_fn;
122 svn_stream_set_mark(svn_stream_t *stream, svn_stream_mark_fn_t mark_fn)
124 stream->mark_fn = mark_fn;
128 svn_stream_set_seek(svn_stream_t *stream, svn_stream_seek_fn_t seek_fn)
130 stream->seek_fn = seek_fn;
134 svn_stream_set_data_available(svn_stream_t *stream,
135 svn_stream_data_available_fn_t data_available_fn)
137 stream->data_available_fn = data_available_fn;
141 svn_stream__set_is_buffered(svn_stream_t *stream,
142 svn_stream__is_buffered_fn_t is_buffered_fn)
144 stream->is_buffered_fn = is_buffered_fn;
147 /* Standard implementation for svn_stream_read_full() based on
148 multiple svn_stream_read2() calls (in separate function to make
149 it more likely for svn_stream_read_full to be inlined) */
151 full_read_fallback(svn_stream_t *stream, char *buffer, apr_size_t *len)
153 apr_size_t remaining = *len;
154 while (remaining > 0)
156 apr_size_t length = remaining;
157 SVN_ERR(svn_stream_read2(stream, buffer, &length));
173 svn_stream_supports_partial_read(svn_stream_t *stream)
175 return stream->read_fn != NULL;
179 svn_stream_read2(svn_stream_t *stream, char *buffer, apr_size_t *len)
181 if (stream->read_fn == NULL)
182 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, NULL, NULL);
184 return svn_error_trace(stream->read_fn(stream->baton, buffer, len));
188 svn_stream_read_full(svn_stream_t *stream, char *buffer, apr_size_t *len)
190 if (stream->read_full_fn == NULL)
191 return svn_error_trace(full_read_fallback(stream, buffer, len));
193 return svn_error_trace(stream->read_full_fn(stream->baton, buffer, len));
197 svn_stream_skip(svn_stream_t *stream, apr_size_t len)
199 if (stream->skip_fn == NULL)
200 return svn_error_trace(
201 skip_default_handler(stream->baton, len, stream->read_full_fn));
203 return svn_error_trace(stream->skip_fn(stream->baton, len));
208 svn_stream_write(svn_stream_t *stream, const char *data, apr_size_t *len)
210 if (stream->write_fn == NULL)
211 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, NULL, NULL);
213 return svn_error_trace(stream->write_fn(stream->baton, data, len));
218 svn_stream_reset(svn_stream_t *stream)
220 return svn_error_trace(
221 svn_stream_seek(stream, NULL));
225 svn_stream_supports_mark(svn_stream_t *stream)
227 return stream->mark_fn != NULL;
231 svn_stream_mark(svn_stream_t *stream, svn_stream_mark_t **mark,
234 if (stream->mark_fn == NULL)
235 return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
237 return svn_error_trace(stream->mark_fn(stream->baton, mark, pool));
241 svn_stream_seek(svn_stream_t *stream, const svn_stream_mark_t *mark)
243 if (stream->seek_fn == NULL)
244 return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
246 return svn_error_trace(stream->seek_fn(stream->baton, mark));
250 svn_stream_data_available(svn_stream_t *stream,
251 svn_boolean_t *data_available)
253 if (stream->data_available_fn == NULL)
254 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, NULL, NULL);
256 return svn_error_trace(stream->data_available_fn(stream->baton,
261 svn_stream__is_buffered(svn_stream_t *stream)
263 if (stream->is_buffered_fn == NULL)
266 return stream->is_buffered_fn(stream->baton);
270 svn_stream_close(svn_stream_t *stream)
272 if (stream->close_fn == NULL)
274 return svn_error_trace(stream->close_fn(stream->baton));
278 svn_stream_puts(svn_stream_t *stream,
283 return svn_error_trace(svn_stream_write(stream, str, &len));
287 svn_stream_printf(svn_stream_t *stream,
296 message = apr_pvsprintf(pool, fmt, ap);
299 return svn_error_trace(svn_stream_puts(stream, message));
304 svn_stream_printf_from_utf8(svn_stream_t *stream,
305 const char *encoding,
310 const char *message, *translated;
314 message = apr_pvsprintf(pool, fmt, ap);
317 SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated, message, encoding,
320 return svn_error_trace(svn_stream_puts(stream, translated));
323 /* Guts of svn_stream_readline().
324 * Returns the line read from STREAM in *STRINGBUF, and indicates
325 * end-of-file in *EOF. If DETECT_EOL is TRUE, the end-of-line indicator
326 * is detected automatically and returned in *EOL.
327 * If DETECT_EOL is FALSE, *EOL must point to the desired end-of-line
328 * indicator. STRINGBUF is allocated in POOL. */
330 stream_readline_bytewise(svn_stringbuf_t **stringbuf,
333 svn_stream_t *stream,
336 svn_stringbuf_t *str;
341 /* Since we're reading one character at a time, let's at least
342 optimize for the 90% case. 90% of the time, we can avoid the
343 stringbuf ever having to realloc() itself if we start it out at
345 str = svn_stringbuf_create_ensure(SVN__LINE_CHUNK_SIZE, pool);
347 /* Read into STR up to and including the next EOL sequence. */
352 SVN_ERR(svn_stream_read_full(stream, &c, &numbytes));
355 /* a 'short' read means the stream has run out. */
366 svn_stringbuf_appendbyte(str, c);
370 svn_stringbuf_chop(str, match - eol);
377 stream_readline_chunky(svn_stringbuf_t **stringbuf,
380 svn_stream_t *stream,
383 /* Read larger chunks of data at once into this buffer and scan
384 * that for EOL. A good chunk size should be about 80 chars since
385 * most text lines will be shorter. However, don't use a much
386 * larger value because filling the buffer from the stream takes
389 char buffer[SVN__LINE_CHUNK_SIZE+1];
392 svn_stream_mark_t *mark;
395 apr_size_t total_parsed = 0;
397 /* invariant for this call */
398 const size_t eol_len = strlen(eol);
400 /* Remember the line start so this plus the line length will be
401 * the position to move to at the end of this function.
403 SVN_ERR(svn_stream_mark(stream, &mark, pool));
405 /* Read the first chunk. */
406 numbytes = SVN__LINE_CHUNK_SIZE;
407 SVN_ERR(svn_stream_read_full(stream, buffer, &numbytes));
408 buffer[numbytes] = '\0';
410 /* Look for the EOL in this first chunk. If we find it, we are done here.
412 eol_pos = strstr(buffer, eol);
415 *stringbuf = svn_stringbuf_ncreate(buffer, eol_pos - buffer, pool);
416 total_parsed = eol_pos - buffer + eol_len;
418 else if (numbytes < SVN__LINE_CHUNK_SIZE)
420 /* We hit EOF but not EOL.
422 *stringbuf = svn_stringbuf_ncreate(buffer, numbytes, pool);
428 /* A larger buffer for the string is needed. */
429 svn_stringbuf_t *str;
430 str = svn_stringbuf_create_ensure(2*SVN__LINE_CHUNK_SIZE, pool);
431 svn_stringbuf_appendbytes(str, buffer, numbytes);
434 /* Loop reading chunks until an EOL was found. If we hit EOF, fall
435 * back to the standard implementation. */
438 /* Append the next chunk to the string read so far.
440 svn_stringbuf_ensure(str, str->len + SVN__LINE_CHUNK_SIZE);
441 numbytes = SVN__LINE_CHUNK_SIZE;
442 SVN_ERR(svn_stream_read_full(stream, str->data + str->len, &numbytes));
443 str->len += numbytes;
444 str->data[str->len] = '\0';
446 /* Look for the EOL in the new data plus the last part of the
447 * previous chunk because the EOL may span over the boundary
448 * between both chunks.
450 eol_pos = strstr(str->data + str->len - numbytes - (eol_len-1), eol);
452 if ((numbytes < SVN__LINE_CHUNK_SIZE) && (eol_pos == NULL))
454 /* We hit EOF instead of EOL. */
459 while (eol_pos == NULL);
461 /* Number of bytes we actually consumed (i.e. line + EOF).
462 * We need to "return" the rest to the stream by moving its
465 total_parsed = eol_pos - str->data + eol_len;
467 /* Terminate the string at the EOL postion and return it. */
468 str->len = eol_pos - str->data;
469 str->data[str->len] = 0;
472 /* Move the stream read pointer to the first position behind the EOL.
474 SVN_ERR(svn_stream_seek(stream, mark));
475 return svn_error_trace(svn_stream_skip(stream, total_parsed));
478 /* Guts of svn_stream_readline().
479 * Returns the line read from STREAM in *STRINGBUF, and indicates
480 * end-of-file in *EOF. EOL must point to the desired end-of-line
481 * indicator. STRINGBUF is allocated in POOL. */
483 stream_readline(svn_stringbuf_t **stringbuf,
486 svn_stream_t *stream,
491 /* Often, we operate on APR file or string-based streams and know what
492 * EOL we are looking for. Optimize that common case.
494 if (svn_stream_supports_mark(stream) &&
495 svn_stream__is_buffered(stream))
497 /* We can efficiently read chunks speculatively and reposition the
498 * stream pointer to the end of the line once we found that.
500 SVN_ERR(stream_readline_chunky(stringbuf,
508 /* Use the standard byte-byte implementation.
510 SVN_ERR(stream_readline_bytewise(stringbuf,
521 svn_stream_readline(svn_stream_t *stream,
522 svn_stringbuf_t **stringbuf,
527 return svn_error_trace(stream_readline(stringbuf, eof, eol, stream,
531 svn_error_t *svn_stream_copy3(svn_stream_t *from, svn_stream_t *to,
532 svn_cancel_func_t cancel_func,
534 apr_pool_t *scratch_pool)
536 char *buf = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE);
540 /* Read and write chunks until we get a short read, indicating the
541 end of the stream. (We can't get a short write without an
542 associated error.) */
545 apr_size_t len = SVN__STREAM_CHUNK_SIZE;
549 err = cancel_func(cancel_baton);
554 err = svn_stream_read_full(from, buf, &len);
559 err = svn_stream_write(to, buf, &len);
561 if (err || (len != SVN__STREAM_CHUNK_SIZE))
565 err2 = svn_error_compose_create(svn_stream_close(from),
566 svn_stream_close(to));
568 return svn_error_compose_create(err, err2);
572 svn_stream_contents_same2(svn_boolean_t *same,
573 svn_stream_t *stream1,
574 svn_stream_t *stream2,
577 char *buf1 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
578 char *buf2 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
579 apr_size_t bytes_read1 = SVN__STREAM_CHUNK_SIZE;
580 apr_size_t bytes_read2 = SVN__STREAM_CHUNK_SIZE;
581 svn_error_t *err = NULL;
583 *same = TRUE; /* assume TRUE, until disproved below */
584 while (bytes_read1 == SVN__STREAM_CHUNK_SIZE
585 && bytes_read2 == SVN__STREAM_CHUNK_SIZE)
587 err = svn_stream_read_full(stream1, buf1, &bytes_read1);
590 err = svn_stream_read_full(stream2, buf2, &bytes_read2);
594 if ((bytes_read1 != bytes_read2)
595 || (memcmp(buf1, buf2, bytes_read1)))
602 return svn_error_compose_create(err,
603 svn_error_compose_create(
604 svn_stream_close(stream1),
605 svn_stream_close(stream2)));
609 /*** Stream implementation utilities ***/
611 /* Skip data from any stream by reading and simply discarding it. */
613 skip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_full_fn)
615 apr_size_t bytes_read = 1;
617 apr_size_t to_read = len;
619 while ((to_read > 0) && (bytes_read > 0))
621 bytes_read = sizeof(buffer) < to_read ? sizeof(buffer) : to_read;
622 SVN_ERR(read_full_fn(baton, buffer, &bytes_read));
623 to_read -= bytes_read;
631 /*** Generic readable empty stream ***/
634 read_handler_empty(void *baton, char *buffer, apr_size_t *len)
641 write_handler_empty(void *baton, const char *data, apr_size_t *len)
647 mark_handler_empty(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
649 *mark = NULL; /* Seek to start of stream marker */
654 seek_handler_empty(void *baton, const svn_stream_mark_t *mark)
660 is_buffered_handler_empty(void *baton)
667 svn_stream_empty(apr_pool_t *pool)
669 svn_stream_t *stream;
671 stream = svn_stream_create(NULL, pool);
672 svn_stream_set_read2(stream, read_handler_empty, read_handler_empty);
673 svn_stream_set_write(stream, write_handler_empty);
674 svn_stream_set_mark(stream, mark_handler_empty);
675 svn_stream_set_seek(stream, seek_handler_empty);
676 svn_stream__set_is_buffered(stream, is_buffered_handler_empty);
682 /*** Stream duplication support ***/
690 write_handler_tee(void *baton, const char *data, apr_size_t *len)
692 struct baton_tee *bt = baton;
694 SVN_ERR(svn_stream_write(bt->out1, data, len));
695 SVN_ERR(svn_stream_write(bt->out2, data, len));
702 close_handler_tee(void *baton)
704 struct baton_tee *bt = baton;
706 SVN_ERR(svn_stream_close(bt->out1));
707 SVN_ERR(svn_stream_close(bt->out2));
714 svn_stream_tee(svn_stream_t *out1,
718 struct baton_tee *baton;
719 svn_stream_t *stream;
727 baton = apr_palloc(pool, sizeof(*baton));
730 stream = svn_stream_create(baton, pool);
731 svn_stream_set_write(stream, write_handler_tee);
732 svn_stream_set_close(stream, close_handler_tee);
739 /*** Ownership detaching stream ***/
742 read_handler_disown(void *baton, char *buffer, apr_size_t *len)
744 return svn_error_trace(svn_stream_read2(baton, buffer, len));
748 read_full_handler_disown(void *baton, char *buffer, apr_size_t *len)
750 return svn_error_trace(svn_stream_read_full(baton, buffer, len));
754 skip_handler_disown(void *baton, apr_size_t len)
756 return svn_error_trace(svn_stream_skip(baton, len));
760 write_handler_disown(void *baton, const char *buffer, apr_size_t *len)
762 return svn_error_trace(svn_stream_write(baton, buffer, len));
766 mark_handler_disown(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
768 return svn_error_trace(svn_stream_mark(baton, mark, pool));
772 seek_handler_disown(void *baton, const svn_stream_mark_t *mark)
774 return svn_error_trace(svn_stream_seek(baton, mark));
778 data_available_disown(void *baton, svn_boolean_t *data_available)
780 return svn_error_trace(svn_stream_data_available(baton, data_available));
784 is_buffered_handler_disown(void *baton)
786 return svn_stream__is_buffered(baton);
790 svn_stream_disown(svn_stream_t *stream, apr_pool_t *pool)
792 svn_stream_t *s = svn_stream_create(stream, pool);
794 svn_stream_set_read2(s, read_handler_disown, read_full_handler_disown);
795 svn_stream_set_skip(s, skip_handler_disown);
796 svn_stream_set_write(s, write_handler_disown);
797 svn_stream_set_mark(s, mark_handler_disown);
798 svn_stream_set_seek(s, seek_handler_disown);
799 svn_stream_set_data_available(s, data_available_disown);
800 svn_stream__set_is_buffered(s, is_buffered_handler_disown);
807 /*** Generic stream for APR files ***/
813 /* svn_stream_mark_t for streams backed by APR files. */
819 read_handler_apr(void *baton, char *buffer, apr_size_t *len)
821 struct baton_apr *btn = baton;
826 err = svn_io_file_getc(buffer, btn->file, btn->pool);
830 if (APR_STATUS_IS_EOF(err->apr_err))
832 svn_error_clear(err);
839 err = svn_io_file_read(btn->file, buffer, len, btn->pool);
840 if (err && APR_STATUS_IS_EOF(err->apr_err))
842 svn_error_clear(err);
847 return svn_error_trace(err);
851 read_full_handler_apr(void *baton, char *buffer, apr_size_t *len)
853 struct baton_apr *btn = baton;
859 err = svn_io_file_getc(buffer, btn->file, btn->pool);
863 if (APR_STATUS_IS_EOF(err->apr_err))
865 svn_error_clear(err);
871 err = svn_io_file_read_full2(btn->file, buffer, *len, len,
874 return svn_error_trace(err);
878 skip_handler_apr(void *baton, apr_size_t len)
880 struct baton_apr *btn = baton;
881 apr_off_t offset = len;
883 return svn_error_trace(
884 svn_io_file_seek(btn->file, APR_CUR, &offset, btn->pool));
888 write_handler_apr(void *baton, const char *data, apr_size_t *len)
890 struct baton_apr *btn = baton;
895 err = svn_io_file_putc(*data, btn->file, btn->pool);
900 err = svn_io_file_write_full(btn->file, data, *len, len, btn->pool);
902 return svn_error_trace(err);
906 close_handler_apr(void *baton)
908 struct baton_apr *btn = baton;
910 return svn_error_trace(svn_io_file_close(btn->file, btn->pool));
914 mark_handler_apr(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
916 struct baton_apr *btn = baton;
917 struct mark_apr *mark_apr;
919 mark_apr = apr_palloc(pool, sizeof(*mark_apr));
921 SVN_ERR(svn_io_file_seek(btn->file, APR_CUR, &mark_apr->off, btn->pool));
922 *mark = (svn_stream_mark_t *)mark_apr;
927 seek_handler_apr(void *baton, const svn_stream_mark_t *mark)
929 struct baton_apr *btn = baton;
930 apr_off_t offset = (mark != NULL) ? ((const struct mark_apr *)mark)->off : 0;
932 SVN_ERR(svn_io_file_seek(btn->file, APR_SET, &offset, btn->pool));
938 data_available_handler_apr(void *baton, svn_boolean_t *data_available)
940 struct baton_apr *btn = baton;
942 #if !defined(WIN32) || APR_FILES_AS_SOCKETS
946 pfd.desc_type = APR_POLL_FILE;
947 pfd.desc.f = btn->file;
948 pfd.p = btn->pool; /* If we had a scratch pool... Luckily apr doesn't
949 store anything in this pool at this time */
950 pfd.reqevents = APR_POLLIN;
952 status = apr_poll(&pfd, 1, &n, 0);
954 if (status == APR_SUCCESS)
956 *data_available = (n > 0);
959 else if (APR_STATUS_IS_EOF(status) || APR_STATUS_IS_TIMEUP(status))
961 *data_available = FALSE;
966 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED,
969 _("Polling for available data on filestream "
976 status = apr_os_file_get(&h, btn->file);
979 return svn_error_wrap_apr(status, NULL);
981 if (PeekNamedPipe(h, NULL, 0, NULL, &dwAvail, NULL))
983 *data_available = (dwAvail > 0);
987 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED,
988 svn_error_wrap_apr(apr_get_os_error(), NULL),
989 _("Windows doesn't support polling on files"));
994 is_buffered_handler_apr(void *baton)
996 struct baton_apr *btn = baton;
997 return (apr_file_flags_get(btn->file) & APR_BUFFERED) != 0;
1001 svn_stream_open_readonly(svn_stream_t **stream,
1003 apr_pool_t *result_pool,
1004 apr_pool_t *scratch_pool)
1008 SVN_ERR(svn_io_file_open(&file, path, APR_READ | APR_BUFFERED,
1009 APR_OS_DEFAULT, result_pool));
1010 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
1012 return SVN_NO_ERROR;
1017 svn_stream_open_writable(svn_stream_t **stream,
1019 apr_pool_t *result_pool,
1020 apr_pool_t *scratch_pool)
1024 SVN_ERR(svn_io_file_open(&file, path,
1029 APR_OS_DEFAULT, result_pool));
1030 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
1032 return SVN_NO_ERROR;
1037 svn_stream_open_unique(svn_stream_t **stream,
1038 const char **temp_path,
1039 const char *dirpath,
1040 svn_io_file_del_t delete_when,
1041 apr_pool_t *result_pool,
1042 apr_pool_t *scratch_pool)
1046 SVN_ERR(svn_io_open_unique_file3(&file, temp_path, dirpath,
1047 delete_when, result_pool, scratch_pool));
1048 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
1050 return SVN_NO_ERROR;
1054 /* Helper function that creates a stream from an APR file. */
1055 static svn_stream_t *
1056 make_stream_from_apr_file(apr_file_t *file,
1057 svn_boolean_t disown,
1058 svn_boolean_t supports_seek,
1061 struct baton_apr *baton;
1062 svn_stream_t *stream;
1065 return svn_stream_empty(pool);
1067 baton = apr_palloc(pool, sizeof(*baton));
1070 stream = svn_stream_create(baton, pool);
1071 svn_stream_set_read2(stream, read_handler_apr, read_full_handler_apr);
1072 svn_stream_set_write(stream, write_handler_apr);
1076 svn_stream_set_skip(stream, skip_handler_apr);
1077 svn_stream_set_mark(stream, mark_handler_apr);
1078 svn_stream_set_seek(stream, seek_handler_apr);
1081 svn_stream_set_data_available(stream, data_available_handler_apr);
1082 svn_stream__set_is_buffered(stream, is_buffered_handler_apr);
1083 stream->file = file;
1086 svn_stream_set_close(stream, close_handler_apr);
1092 svn_stream_from_aprfile2(apr_file_t *file,
1093 svn_boolean_t disown,
1096 return make_stream_from_apr_file(file, disown, TRUE, pool);
1100 svn_stream__aprfile(svn_stream_t *stream)
1102 return stream->file;
1106 /* Compressed stream support */
1108 #define ZBUFFER_SIZE 4096 /* The size of the buffer the
1109 compressed stream uses to read from
1110 the substream. Basically an
1111 arbitrary value, picked to be about
1115 z_stream *in; /* compressed stream for reading */
1116 z_stream *out; /* compressed stream for writing */
1117 void *substream; /* The substream */
1118 void *read_buffer; /* buffer used for reading from
1120 int read_flush; /* what flush mode to use while
1122 apr_pool_t *pool; /* The pool this baton is allocated
1126 /* zlib alloc function. opaque is the pool we need. */
1128 zalloc(voidpf opaque, uInt items, uInt size)
1130 apr_pool_t *pool = opaque;
1132 return apr_palloc(pool, items * size);
1135 /* zlib free function */
1137 zfree(voidpf opaque, voidpf address)
1139 /* Empty, since we allocate on the pool */
1142 /* Helper function to figure out the sync mode */
1143 static svn_error_t *
1144 read_helper_gz(svn_stream_t *substream,
1146 uInt *len, int *zflush)
1148 uInt orig_len = *len;
1150 /* There's no reason this value should grow bigger than the range of
1151 uInt, but Subversion's API requires apr_size_t. */
1152 apr_size_t apr_len = (apr_size_t) *len;
1154 SVN_ERR(svn_stream_read_full(substream, buffer, &apr_len));
1156 /* Type cast back to uInt type that zlib uses. On LP64 platforms
1157 apr_size_t will be bigger than uInt. */
1158 *len = (uInt) apr_len;
1160 /* I wanted to use Z_FINISH here, but we need to know our buffer is
1162 *zflush = (*len) < orig_len ? Z_SYNC_FLUSH : Z_SYNC_FLUSH;
1164 return SVN_NO_ERROR;
1167 /* Handle reading from a compressed stream */
1168 static svn_error_t *
1169 read_handler_gz(void *baton, char *buffer, apr_size_t *len)
1171 struct zbaton *btn = baton;
1174 if (btn->in == NULL)
1176 btn->in = apr_palloc(btn->pool, sizeof(z_stream));
1177 btn->in->zalloc = zalloc;
1178 btn->in->zfree = zfree;
1179 btn->in->opaque = btn->pool;
1180 btn->read_buffer = apr_palloc(btn->pool, ZBUFFER_SIZE);
1181 btn->in->next_in = btn->read_buffer;
1182 btn->in->avail_in = ZBUFFER_SIZE;
1184 SVN_ERR(read_helper_gz(btn->substream, btn->read_buffer,
1185 &btn->in->avail_in, &btn->read_flush));
1187 zerr = inflateInit(btn->in);
1188 SVN_ERR(svn_error__wrap_zlib(zerr, "inflateInit", btn->in->msg));
1191 btn->in->next_out = (Bytef *) buffer;
1192 btn->in->avail_out = (uInt) *len;
1194 while (btn->in->avail_out > 0)
1196 if (btn->in->avail_in <= 0)
1198 btn->in->avail_in = ZBUFFER_SIZE;
1199 btn->in->next_in = btn->read_buffer;
1200 SVN_ERR(read_helper_gz(btn->substream, btn->read_buffer,
1201 &btn->in->avail_in, &btn->read_flush));
1204 /* Short read means underlying stream has run out. */
1205 if (btn->in->avail_in == 0)
1208 return SVN_NO_ERROR;
1211 zerr = inflate(btn->in, btn->read_flush);
1212 if (zerr == Z_STREAM_END)
1214 else if (zerr != Z_OK)
1215 return svn_error_trace(svn_error__wrap_zlib(zerr, "inflate",
1219 *len -= btn->in->avail_out;
1220 return SVN_NO_ERROR;
1223 /* Compress data and write it to the substream */
1224 static svn_error_t *
1225 write_handler_gz(void *baton, const char *buffer, apr_size_t *len)
1227 struct zbaton *btn = baton;
1228 apr_pool_t *subpool;
1230 apr_size_t buf_size, write_len;
1233 if (btn->out == NULL)
1235 btn->out = apr_palloc(btn->pool, sizeof(z_stream));
1236 btn->out->zalloc = zalloc;
1237 btn->out->zfree = zfree;
1238 btn->out->opaque = btn->pool;
1240 zerr = deflateInit(btn->out, Z_DEFAULT_COMPRESSION);
1241 SVN_ERR(svn_error__wrap_zlib(zerr, "deflateInit", btn->out->msg));
1244 /* The largest buffer we should need is 0.1% larger than the
1245 compressed data, + 12 bytes. This info comes from zlib.h. */
1246 buf_size = *len + (*len / 1000) + 13;
1247 subpool = svn_pool_create(btn->pool);
1248 write_buf = apr_palloc(subpool, buf_size);
1250 btn->out->next_in = (Bytef *) buffer; /* Casting away const! */
1251 btn->out->avail_in = (uInt) *len;
1253 while (btn->out->avail_in > 0)
1255 btn->out->next_out = write_buf;
1256 btn->out->avail_out = (uInt) buf_size;
1258 zerr = deflate(btn->out, Z_NO_FLUSH);
1259 SVN_ERR(svn_error__wrap_zlib(zerr, "deflate", btn->out->msg));
1260 write_len = buf_size - btn->out->avail_out;
1262 SVN_ERR(svn_stream_write(btn->substream, write_buf, &write_len));
1265 svn_pool_destroy(subpool);
1267 return SVN_NO_ERROR;
1270 /* Handle flushing and closing the stream */
1271 static svn_error_t *
1272 close_handler_gz(void *baton)
1274 struct zbaton *btn = baton;
1277 if (btn->in != NULL)
1279 zerr = inflateEnd(btn->in);
1280 SVN_ERR(svn_error__wrap_zlib(zerr, "inflateEnd", btn->in->msg));
1283 if (btn->out != NULL)
1286 apr_size_t write_len;
1288 buf = apr_palloc(btn->pool, ZBUFFER_SIZE);
1292 btn->out->next_out = buf;
1293 btn->out->avail_out = ZBUFFER_SIZE;
1295 zerr = deflate(btn->out, Z_FINISH);
1296 if (zerr != Z_STREAM_END && zerr != Z_OK)
1297 return svn_error_trace(svn_error__wrap_zlib(zerr, "deflate",
1299 write_len = ZBUFFER_SIZE - btn->out->avail_out;
1301 SVN_ERR(svn_stream_write(btn->substream, buf, &write_len));
1302 if (zerr == Z_STREAM_END)
1306 zerr = deflateEnd(btn->out);
1307 SVN_ERR(svn_error__wrap_zlib(zerr, "deflateEnd", btn->out->msg));
1310 return svn_error_trace(svn_stream_close(btn->substream));
1315 svn_stream_compressed(svn_stream_t *stream, apr_pool_t *pool)
1317 struct svn_stream_t *zstream;
1318 struct zbaton *baton;
1320 assert(stream != NULL);
1322 baton = apr_palloc(pool, sizeof(*baton));
1323 baton->in = baton->out = NULL;
1324 baton->substream = stream;
1326 baton->read_buffer = NULL;
1327 baton->read_flush = Z_SYNC_FLUSH;
1329 zstream = svn_stream_create(baton, pool);
1330 svn_stream_set_read2(zstream, NULL /* only full read support */,
1332 svn_stream_set_write(zstream, write_handler_gz);
1333 svn_stream_set_close(zstream, close_handler_gz);
1339 /* Checksummed stream support */
1341 struct checksum_stream_baton
1343 svn_checksum_ctx_t *read_ctx, *write_ctx;
1344 svn_checksum_t **read_checksum; /* Output value. */
1345 svn_checksum_t **write_checksum; /* Output value. */
1346 svn_stream_t *proxy;
1348 /* True if more data should be read when closing the stream. */
1349 svn_boolean_t read_more;
1351 /* Pool to allocate read buffer and output values from. */
1355 static svn_error_t *
1356 read_handler_checksum(void *baton, char *buffer, apr_size_t *len)
1358 struct checksum_stream_baton *btn = baton;
1360 SVN_ERR(svn_stream_read2(btn->proxy, buffer, len));
1362 if (btn->read_checksum)
1363 SVN_ERR(svn_checksum_update(btn->read_ctx, buffer, *len));
1365 return SVN_NO_ERROR;
1368 static svn_error_t *
1369 read_full_handler_checksum(void *baton, char *buffer, apr_size_t *len)
1371 struct checksum_stream_baton *btn = baton;
1372 apr_size_t saved_len = *len;
1374 SVN_ERR(svn_stream_read_full(btn->proxy, buffer, len));
1376 if (btn->read_checksum)
1377 SVN_ERR(svn_checksum_update(btn->read_ctx, buffer, *len));
1379 if (saved_len != *len)
1380 btn->read_more = FALSE;
1382 return SVN_NO_ERROR;
1386 static svn_error_t *
1387 write_handler_checksum(void *baton, const char *buffer, apr_size_t *len)
1389 struct checksum_stream_baton *btn = baton;
1391 if (btn->write_checksum && *len > 0)
1392 SVN_ERR(svn_checksum_update(btn->write_ctx, buffer, *len));
1394 return svn_error_trace(svn_stream_write(btn->proxy, buffer, len));
1397 static svn_error_t *
1398 data_available_handler_checksum(void *baton, svn_boolean_t *data_available)
1400 struct checksum_stream_baton *btn = baton;
1402 return svn_error_trace(svn_stream_data_available(btn->proxy,
1406 static svn_error_t *
1407 close_handler_checksum(void *baton)
1409 struct checksum_stream_baton *btn = baton;
1411 /* If we're supposed to drain the stream, do so before finalizing the
1415 char *buf = apr_palloc(btn->pool, SVN__STREAM_CHUNK_SIZE);
1416 apr_size_t len = SVN__STREAM_CHUNK_SIZE;
1420 SVN_ERR(read_full_handler_checksum(baton, buf, &len));
1422 while (btn->read_more);
1426 SVN_ERR(svn_checksum_final(btn->read_checksum, btn->read_ctx, btn->pool));
1429 SVN_ERR(svn_checksum_final(btn->write_checksum, btn->write_ctx, btn->pool));
1431 return svn_error_trace(svn_stream_close(btn->proxy));
1436 svn_stream_checksummed2(svn_stream_t *stream,
1437 svn_checksum_t **read_checksum,
1438 svn_checksum_t **write_checksum,
1439 svn_checksum_kind_t checksum_kind,
1440 svn_boolean_t read_all,
1444 struct checksum_stream_baton *baton;
1446 if (read_checksum == NULL && write_checksum == NULL)
1449 baton = apr_palloc(pool, sizeof(*baton));
1451 baton->read_ctx = svn_checksum_ctx_create(checksum_kind, pool);
1453 baton->read_ctx = NULL;
1456 baton->write_ctx = svn_checksum_ctx_create(checksum_kind, pool);
1458 baton->write_ctx = NULL;
1460 baton->read_checksum = read_checksum;
1461 baton->write_checksum = write_checksum;
1462 baton->proxy = stream;
1463 baton->read_more = read_all;
1466 s = svn_stream_create(baton, pool);
1467 svn_stream_set_read2(s, read_handler_checksum, read_full_handler_checksum);
1468 svn_stream_set_write(s, write_handler_checksum);
1469 svn_stream_set_data_available(s, data_available_handler_checksum);
1470 svn_stream_set_close(s, close_handler_checksum);
1474 /* Miscellaneous stream functions. */
1477 svn_stringbuf_from_stream(svn_stringbuf_t **str,
1478 svn_stream_t *stream,
1479 apr_size_t len_hint,
1480 apr_pool_t *result_pool)
1482 #define MIN_READ_SIZE 64
1484 apr_size_t to_read = 0;
1485 svn_stringbuf_t *text
1486 = svn_stringbuf_create_ensure(len_hint ? len_hint : MIN_READ_SIZE,
1491 to_read = text->blocksize - 1 - text->len;
1492 SVN_ERR(svn_stream_read_full(stream, text->data + text->len, &to_read));
1493 text->len += to_read;
1495 if (to_read && text->blocksize < text->len + MIN_READ_SIZE)
1496 svn_stringbuf_ensure(text, text->blocksize * 2);
1500 text->data[text->len] = '\0';
1503 return SVN_NO_ERROR;
1506 struct stringbuf_stream_baton
1508 svn_stringbuf_t *str;
1509 apr_size_t amt_read;
1512 /* svn_stream_mark_t for streams backed by stringbufs. */
1513 struct stringbuf_stream_mark {
1517 static svn_error_t *
1518 read_handler_stringbuf(void *baton, char *buffer, apr_size_t *len)
1520 struct stringbuf_stream_baton *btn = baton;
1521 apr_size_t left_to_read = btn->str->len - btn->amt_read;
1523 *len = (*len > left_to_read) ? left_to_read : *len;
1524 memcpy(buffer, btn->str->data + btn->amt_read, *len);
1525 btn->amt_read += *len;
1526 return SVN_NO_ERROR;
1529 static svn_error_t *
1530 skip_handler_stringbuf(void *baton, apr_size_t len)
1532 struct stringbuf_stream_baton *btn = baton;
1533 apr_size_t left_to_read = btn->str->len - btn->amt_read;
1535 len = (len > left_to_read) ? left_to_read : len;
1536 btn->amt_read += len;
1537 return SVN_NO_ERROR;
1540 static svn_error_t *
1541 write_handler_stringbuf(void *baton, const char *data, apr_size_t *len)
1543 struct stringbuf_stream_baton *btn = baton;
1545 svn_stringbuf_appendbytes(btn->str, data, *len);
1546 return SVN_NO_ERROR;
1549 static svn_error_t *
1550 mark_handler_stringbuf(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
1552 struct stringbuf_stream_baton *btn;
1553 struct stringbuf_stream_mark *stringbuf_stream_mark;
1557 stringbuf_stream_mark = apr_palloc(pool, sizeof(*stringbuf_stream_mark));
1558 stringbuf_stream_mark->pos = btn->amt_read;
1559 *mark = (svn_stream_mark_t *)stringbuf_stream_mark;
1560 return SVN_NO_ERROR;
1563 static svn_error_t *
1564 seek_handler_stringbuf(void *baton, const svn_stream_mark_t *mark)
1566 struct stringbuf_stream_baton *btn = baton;
1570 const struct stringbuf_stream_mark *stringbuf_stream_mark;
1572 stringbuf_stream_mark = (const struct stringbuf_stream_mark *)mark;
1573 btn->amt_read = stringbuf_stream_mark->pos;
1578 return SVN_NO_ERROR;
1581 static svn_error_t *
1582 data_available_handler_stringbuf(void *baton, svn_boolean_t *data_available)
1584 struct stringbuf_stream_baton *btn = baton;
1586 *data_available = ((btn->str->len - btn->amt_read) > 0);
1587 return SVN_NO_ERROR;
1590 static svn_boolean_t
1591 is_buffered_handler_stringbuf(void *baton)
1597 svn_stream_from_stringbuf(svn_stringbuf_t *str,
1600 svn_stream_t *stream;
1601 struct stringbuf_stream_baton *baton;
1604 return svn_stream_empty(pool);
1606 baton = apr_palloc(pool, sizeof(*baton));
1608 baton->amt_read = 0;
1609 stream = svn_stream_create(baton, pool);
1610 svn_stream_set_read2(stream, read_handler_stringbuf, read_handler_stringbuf);
1611 svn_stream_set_skip(stream, skip_handler_stringbuf);
1612 svn_stream_set_write(stream, write_handler_stringbuf);
1613 svn_stream_set_mark(stream, mark_handler_stringbuf);
1614 svn_stream_set_seek(stream, seek_handler_stringbuf);
1615 svn_stream_set_data_available(stream, data_available_handler_stringbuf);
1616 svn_stream__set_is_buffered(stream, is_buffered_handler_stringbuf);
1620 struct string_stream_baton
1622 const svn_string_t *str;
1623 apr_size_t amt_read;
1626 /* svn_stream_mark_t for streams backed by stringbufs. */
1627 struct string_stream_mark {
1631 static svn_error_t *
1632 read_handler_string(void *baton, char *buffer, apr_size_t *len)
1634 struct string_stream_baton *btn = baton;
1635 apr_size_t left_to_read = btn->str->len - btn->amt_read;
1637 *len = (*len > left_to_read) ? left_to_read : *len;
1638 memcpy(buffer, btn->str->data + btn->amt_read, *len);
1639 btn->amt_read += *len;
1640 return SVN_NO_ERROR;
1643 static svn_error_t *
1644 mark_handler_string(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
1646 struct string_stream_baton *btn;
1647 struct string_stream_mark *marker;
1651 marker = apr_palloc(pool, sizeof(*marker));
1652 marker->pos = btn->amt_read;
1653 *mark = (svn_stream_mark_t *)marker;
1654 return SVN_NO_ERROR;
1657 static svn_error_t *
1658 seek_handler_string(void *baton, const svn_stream_mark_t *mark)
1660 struct string_stream_baton *btn = baton;
1664 const struct string_stream_mark *marker;
1666 marker = (const struct string_stream_mark *)mark;
1667 btn->amt_read = marker->pos;
1672 return SVN_NO_ERROR;
1675 static svn_error_t *
1676 skip_handler_string(void *baton, apr_size_t len)
1678 struct string_stream_baton *btn = baton;
1679 apr_size_t left_to_read = btn->str->len - btn->amt_read;
1681 len = (len > left_to_read) ? left_to_read : len;
1682 btn->amt_read += len;
1683 return SVN_NO_ERROR;
1686 static svn_error_t *
1687 data_available_handler_string(void *baton, svn_boolean_t *data_available)
1689 struct string_stream_baton *btn = baton;
1691 *data_available = ((btn->str->len - btn->amt_read) > 0);
1692 return SVN_NO_ERROR;
1695 static svn_boolean_t
1696 is_buffered_handler_string(void *baton)
1702 svn_stream_from_string(const svn_string_t *str,
1705 svn_stream_t *stream;
1706 struct string_stream_baton *baton;
1709 return svn_stream_empty(pool);
1711 baton = apr_palloc(pool, sizeof(*baton));
1713 baton->amt_read = 0;
1714 stream = svn_stream_create(baton, pool);
1715 svn_stream_set_read2(stream, read_handler_string, read_handler_string);
1716 svn_stream_set_mark(stream, mark_handler_string);
1717 svn_stream_set_seek(stream, seek_handler_string);
1718 svn_stream_set_skip(stream, skip_handler_string);
1719 svn_stream_set_data_available(stream, data_available_handler_string);
1720 svn_stream__set_is_buffered(stream, is_buffered_handler_string);
1726 svn_stream_for_stdin(svn_stream_t **in, apr_pool_t *pool)
1728 apr_file_t *stdin_file;
1729 apr_status_t apr_err;
1731 apr_err = apr_file_open_stdin(&stdin_file, pool);
1733 return svn_error_wrap_apr(apr_err, "Can't open stdin");
1735 /* STDIN may or may not support positioning requests, but generally
1736 it does not, or the behavior is implementation-specific. Hence,
1737 we cannot safely advertise mark(), seek() and non-default skip()
1739 *in = make_stream_from_apr_file(stdin_file, TRUE, FALSE, pool);
1741 return SVN_NO_ERROR;
1746 svn_stream_for_stdout(svn_stream_t **out, apr_pool_t *pool)
1748 apr_file_t *stdout_file;
1749 apr_status_t apr_err;
1751 apr_err = apr_file_open_stdout(&stdout_file, pool);
1753 return svn_error_wrap_apr(apr_err, "Can't open stdout");
1755 /* STDOUT may or may not support positioning requests, but generally
1756 it does not, or the behavior is implementation-specific. Hence,
1757 we cannot safely advertise mark(), seek() and non-default skip()
1759 *out = make_stream_from_apr_file(stdout_file, TRUE, FALSE, pool);
1761 return SVN_NO_ERROR;
1766 svn_stream_for_stderr(svn_stream_t **err, apr_pool_t *pool)
1768 apr_file_t *stderr_file;
1769 apr_status_t apr_err;
1771 apr_err = apr_file_open_stderr(&stderr_file, pool);
1773 return svn_error_wrap_apr(apr_err, "Can't open stderr");
1775 /* STDERR may or may not support positioning requests, but generally
1776 it does not, or the behavior is implementation-specific. Hence,
1777 we cannot safely advertise mark(), seek() and non-default skip()
1779 *err = make_stream_from_apr_file(stderr_file, TRUE, FALSE, pool);
1781 return SVN_NO_ERROR;
1786 svn_string_from_stream(svn_string_t **result,
1787 svn_stream_t *stream,
1788 apr_pool_t *result_pool,
1789 apr_pool_t *scratch_pool)
1791 svn_stringbuf_t *work = svn_stringbuf_create_ensure(SVN__STREAM_CHUNK_SIZE,
1793 char *buffer = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE);
1797 apr_size_t len = SVN__STREAM_CHUNK_SIZE;
1799 SVN_ERR(svn_stream_read_full(stream, buffer, &len));
1800 svn_stringbuf_appendbytes(work, buffer, len);
1802 if (len < SVN__STREAM_CHUNK_SIZE)
1806 SVN_ERR(svn_stream_close(stream));
1808 *result = apr_palloc(result_pool, sizeof(**result));
1809 (*result)->data = work->data;
1810 (*result)->len = work->len;
1812 return SVN_NO_ERROR;
1816 /* These are somewhat arbitrary, if we ever get good empirical data as to
1817 actually valid values, feel free to update them. */
1818 #define BUFFER_BLOCK_SIZE 1024
1819 #define BUFFER_MAX_SIZE 100000
1822 svn_stream_buffered(apr_pool_t *result_pool)
1824 return svn_stream__from_spillbuf(svn_spillbuf__create(BUFFER_BLOCK_SIZE,
1832 /*** Lazyopen Streams ***/
1834 /* Custom baton for lazyopen-style wrapper streams. */
1835 typedef struct lazyopen_baton_t {
1837 /* Callback function and baton for opening the wrapped stream. */
1838 svn_stream_lazyopen_func_t open_func;
1841 /* The wrapped stream, or NULL if the stream hasn't yet been
1843 svn_stream_t *real_stream;
1846 /* Whether to open the wrapped stream on a close call. */
1847 svn_boolean_t open_on_close;
1852 /* Use B->open_func/baton to create and set B->real_stream iff it
1853 isn't already set. */
1854 static svn_error_t *
1855 lazyopen_if_unopened(lazyopen_baton_t *b)
1857 if (b->real_stream == NULL)
1859 svn_stream_t *stream;
1860 apr_pool_t *scratch_pool = svn_pool_create(b->pool);
1862 SVN_ERR(b->open_func(&stream, b->open_baton,
1863 b->pool, scratch_pool));
1865 svn_pool_destroy(scratch_pool);
1867 b->real_stream = stream;
1870 return SVN_NO_ERROR;
1873 /* Implements svn_read_fn_t */
1874 static svn_error_t *
1875 read_handler_lazyopen(void *baton,
1879 lazyopen_baton_t *b = baton;
1881 SVN_ERR(lazyopen_if_unopened(b));
1882 SVN_ERR(svn_stream_read2(b->real_stream, buffer, len));
1884 return SVN_NO_ERROR;
1887 /* Implements svn_read_fn_t */
1888 static svn_error_t *
1889 read_full_handler_lazyopen(void *baton,
1893 lazyopen_baton_t *b = baton;
1895 SVN_ERR(lazyopen_if_unopened(b));
1896 SVN_ERR(svn_stream_read_full(b->real_stream, buffer, len));
1898 return SVN_NO_ERROR;
1901 /* Implements svn_stream_skip_fn_t */
1902 static svn_error_t *
1903 skip_handler_lazyopen(void *baton,
1906 lazyopen_baton_t *b = baton;
1908 SVN_ERR(lazyopen_if_unopened(b));
1909 SVN_ERR(svn_stream_skip(b->real_stream, len));
1911 return SVN_NO_ERROR;
1914 /* Implements svn_write_fn_t */
1915 static svn_error_t *
1916 write_handler_lazyopen(void *baton,
1920 lazyopen_baton_t *b = baton;
1922 SVN_ERR(lazyopen_if_unopened(b));
1923 SVN_ERR(svn_stream_write(b->real_stream, data, len));
1925 return SVN_NO_ERROR;
1928 /* Implements svn_close_fn_t */
1929 static svn_error_t *
1930 close_handler_lazyopen(void *baton)
1932 lazyopen_baton_t *b = baton;
1934 if (b->open_on_close)
1935 SVN_ERR(lazyopen_if_unopened(b));
1937 SVN_ERR(svn_stream_close(b->real_stream));
1939 return SVN_NO_ERROR;
1942 /* Implements svn_stream_mark_fn_t */
1943 static svn_error_t *
1944 mark_handler_lazyopen(void *baton,
1945 svn_stream_mark_t **mark,
1948 lazyopen_baton_t *b = baton;
1950 SVN_ERR(lazyopen_if_unopened(b));
1951 SVN_ERR(svn_stream_mark(b->real_stream, mark, pool));
1953 return SVN_NO_ERROR;
1956 /* Implements svn_stream_seek_fn_t */
1957 static svn_error_t *
1958 seek_handler_lazyopen(void *baton,
1959 const svn_stream_mark_t *mark)
1961 lazyopen_baton_t *b = baton;
1963 SVN_ERR(lazyopen_if_unopened(b));
1964 SVN_ERR(svn_stream_seek(b->real_stream, mark));
1966 return SVN_NO_ERROR;
1969 static svn_error_t *
1970 data_available_handler_lazyopen(void *baton,
1971 svn_boolean_t *data_available)
1973 lazyopen_baton_t *b = baton;
1975 SVN_ERR(lazyopen_if_unopened(b));
1976 return svn_error_trace(svn_stream_data_available(b->real_stream,
1980 /* Implements svn_stream__is_buffered_fn_t */
1981 static svn_boolean_t
1982 is_buffered_lazyopen(void *baton)
1984 lazyopen_baton_t *b = baton;
1986 /* No lazy open as we cannot handle an open error. */
1987 if (!b->real_stream)
1990 return svn_stream__is_buffered(b->real_stream);
1994 svn_stream_lazyopen_create(svn_stream_lazyopen_func_t open_func,
1996 svn_boolean_t open_on_close,
1997 apr_pool_t *result_pool)
1999 lazyopen_baton_t *lob = apr_pcalloc(result_pool, sizeof(*lob));
2000 svn_stream_t *stream;
2002 lob->open_func = open_func;
2003 lob->open_baton = open_baton;
2004 lob->real_stream = NULL;
2005 lob->pool = result_pool;
2006 lob->open_on_close = open_on_close;
2008 stream = svn_stream_create(lob, result_pool);
2009 svn_stream_set_read2(stream, read_handler_lazyopen,
2010 read_full_handler_lazyopen);
2011 svn_stream_set_skip(stream, skip_handler_lazyopen);
2012 svn_stream_set_write(stream, write_handler_lazyopen);
2013 svn_stream_set_close(stream, close_handler_lazyopen);
2014 svn_stream_set_mark(stream, mark_handler_lazyopen);
2015 svn_stream_set_seek(stream, seek_handler_lazyopen);
2016 svn_stream_set_data_available(stream, data_available_handler_lazyopen);
2017 svn_stream__set_is_buffered(stream, is_buffered_lazyopen);
2022 /* Baton for install streams */
2023 struct install_baton_t
2025 struct baton_apr baton_apr;
2026 const char *tmp_path;
2031 /* Create and open a tempfile in DIRECTORY. Return its handle and path */
2032 static svn_error_t *
2033 create_tempfile(HANDLE *hFile,
2034 const char **file_path,
2035 const char *directory,
2036 apr_pool_t *result_pool,
2037 apr_pool_t *scratch_pool)
2039 const char *unique_name;
2040 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
2041 static svn_atomic_t tempname_counter;
2042 int baseNr = (GetTickCount() << 11) + 13 * svn_atomic_inc(&tempname_counter)
2043 + GetCurrentProcessId();
2047 /* Shares common idea with io.c's temp_file_create */
2051 apr_uint32_t unique_nr;
2054 /* Generate a number that should be unique for this application and
2055 usually for the entire computer to reduce the number of cycles
2056 through this loop. (A bit of calculation is much cheaper than
2058 unique_nr = baseNr + 7 * i++;
2061 svn_pool_clear(iterpool);
2062 unique_name = svn_dirent_join(directory,
2063 apr_psprintf(iterpool, "svn-%X",
2067 SVN_ERR(svn_io__utf8_to_unicode_longpath(&w_name, unique_name,
2070 /* Create a completely not-sharable file to avoid indexers, and other
2071 filesystem watchers locking the file while we are still writing.
2073 We need DELETE privileges to move the file. */
2074 h = CreateFileW(w_name, GENERIC_WRITE | DELETE, 0 /* share */,
2075 NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
2077 if (h == INVALID_HANDLE_VALUE)
2079 apr_status_t status = apr_get_os_error();
2081 return svn_error_createf(SVN_ERR_IO_UNIQUE_NAMES_EXHAUSTED,
2082 svn_error_wrap_apr(status, NULL),
2083 _("Unable to make name in '%s'"),
2084 svn_dirent_local_style(directory, scratch_pool));
2086 if (!APR_STATUS_IS_EEXIST(status) && !APR_STATUS_IS_EACCES(status))
2087 return svn_error_wrap_apr(status, NULL);
2090 while (h == INVALID_HANDLE_VALUE);
2093 *file_path = apr_pstrdup(result_pool, unique_name);
2094 svn_pool_destroy(iterpool);
2096 return SVN_NO_ERROR;
2099 /* Implements svn_close_fn_t */
2100 static svn_error_t *
2101 install_close(void *baton)
2103 struct install_baton_t *ib = baton;
2105 /* Flush the data cached in APR, but don't close the file yet */
2106 SVN_ERR(svn_io_file_flush(ib->baton_apr.file, ib->baton_apr.pool));
2108 return SVN_NO_ERROR;
2114 svn_stream__create_for_install(svn_stream_t **install_stream,
2115 const char *tmp_abspath,
2116 apr_pool_t *result_pool,
2117 apr_pool_t *scratch_pool)
2120 struct install_baton_t *ib;
2121 const char *tmp_path;
2125 apr_status_t status;
2127 SVN_ERR_ASSERT(svn_dirent_is_absolute(tmp_abspath));
2129 SVN_ERR(create_tempfile(&hInstall, &tmp_path, tmp_abspath,
2130 scratch_pool, scratch_pool));
2132 /* Wrap as a standard APR file to allow sharing implementation.
2134 But do note that some file functions (such as retrieving the name)
2135 don't work on this wrapper. */
2136 /* ### Buffered, or not? */
2137 status = apr_os_file_put(&file, &hInstall,
2138 APR_WRITE | APR_BINARY | APR_BUFFERED,
2143 CloseHandle(hInstall);
2144 return svn_error_wrap_apr(status, NULL);
2147 tmp_path = svn_dirent_internal_style(tmp_path, result_pool);
2150 SVN_ERR_ASSERT(svn_dirent_is_absolute(tmp_abspath));
2152 SVN_ERR(svn_io_open_unique_file3(&file, &tmp_path, tmp_abspath,
2153 svn_io_file_del_none,
2154 result_pool, scratch_pool));
2156 *install_stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
2158 ib = apr_pcalloc(result_pool, sizeof(*ib));
2159 ib->baton_apr = *(struct baton_apr*)(*install_stream)->baton;
2161 assert((void*)&ib->baton_apr == (void*)ib); /* baton pointer is the same */
2163 (*install_stream)->baton = ib;
2165 ib->tmp_path = tmp_path;
2168 /* Don't close the file on stream close; flush instead */
2169 svn_stream_set_close(*install_stream, install_close);
2171 /* ### Install pool cleanup handler for tempfile? */
2174 return SVN_NO_ERROR;
2178 svn_stream__install_stream(svn_stream_t *install_stream,
2179 const char *final_abspath,
2180 svn_boolean_t make_parents,
2181 apr_pool_t *scratch_pool)
2183 struct install_baton_t *ib = install_stream->baton;
2186 SVN_ERR_ASSERT(svn_dirent_is_absolute(final_abspath));
2188 err = svn_io__win_rename_open_file(ib->baton_apr.file, ib->tmp_path,
2189 final_abspath, scratch_pool);
2190 if (make_parents && err && APR_STATUS_IS_ENOENT(err->apr_err))
2194 err2 = svn_io_make_dir_recursively(svn_dirent_dirname(final_abspath,
2199 return svn_error_trace(svn_error_compose_create(err, err2));
2201 svn_error_clear(err);
2203 err = svn_io__win_rename_open_file(ib->baton_apr.file, ib->tmp_path,
2204 final_abspath, scratch_pool);
2207 /* ### rhuijben: I wouldn't be surprised if we later find out that we
2208 have to fall back to close+rename on some specific
2209 error values here, to support some non standard NAS
2210 and filesystem scenarios. */
2211 if (err && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
2213 /* Rename open files is not supported on this platform: fallback to
2214 svn_io_file_rename2(). */
2215 svn_error_clear(err);
2218 SVN_ERR(svn_io_file_close(ib->baton_apr.file, scratch_pool));
2222 return svn_error_compose_create(err,
2223 svn_io_file_close(ib->baton_apr.file,
2228 err = svn_io_file_rename(ib->tmp_path, final_abspath, scratch_pool);
2230 /* A missing directory is too common to not cover here. */
2231 if (make_parents && err && APR_STATUS_IS_ENOENT(err->apr_err))
2235 err2 = svn_io_make_dir_recursively(svn_dirent_dirname(final_abspath,
2240 /* Creating directory didn't work: Return all errors */
2241 return svn_error_trace(svn_error_compose_create(err, err2));
2243 /* We could create a directory: retry install */
2244 svn_error_clear(err);
2246 SVN_ERR(svn_io_file_rename(ib->tmp_path, final_abspath, scratch_pool));
2251 return SVN_NO_ERROR;
2255 svn_stream__install_get_info(apr_finfo_t *finfo,
2256 svn_stream_t *install_stream,
2258 apr_pool_t *scratch_pool)
2260 struct install_baton_t *ib = install_stream->baton;
2263 /* On WIN32 the file is still open, so we can obtain the information
2264 from the handle without race conditions */
2265 apr_status_t status;
2267 status = apr_file_info_get(finfo, wanted, ib->baton_apr.file);
2270 return svn_error_wrap_apr(status, NULL);
2272 SVN_ERR(svn_io_stat(finfo, ib->tmp_path, wanted, scratch_pool));
2275 return SVN_NO_ERROR;
2279 svn_stream__install_delete(svn_stream_t *install_stream,
2280 apr_pool_t *scratch_pool)
2282 struct install_baton_t *ib = install_stream->baton;
2287 /* Mark the file as delete on close to avoid having to reopen
2288 the file as part of the delete handling. */
2289 err = svn_io__win_delete_file_on_close(ib->baton_apr.file, ib->tmp_path,
2291 if (err == SVN_NO_ERROR)
2293 SVN_ERR(svn_io_file_close(ib->baton_apr.file, scratch_pool));
2294 return SVN_NO_ERROR; /* File is already gone */
2297 /* Deleting file on close may be unsupported, so ignore errors and
2298 fallback to svn_io_remove_file2(). */
2299 svn_error_clear(err);
2300 SVN_ERR(svn_io_file_close(ib->baton_apr.file, scratch_pool));
2303 return svn_error_trace(svn_io_remove_file2(ib->tmp_path, FALSE,