In the command-line client, forbid
[svn.git] / subversion / libsvn_subr / stream.c
blobbad9a572f007ece431c867708c83e221fac151f7
1 /*
2 * stream.c: svn_stream operations
4 * ====================================================================
5 * Copyright (c) 2000-2004, 2006 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 #include "svn_private_config.h"
21 #include <assert.h>
22 #include <stdio.h>
24 #include <apr.h>
25 #include <apr_pools.h>
26 #include <apr_strings.h>
27 #include <apr_file_io.h>
28 #include <apr_errno.h>
29 #include <apr_md5.h>
31 #include <zlib.h>
33 #include "svn_pools.h"
34 #include "svn_io.h"
35 #include "svn_error.h"
36 #include "svn_string.h"
37 #include "svn_utf.h"
40 struct svn_stream_t {
41 void *baton;
42 svn_read_fn_t read_fn;
43 svn_write_fn_t write_fn;
44 svn_close_fn_t close_fn;
49 /*** Generic streams. ***/
51 svn_stream_t *
52 svn_stream_create(void *baton, apr_pool_t *pool)
54 svn_stream_t *stream;
56 stream = apr_palloc(pool, sizeof(*stream));
57 stream->baton = baton;
58 stream->read_fn = NULL;
59 stream->write_fn = NULL;
60 stream->close_fn = NULL;
61 return stream;
65 void
66 svn_stream_set_baton(svn_stream_t *stream, void *baton)
68 stream->baton = baton;
72 void
73 svn_stream_set_read(svn_stream_t *stream, svn_read_fn_t read_fn)
75 stream->read_fn = read_fn;
79 void
80 svn_stream_set_write(svn_stream_t *stream, svn_write_fn_t write_fn)
82 stream->write_fn = write_fn;
86 void
87 svn_stream_set_close(svn_stream_t *stream, svn_close_fn_t close_fn)
89 stream->close_fn = close_fn;
93 svn_error_t *
94 svn_stream_read(svn_stream_t *stream, char *buffer, apr_size_t *len)
96 assert(stream->read_fn != NULL);
97 return stream->read_fn(stream->baton, buffer, len);
101 svn_error_t *
102 svn_stream_write(svn_stream_t *stream, const char *data, apr_size_t *len)
104 assert(stream->write_fn != NULL);
105 return stream->write_fn(stream->baton, data, len);
109 svn_error_t *
110 svn_stream_close(svn_stream_t *stream)
112 if (stream->close_fn == NULL)
113 return SVN_NO_ERROR;
114 return stream->close_fn(stream->baton);
118 svn_error_t *
119 svn_stream_printf(svn_stream_t *stream,
120 apr_pool_t *pool,
121 const char *fmt,
122 ...)
124 const char *message;
125 va_list ap;
126 apr_size_t len;
128 va_start(ap, fmt);
129 message = apr_pvsprintf(pool, fmt, ap);
130 va_end(ap);
132 len = strlen(message);
133 return svn_stream_write(stream, message, &len);
137 svn_error_t *
138 svn_stream_printf_from_utf8(svn_stream_t *stream,
139 const char *encoding,
140 apr_pool_t *pool,
141 const char *fmt,
142 ...)
144 const char *message, *translated;
145 va_list ap;
146 apr_size_t len;
148 va_start(ap, fmt);
149 message = apr_pvsprintf(pool, fmt, ap);
150 va_end(ap);
152 SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated, message, encoding,
153 pool));
155 len = strlen(translated);
157 return svn_stream_write(stream, translated, &len);
161 svn_error_t *
162 svn_stream_readline(svn_stream_t *stream,
163 svn_stringbuf_t **stringbuf,
164 const char *eol,
165 svn_boolean_t *eof,
166 apr_pool_t *pool)
168 apr_size_t numbytes;
169 const char *match;
170 char c;
171 svn_stringbuf_t *str = svn_stringbuf_create("", pool);
173 /* Since we're reading one character at a time, let's at least
174 optimize for the 90% case. 90% of the time, we can avoid the
175 stringbuf ever having to realloc() itself if we start it out at
176 80 chars. */
177 svn_stringbuf_ensure(str, 80);
179 match = eol;
180 while (*match)
182 numbytes = 1;
183 SVN_ERR(svn_stream_read(stream, &c, &numbytes));
184 if (numbytes != 1)
186 /* a 'short' read means the stream has run out. */
187 *eof = TRUE;
188 *stringbuf = str;
189 return SVN_NO_ERROR;
192 if (c == *match)
193 match++;
194 else
195 match = eol;
197 svn_stringbuf_appendbytes(str, &c, 1);
200 *eof = FALSE;
201 svn_stringbuf_chop(str, match - eol);
202 *stringbuf = str;
203 return SVN_NO_ERROR;
207 svn_error_t *svn_stream_copy2(svn_stream_t *from, svn_stream_t *to,
208 svn_cancel_func_t cancel_func,
209 void *cancel_baton,
210 apr_pool_t *pool)
212 char *buf = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
213 apr_size_t len;
215 /* Read and write chunks until we get a short read, indicating the
216 end of the stream. (We can't get a short write without an
217 associated error.) */
218 while (1)
220 len = SVN__STREAM_CHUNK_SIZE;
222 if (cancel_func)
223 SVN_ERR(cancel_func(cancel_baton));
225 SVN_ERR(svn_stream_read(from, buf, &len));
226 if (len > 0)
227 SVN_ERR(svn_stream_write(to, buf, &len));
228 if (len != SVN__STREAM_CHUNK_SIZE)
229 break;
231 return SVN_NO_ERROR;
234 svn_error_t *svn_stream_copy(svn_stream_t *from, svn_stream_t *to,
235 apr_pool_t *pool)
237 return svn_stream_copy2(from, to, NULL, NULL, pool);
240 svn_error_t *
241 svn_stream_contents_same(svn_boolean_t *same,
242 svn_stream_t *stream1,
243 svn_stream_t *stream2,
244 apr_pool_t *pool)
246 char *buf1 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
247 char *buf2 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE);
248 apr_size_t bytes_read1 = SVN__STREAM_CHUNK_SIZE;
249 apr_size_t bytes_read2 = SVN__STREAM_CHUNK_SIZE;
251 *same = TRUE; /* assume TRUE, until disproved below */
252 while (bytes_read1 == SVN__STREAM_CHUNK_SIZE
253 && bytes_read2 == SVN__STREAM_CHUNK_SIZE)
255 SVN_ERR(svn_stream_read(stream1, buf1, &bytes_read1));
256 SVN_ERR(svn_stream_read(stream2, buf2, &bytes_read2));
258 if ((bytes_read1 != bytes_read2)
259 || (memcmp(buf1, buf2, bytes_read1)))
261 *same = FALSE;
262 break;
266 return SVN_NO_ERROR;
271 /*** Generic readable empty stream ***/
273 static svn_error_t *
274 read_handler_empty(void *baton, char *buffer, apr_size_t *len)
276 *len = 0;
277 return SVN_NO_ERROR;
281 static svn_error_t *
282 write_handler_empty(void *baton, const char *data, apr_size_t *len)
284 return SVN_NO_ERROR;
288 svn_stream_t *
289 svn_stream_empty(apr_pool_t *pool)
291 svn_stream_t *stream;
293 stream = svn_stream_create(NULL, pool);
294 svn_stream_set_read(stream, read_handler_empty);
295 svn_stream_set_write(stream, write_handler_empty);
296 return stream;
302 /*** Ownership detaching stream ***/
304 static svn_error_t *
305 read_handler_disown(void *baton, char *buffer, apr_size_t *len)
307 return svn_stream_read((svn_stream_t *)baton, buffer, len);
310 static svn_error_t *
311 write_handler_disown(void *baton, const char *buffer, apr_size_t *len)
313 return svn_stream_write((svn_stream_t *)baton, buffer, len);
317 svn_stream_t *
318 svn_stream_disown(svn_stream_t *stream, apr_pool_t *pool)
320 svn_stream_t *s = svn_stream_create(stream, pool);
322 svn_stream_set_read(s, read_handler_disown);
323 svn_stream_set_write(s, write_handler_disown);
325 return s;
330 /*** Generic stream for APR files ***/
331 struct baton_apr {
332 apr_file_t *file;
333 apr_pool_t *pool;
337 static svn_error_t *
338 read_handler_apr(void *baton, char *buffer, apr_size_t *len)
340 struct baton_apr *btn = baton;
341 svn_error_t *err;
343 err = svn_io_file_read_full(btn->file, buffer, *len, len, btn->pool);
344 if (err && APR_STATUS_IS_EOF(err->apr_err))
346 svn_error_clear(err);
347 err = SVN_NO_ERROR;
350 return err;
354 static svn_error_t *
355 write_handler_apr(void *baton, const char *data, apr_size_t *len)
357 struct baton_apr *btn = baton;
359 return svn_io_file_write_full(btn->file, data, *len, len, btn->pool);
362 static svn_error_t *
363 close_handler_apr(void *baton)
365 struct baton_apr *btn = baton;
367 return svn_io_file_close(btn->file, btn->pool);
371 svn_stream_t *
372 svn_stream_from_aprfile2(apr_file_t *file,
373 svn_boolean_t disown,
374 apr_pool_t *pool)
376 struct baton_apr *baton;
377 svn_stream_t *stream;
379 if (file == NULL)
380 return svn_stream_empty(pool);
382 baton = apr_palloc(pool, sizeof(*baton));
383 baton->file = file;
384 baton->pool = pool;
385 stream = svn_stream_create(baton, pool);
386 svn_stream_set_read(stream, read_handler_apr);
387 svn_stream_set_write(stream, write_handler_apr);
389 if (! disown)
390 svn_stream_set_close(stream, close_handler_apr);
392 return stream;
395 svn_stream_t *
396 svn_stream_from_aprfile(apr_file_t *file, apr_pool_t *pool)
398 return svn_stream_from_aprfile2(file, TRUE, pool);
403 /* Compressed stream support */
405 #define ZBUFFER_SIZE 4096 /* The size of the buffer the
406 compressed stream uses to read from
407 the substream. Basically an
408 arbitrary value, picked to be about
409 page-sized. */
411 struct zbaton {
412 z_stream *in; /* compressed stream for reading */
413 z_stream *out; /* compressed stream for writing */
414 svn_read_fn_t read; /* substream's read function */
415 svn_write_fn_t write; /* substream's write function */
416 svn_close_fn_t close; /* substream's close function */
417 void *read_buffer; /* buffer used for reading from
418 substream */
419 int read_flush; /* what flush mode to use while
420 reading */
421 apr_pool_t *pool; /* The pool this baton is allocated
422 on */
423 void *subbaton; /* The substream's baton */
426 /* zlib alloc function. opaque is the pool we need. */
427 static voidpf
428 zalloc(voidpf opaque, uInt items, uInt size)
430 apr_pool_t *pool = opaque;
432 return apr_palloc(pool, items * size);
435 /* zlib free function */
436 static void
437 zfree(voidpf opaque, voidpf address)
439 /* Empty, since we allocate on the pool */
442 /* Converts a zlib error to an svn_error_t. zerr is the error code,
443 function is the function name, and stream is the z_stream we are
444 using. */
445 static svn_error_t *
446 zerr_to_svn_error(int zerr, const char *function, z_stream *stream)
448 apr_status_t status;
449 const char *message;
451 if (zerr == Z_OK)
452 return SVN_NO_ERROR;
454 switch (zerr)
456 case Z_STREAM_ERROR:
457 status = SVN_ERR_STREAM_MALFORMED_DATA;
458 message = "stream error";
459 break;
461 case Z_MEM_ERROR:
462 status = APR_ENOMEM;
463 message = "out of memory";
464 break;
466 case Z_BUF_ERROR:
467 status = APR_ENOMEM;
468 message = "buffer error";
469 break;
471 case Z_VERSION_ERROR:
472 status = SVN_ERR_STREAM_UNRECOGNIZED_DATA;
473 message = "version error";
474 break;
476 case Z_DATA_ERROR:
477 status = SVN_ERR_STREAM_MALFORMED_DATA;
478 message = "corrupted data";
479 break;
481 default:
482 status = SVN_ERR_STREAM_UNRECOGNIZED_DATA;
483 message = "error";
484 break;
487 if (stream->msg != NULL)
488 return svn_error_createf(status, NULL, "zlib (%s): %s: %s", function,
489 message, stream->msg);
490 else
491 return svn_error_createf(status, NULL, "zlib (%s): %s", function,
492 message);
495 /* Helper function to figure out the sync mode */
496 static svn_error_t *
497 read_helper_gz(svn_read_fn_t read_fn,
498 void *baton,
499 char *buffer,
500 uInt *len, int *zflush)
502 uInt orig_len = *len;
504 /* There's no reason this value should grow bigger than the range of
505 uInt, but Subversion's API requires apr_size_t. */
506 apr_size_t apr_len = (apr_size_t) *len;
508 SVN_ERR((*read_fn)(baton, buffer, &apr_len));
510 /* Type cast back to uInt type that zlib uses. On LP64 platforms
511 apr_size_t will be bigger than uInt. */
512 *len = (uInt) apr_len;
514 /* I wanted to use Z_FINISH here, but we need to know our buffer is
515 big enough */
516 *zflush = (*len) < orig_len ? Z_SYNC_FLUSH : Z_SYNC_FLUSH;
518 return SVN_NO_ERROR;
521 /* Handle reading from a compressed stream */
522 static svn_error_t *
523 read_handler_gz(void *baton, char *buffer, apr_size_t *len)
525 struct zbaton *btn = baton;
526 int zerr;
528 if (btn->in == NULL)
530 btn->in = apr_palloc(btn->pool, sizeof(z_stream));
531 btn->in->zalloc = zalloc;
532 btn->in->zfree = zfree;
533 btn->in->opaque = btn->pool;
534 btn->read_buffer = apr_palloc(btn->pool, ZBUFFER_SIZE);
535 btn->in->next_in = btn->read_buffer;
536 btn->in->avail_in = ZBUFFER_SIZE;
538 SVN_ERR(read_helper_gz(btn->read, btn->subbaton, btn->read_buffer,
539 &btn->in->avail_in, &btn->read_flush));
541 zerr = inflateInit(btn->in);
542 SVN_ERR(zerr_to_svn_error(zerr, "inflateInit", btn->in));
545 btn->in->next_out = (Bytef *) buffer;
546 btn->in->avail_out = *len;
548 while (btn->in->avail_out > 0)
550 if (btn->in->avail_in <= 0)
552 btn->in->avail_in = ZBUFFER_SIZE;
553 btn->in->next_in = btn->read_buffer;
554 SVN_ERR(read_helper_gz(btn->read, btn->subbaton, btn->read_buffer,
555 &btn->in->avail_in, &btn->read_flush));
558 zerr = inflate(btn->in, btn->read_flush);
559 if (zerr == Z_STREAM_END)
560 break;
561 else if (zerr != Z_OK)
562 return zerr_to_svn_error(zerr, "inflate", btn->in);
565 *len -= btn->in->avail_out;
566 return SVN_NO_ERROR;
569 /* Compress data and write it to the substream */
570 static svn_error_t *
571 write_handler_gz(void *baton, const char *buffer, apr_size_t *len)
573 struct zbaton *btn = baton;
574 apr_pool_t *subpool;
575 void *write_buf;
576 apr_size_t buf_size, write_len;
577 int zerr;
579 if (btn->out == NULL)
581 btn->out = apr_palloc(btn->pool, sizeof(z_stream));
582 btn->out->zalloc = zalloc;
583 btn->out->zfree = zfree;
584 btn->out->opaque = btn->pool;
586 zerr = deflateInit(btn->out, Z_DEFAULT_COMPRESSION);
587 SVN_ERR(zerr_to_svn_error(zerr, "deflateInit", btn->out));
590 /* The largest buffer we should need is 0.1% larger than the
591 compressed data, + 12 bytes. This info comes from zlib.h. */
592 buf_size = *len + (*len / 1000) + 13;
593 subpool = svn_pool_create(btn->pool);
594 write_buf = apr_palloc(subpool, buf_size);
596 btn->out->next_in = (Bytef *) buffer; /* Casting away const! */
597 btn->out->avail_in = *len;
599 while (btn->out->avail_in > 0)
601 btn->out->next_out = write_buf;
602 btn->out->avail_out = buf_size;
604 zerr = deflate(btn->out, Z_NO_FLUSH);
605 SVN_ERR(zerr_to_svn_error(zerr, "deflate", btn->out));
606 write_len = buf_size - btn->out->avail_out;
607 if (write_len > 0)
608 SVN_ERR(btn->write(btn->subbaton, write_buf, &write_len));
611 svn_pool_destroy(subpool);
613 return SVN_NO_ERROR;
616 /* Handle flushing and closing the stream */
617 static svn_error_t *
618 close_handler_gz(void *baton)
620 struct zbaton *btn = baton;
621 int zerr;
623 if (btn->in != NULL)
625 zerr = inflateEnd(btn->in);
626 SVN_ERR(zerr_to_svn_error(zerr, "inflateEnd", btn->in));
629 if (btn->out != NULL)
631 void *buf;
632 apr_size_t write_len;
634 buf = apr_palloc(btn->pool, ZBUFFER_SIZE);
636 while (TRUE)
638 btn->out->next_out = buf;
639 btn->out->avail_out = ZBUFFER_SIZE;
641 zerr = deflate(btn->out, Z_FINISH);
642 if (zerr != Z_STREAM_END && zerr != Z_OK)
643 return zerr_to_svn_error(zerr, "deflate", btn->out);
644 write_len = ZBUFFER_SIZE - btn->out->avail_out;
645 if (write_len > 0)
646 SVN_ERR(btn->write(btn->subbaton, buf, &write_len));
647 if (zerr == Z_STREAM_END)
648 break;
651 zerr = deflateEnd(btn->out);
652 SVN_ERR(zerr_to_svn_error(zerr, "deflateEnd", btn->out));
655 if (btn->close != NULL)
656 return btn->close(btn->subbaton);
657 else
658 return SVN_NO_ERROR;
662 svn_stream_t *
663 svn_stream_compressed(svn_stream_t *stream, apr_pool_t *pool)
665 struct svn_stream_t *zstream;
666 struct zbaton *baton;
668 assert(stream != NULL);
670 baton = apr_palloc(pool, sizeof(*baton));
671 baton->in = baton->out = NULL;
672 baton->read = stream->read_fn;
673 baton->write = stream->write_fn;
674 baton->close = stream->close_fn;
675 baton->subbaton = stream->baton;
676 baton->pool = pool;
677 baton->read_buffer = NULL;
678 baton->read_flush = Z_SYNC_FLUSH;
680 zstream = svn_stream_create(baton, pool);
681 svn_stream_set_read(zstream, read_handler_gz);
682 svn_stream_set_write(zstream, write_handler_gz);
683 svn_stream_set_close(zstream, close_handler_gz);
685 return zstream;
689 /* MD5 checked stream support */
691 struct md5_stream_baton
693 apr_md5_ctx_t read_ctx, write_ctx;
694 const unsigned char **read_digest;
695 const unsigned char **write_digest;
696 unsigned char read_digest_buf[APR_MD5_DIGESTSIZE];
697 unsigned char write_digest_buf[APR_MD5_DIGESTSIZE];
698 svn_stream_t *proxy;
700 /* True if more data should be read when closing the stream. */
701 svn_boolean_t read_more;
703 /* Pool to allocate read buffer from. */
704 apr_pool_t *pool;
707 static svn_error_t *
708 read_handler_md5(void *baton, char *buffer, apr_size_t *len)
710 struct md5_stream_baton *btn = baton;
711 apr_size_t saved_len = *len;
713 SVN_ERR(svn_stream_read(btn->proxy, buffer, len));
715 if (btn->read_digest)
717 apr_status_t apr_err = apr_md5_update(&btn->read_ctx, buffer, *len);
719 if (apr_err)
720 return svn_error_create(apr_err, NULL, NULL);
723 if (saved_len != *len)
724 btn->read_more = FALSE;
726 return SVN_NO_ERROR;
730 static svn_error_t *
731 write_handler_md5(void *baton, const char *buffer, apr_size_t *len)
733 struct md5_stream_baton *btn = baton;
735 if (btn->write_digest && *len > 0)
737 apr_status_t apr_err = apr_md5_update(&btn->write_ctx, buffer, *len);
739 if (apr_err)
740 return svn_error_create(apr_err, NULL, NULL);
743 return svn_stream_write(btn->proxy, buffer, len);
747 static svn_error_t *
748 close_handler_md5(void *baton)
750 struct md5_stream_baton *btn = baton;
752 /* If we're supposed to drain the stream, do so before finalizing the
753 checksum. */
754 if (btn->read_more)
756 char *buf = apr_palloc(btn->pool, SVN__STREAM_CHUNK_SIZE);
757 apr_size_t len = SVN__STREAM_CHUNK_SIZE;
761 SVN_ERR(read_handler_md5(baton, buf, &len));
763 while (btn->read_more);
766 if (btn->read_digest)
768 apr_status_t apr_err
769 = apr_md5_final(btn->read_digest_buf, &btn->read_ctx);
771 if (apr_err)
772 return svn_error_create(apr_err, NULL, NULL);
774 *btn->read_digest = btn->read_digest_buf;
777 if (btn->write_digest)
779 apr_status_t apr_err
780 = apr_md5_final(btn->write_digest_buf, &btn->write_ctx);
782 if (apr_err)
783 return svn_error_create(apr_err, NULL, NULL);
785 *btn->write_digest = btn->write_digest_buf;
788 return svn_stream_close(btn->proxy);
792 svn_stream_t *
793 svn_stream_checksummed(svn_stream_t *stream,
794 const unsigned char **read_digest,
795 const unsigned char **write_digest,
796 svn_boolean_t read_all,
797 apr_pool_t *pool)
799 svn_stream_t *s;
800 struct md5_stream_baton *baton;
802 if (! read_digest && ! write_digest)
803 return stream;
805 baton = apr_palloc(pool, sizeof(*baton));
806 apr_md5_init(&baton->read_ctx);
807 apr_md5_init(&baton->write_ctx);
808 baton->read_digest = read_digest;
809 baton->write_digest = write_digest;
810 baton->proxy = stream;
811 baton->read_more = read_all;
812 baton->pool = pool;
814 s = svn_stream_create(baton, pool);
815 svn_stream_set_read(s, read_handler_md5);
816 svn_stream_set_write(s, write_handler_md5);
817 svn_stream_set_close(s, close_handler_md5);
818 return s;
824 /* Miscellaneous stream functions. */
825 struct string_stream_baton
827 svn_stringbuf_t *str;
828 apr_size_t amt_read;
831 static svn_error_t *
832 read_handler_string(void *baton, char *buffer, apr_size_t *len)
834 struct string_stream_baton *btn = baton;
835 apr_size_t left_to_read = btn->str->len - btn->amt_read;
837 *len = (*len > left_to_read) ? left_to_read : *len;
838 memcpy(buffer, btn->str->data + btn->amt_read, *len);
839 btn->amt_read += *len;
840 return SVN_NO_ERROR;
843 static svn_error_t *
844 write_handler_string(void *baton, const char *data, apr_size_t *len)
846 struct string_stream_baton *btn = baton;
848 svn_stringbuf_appendbytes(btn->str, data, *len);
849 return SVN_NO_ERROR;
852 svn_stream_t *
853 svn_stream_from_stringbuf(svn_stringbuf_t *str,
854 apr_pool_t *pool)
856 svn_stream_t *stream;
857 struct string_stream_baton *baton;
859 if (! str)
860 return svn_stream_empty(pool);
862 baton = apr_palloc(pool, sizeof(*baton));
863 baton->str = str;
864 baton->amt_read = 0;
865 stream = svn_stream_create(baton, pool);
866 svn_stream_set_read(stream, read_handler_string);
867 svn_stream_set_write(stream, write_handler_string);
868 return stream;
872 svn_error_t *
873 svn_stream_for_stdout(svn_stream_t **out, apr_pool_t *pool)
875 apr_file_t *stdout_file;
876 apr_status_t apr_err;
878 apr_err = apr_file_open_stdout(&stdout_file, pool);
879 if (apr_err)
880 return svn_error_wrap_apr(apr_err, "Can't open stdout");
882 *out = svn_stream_from_aprfile(stdout_file, pool);
884 return SVN_NO_ERROR;