1251881Speter/* 2251881Speter * stream.c: svn_stream operations 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter#include <assert.h> 25251881Speter#include <stdio.h> 26251881Speter 27251881Speter#include <apr.h> 28251881Speter#include <apr_pools.h> 29251881Speter#include <apr_strings.h> 30251881Speter#include <apr_file_io.h> 31251881Speter#include <apr_errno.h> 32251881Speter#include <apr_md5.h> 33251881Speter 34251881Speter#include <zlib.h> 35251881Speter 36251881Speter#include "svn_pools.h" 37251881Speter#include "svn_io.h" 38251881Speter#include "svn_error.h" 39251881Speter#include "svn_string.h" 40251881Speter#include "svn_utf.h" 41251881Speter#include "svn_checksum.h" 42251881Speter#include "svn_path.h" 43251881Speter#include "svn_private_config.h" 44251881Speter#include "private/svn_error_private.h" 45251881Speter#include "private/svn_eol_private.h" 46251881Speter#include "private/svn_io_private.h" 47251881Speter#include "private/svn_subr_private.h" 48251881Speter 49251881Speter 50251881Speterstruct svn_stream_t { 51251881Speter void *baton; 52251881Speter svn_read_fn_t read_fn; 53251881Speter svn_stream_skip_fn_t skip_fn; 54251881Speter svn_write_fn_t write_fn; 55251881Speter svn_close_fn_t close_fn; 56251881Speter svn_stream_mark_fn_t mark_fn; 57251881Speter svn_stream_seek_fn_t seek_fn; 58251881Speter svn_stream__is_buffered_fn_t is_buffered_fn; 59253734Speter apr_file_t *file; /* Maybe NULL */ 60251881Speter}; 61251881Speter 62251881Speter 63251881Speter/*** Forward declarations. ***/ 64251881Speter 65251881Speterstatic svn_error_t * 66251881Speterskip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_fn); 67251881Speter 68251881Speter 69251881Speter/*** Generic streams. ***/ 70251881Speter 71251881Spetersvn_stream_t * 72251881Spetersvn_stream_create(void *baton, apr_pool_t *pool) 73251881Speter{ 74251881Speter svn_stream_t *stream; 75251881Speter 76251881Speter stream = apr_palloc(pool, sizeof(*stream)); 77251881Speter stream->baton = baton; 78251881Speter stream->read_fn = NULL; 79251881Speter stream->skip_fn = NULL; 80251881Speter stream->write_fn = NULL; 81251881Speter stream->close_fn = NULL; 82251881Speter stream->mark_fn = NULL; 83251881Speter stream->seek_fn = NULL; 84251881Speter stream->is_buffered_fn = NULL; 85253734Speter stream->file = NULL; 86251881Speter return stream; 87251881Speter} 88251881Speter 89251881Speter 90251881Spetervoid 91251881Spetersvn_stream_set_baton(svn_stream_t *stream, void *baton) 92251881Speter{ 93251881Speter stream->baton = baton; 94251881Speter} 95251881Speter 96251881Speter 97251881Spetervoid 98251881Spetersvn_stream_set_read(svn_stream_t *stream, svn_read_fn_t read_fn) 99251881Speter{ 100251881Speter stream->read_fn = read_fn; 101251881Speter} 102251881Speter 103251881Spetervoid 104251881Spetersvn_stream_set_skip(svn_stream_t *stream, svn_stream_skip_fn_t skip_fn) 105251881Speter{ 106251881Speter stream->skip_fn = skip_fn; 107251881Speter} 108251881Speter 109251881Spetervoid 110251881Spetersvn_stream_set_write(svn_stream_t *stream, svn_write_fn_t write_fn) 111251881Speter{ 112251881Speter stream->write_fn = write_fn; 113251881Speter} 114251881Speter 115251881Spetervoid 116251881Spetersvn_stream_set_close(svn_stream_t *stream, svn_close_fn_t close_fn) 117251881Speter{ 118251881Speter stream->close_fn = close_fn; 119251881Speter} 120251881Speter 121251881Spetervoid 122251881Spetersvn_stream_set_mark(svn_stream_t *stream, svn_stream_mark_fn_t mark_fn) 123251881Speter{ 124251881Speter stream->mark_fn = mark_fn; 125251881Speter} 126251881Speter 127251881Spetervoid 128251881Spetersvn_stream_set_seek(svn_stream_t *stream, svn_stream_seek_fn_t seek_fn) 129251881Speter{ 130251881Speter stream->seek_fn = seek_fn; 131251881Speter} 132251881Speter 133251881Spetervoid 134251881Spetersvn_stream__set_is_buffered(svn_stream_t *stream, 135251881Speter svn_stream__is_buffered_fn_t is_buffered_fn) 136251881Speter{ 137251881Speter stream->is_buffered_fn = is_buffered_fn; 138251881Speter} 139251881Speter 140251881Spetersvn_error_t * 141251881Spetersvn_stream_read(svn_stream_t *stream, char *buffer, apr_size_t *len) 142251881Speter{ 143251881Speter SVN_ERR_ASSERT(stream->read_fn != NULL); 144251881Speter return svn_error_trace(stream->read_fn(stream->baton, buffer, len)); 145251881Speter} 146251881Speter 147251881Speter 148251881Spetersvn_error_t * 149251881Spetersvn_stream_skip(svn_stream_t *stream, apr_size_t len) 150251881Speter{ 151251881Speter if (stream->skip_fn == NULL) 152251881Speter return svn_error_trace( 153251881Speter skip_default_handler(stream->baton, len, stream->read_fn)); 154251881Speter 155251881Speter return svn_error_trace(stream->skip_fn(stream->baton, len)); 156251881Speter} 157251881Speter 158251881Speter 159251881Spetersvn_error_t * 160251881Spetersvn_stream_write(svn_stream_t *stream, const char *data, apr_size_t *len) 161251881Speter{ 162251881Speter SVN_ERR_ASSERT(stream->write_fn != NULL); 163251881Speter return svn_error_trace(stream->write_fn(stream->baton, data, len)); 164251881Speter} 165251881Speter 166251881Speter 167251881Spetersvn_error_t * 168251881Spetersvn_stream_reset(svn_stream_t *stream) 169251881Speter{ 170251881Speter return svn_error_trace( 171251881Speter svn_stream_seek(stream, NULL)); 172251881Speter} 173251881Speter 174251881Spetersvn_boolean_t 175251881Spetersvn_stream_supports_mark(svn_stream_t *stream) 176251881Speter{ 177251881Speter return stream->mark_fn != NULL; 178251881Speter} 179251881Speter 180251881Spetersvn_error_t * 181251881Spetersvn_stream_mark(svn_stream_t *stream, svn_stream_mark_t **mark, 182251881Speter apr_pool_t *pool) 183251881Speter{ 184251881Speter if (stream->mark_fn == NULL) 185251881Speter return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL); 186251881Speter 187251881Speter return svn_error_trace(stream->mark_fn(stream->baton, mark, pool)); 188251881Speter} 189251881Speter 190251881Spetersvn_error_t * 191251881Spetersvn_stream_seek(svn_stream_t *stream, const svn_stream_mark_t *mark) 192251881Speter{ 193251881Speter if (stream->seek_fn == NULL) 194251881Speter return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL); 195251881Speter 196251881Speter return svn_error_trace(stream->seek_fn(stream->baton, mark)); 197251881Speter} 198251881Speter 199251881Spetersvn_boolean_t 200251881Spetersvn_stream__is_buffered(svn_stream_t *stream) 201251881Speter{ 202251881Speter if (stream->is_buffered_fn == NULL) 203251881Speter return FALSE; 204251881Speter 205251881Speter return stream->is_buffered_fn(stream->baton); 206251881Speter} 207251881Speter 208251881Spetersvn_error_t * 209251881Spetersvn_stream_close(svn_stream_t *stream) 210251881Speter{ 211251881Speter if (stream->close_fn == NULL) 212251881Speter return SVN_NO_ERROR; 213251881Speter return svn_error_trace(stream->close_fn(stream->baton)); 214251881Speter} 215251881Speter 216251881Spetersvn_error_t * 217251881Spetersvn_stream_puts(svn_stream_t *stream, 218251881Speter const char *str) 219251881Speter{ 220251881Speter apr_size_t len; 221251881Speter len = strlen(str); 222251881Speter return svn_error_trace(svn_stream_write(stream, str, &len)); 223251881Speter} 224251881Speter 225251881Spetersvn_error_t * 226251881Spetersvn_stream_printf(svn_stream_t *stream, 227251881Speter apr_pool_t *pool, 228251881Speter const char *fmt, 229251881Speter ...) 230251881Speter{ 231251881Speter const char *message; 232251881Speter va_list ap; 233251881Speter 234251881Speter va_start(ap, fmt); 235251881Speter message = apr_pvsprintf(pool, fmt, ap); 236251881Speter va_end(ap); 237251881Speter 238251881Speter return svn_error_trace(svn_stream_puts(stream, message)); 239251881Speter} 240251881Speter 241251881Speter 242251881Spetersvn_error_t * 243251881Spetersvn_stream_printf_from_utf8(svn_stream_t *stream, 244251881Speter const char *encoding, 245251881Speter apr_pool_t *pool, 246251881Speter const char *fmt, 247251881Speter ...) 248251881Speter{ 249251881Speter const char *message, *translated; 250251881Speter va_list ap; 251251881Speter 252251881Speter va_start(ap, fmt); 253251881Speter message = apr_pvsprintf(pool, fmt, ap); 254251881Speter va_end(ap); 255251881Speter 256251881Speter SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated, message, encoding, 257251881Speter pool)); 258251881Speter 259251881Speter return svn_error_trace(svn_stream_puts(stream, translated)); 260251881Speter} 261251881Speter 262251881Speter/* Size that 90% of the lines we encounter will be not longer than. 263251881Speter used by stream_readline_bytewise() and stream_readline_chunky(). 264251881Speter */ 265251881Speter#define LINE_CHUNK_SIZE 80 266251881Speter 267251881Speter/* Guts of svn_stream_readline(). 268251881Speter * Returns the line read from STREAM in *STRINGBUF, and indicates 269251881Speter * end-of-file in *EOF. If DETECT_EOL is TRUE, the end-of-line indicator 270251881Speter * is detected automatically and returned in *EOL. 271251881Speter * If DETECT_EOL is FALSE, *EOL must point to the desired end-of-line 272251881Speter * indicator. STRINGBUF is allocated in POOL. */ 273251881Speterstatic svn_error_t * 274251881Speterstream_readline_bytewise(svn_stringbuf_t **stringbuf, 275251881Speter svn_boolean_t *eof, 276251881Speter const char *eol, 277251881Speter svn_stream_t *stream, 278251881Speter apr_pool_t *pool) 279251881Speter{ 280251881Speter svn_stringbuf_t *str; 281251881Speter apr_size_t numbytes; 282251881Speter const char *match; 283251881Speter char c; 284251881Speter 285251881Speter /* Since we're reading one character at a time, let's at least 286251881Speter optimize for the 90% case. 90% of the time, we can avoid the 287251881Speter stringbuf ever having to realloc() itself if we start it out at 288251881Speter 80 chars. */ 289251881Speter str = svn_stringbuf_create_ensure(LINE_CHUNK_SIZE, pool); 290251881Speter 291251881Speter /* Read into STR up to and including the next EOL sequence. */ 292251881Speter match = eol; 293251881Speter while (*match) 294251881Speter { 295251881Speter numbytes = 1; 296251881Speter SVN_ERR(svn_stream_read(stream, &c, &numbytes)); 297251881Speter if (numbytes != 1) 298251881Speter { 299251881Speter /* a 'short' read means the stream has run out. */ 300251881Speter *eof = TRUE; 301251881Speter *stringbuf = str; 302251881Speter return SVN_NO_ERROR; 303251881Speter } 304251881Speter 305251881Speter if (c == *match) 306251881Speter match++; 307251881Speter else 308251881Speter match = eol; 309251881Speter 310251881Speter svn_stringbuf_appendbyte(str, c); 311251881Speter } 312251881Speter 313251881Speter *eof = FALSE; 314251881Speter svn_stringbuf_chop(str, match - eol); 315251881Speter *stringbuf = str; 316251881Speter 317251881Speter return SVN_NO_ERROR; 318251881Speter} 319251881Speter 320251881Speterstatic svn_error_t * 321251881Speterstream_readline_chunky(svn_stringbuf_t **stringbuf, 322251881Speter svn_boolean_t *eof, 323251881Speter const char *eol, 324251881Speter svn_stream_t *stream, 325251881Speter apr_pool_t *pool) 326251881Speter{ 327251881Speter /* Read larger chunks of data at once into this buffer and scan 328251881Speter * that for EOL. A good chunk size should be about 80 chars since 329251881Speter * most text lines will be shorter. However, don't use a much 330251881Speter * larger value because filling the buffer from the stream takes 331251881Speter * time as well. 332251881Speter */ 333251881Speter char buffer[LINE_CHUNK_SIZE+1]; 334251881Speter 335251881Speter /* variables */ 336251881Speter svn_stream_mark_t *mark; 337251881Speter apr_size_t numbytes; 338251881Speter const char *eol_pos; 339251881Speter apr_size_t total_parsed = 0; 340251881Speter 341251881Speter /* invariant for this call */ 342251881Speter const size_t eol_len = strlen(eol); 343251881Speter 344251881Speter /* Remember the line start so this plus the line length will be 345251881Speter * the position to move to at the end of this function. 346251881Speter */ 347251881Speter SVN_ERR(svn_stream_mark(stream, &mark, pool)); 348251881Speter 349251881Speter /* Read the first chunk. */ 350251881Speter numbytes = LINE_CHUNK_SIZE; 351251881Speter SVN_ERR(svn_stream_read(stream, buffer, &numbytes)); 352251881Speter buffer[numbytes] = '\0'; 353251881Speter 354251881Speter /* Look for the EOL in this first chunk. If we find it, we are done here. 355251881Speter */ 356251881Speter eol_pos = strstr(buffer, eol); 357251881Speter if (eol_pos != NULL) 358251881Speter { 359251881Speter *stringbuf = svn_stringbuf_ncreate(buffer, eol_pos - buffer, pool); 360251881Speter total_parsed = eol_pos - buffer + eol_len; 361251881Speter } 362251881Speter else if (numbytes < LINE_CHUNK_SIZE) 363251881Speter { 364251881Speter /* We hit EOF but not EOL. 365251881Speter */ 366251881Speter *stringbuf = svn_stringbuf_ncreate(buffer, numbytes, pool); 367251881Speter *eof = TRUE; 368251881Speter return SVN_NO_ERROR; 369251881Speter } 370251881Speter else 371251881Speter { 372251881Speter /* A larger buffer for the string is needed. */ 373251881Speter svn_stringbuf_t *str; 374251881Speter str = svn_stringbuf_create_ensure(2*LINE_CHUNK_SIZE, pool); 375251881Speter svn_stringbuf_appendbytes(str, buffer, numbytes); 376251881Speter *stringbuf = str; 377251881Speter 378251881Speter /* Loop reading chunks until an EOL was found. If we hit EOF, fall 379251881Speter * back to the standard implementation. */ 380251881Speter do 381251881Speter { 382251881Speter /* Append the next chunk to the string read so far. 383251881Speter */ 384251881Speter svn_stringbuf_ensure(str, str->len + LINE_CHUNK_SIZE); 385251881Speter numbytes = LINE_CHUNK_SIZE; 386251881Speter SVN_ERR(svn_stream_read(stream, str->data + str->len, &numbytes)); 387251881Speter str->len += numbytes; 388251881Speter str->data[str->len] = '\0'; 389251881Speter 390251881Speter /* Look for the EOL in the new data plus the last part of the 391251881Speter * previous chunk because the EOL may span over the boundary 392251881Speter * between both chunks. 393251881Speter */ 394251881Speter eol_pos = strstr(str->data + str->len - numbytes - (eol_len-1), eol); 395251881Speter 396251881Speter if ((numbytes < LINE_CHUNK_SIZE) && (eol_pos == NULL)) 397251881Speter { 398251881Speter /* We hit EOF instead of EOL. */ 399251881Speter *eof = TRUE; 400251881Speter return SVN_NO_ERROR; 401251881Speter } 402251881Speter } 403251881Speter while (eol_pos == NULL); 404251881Speter 405251881Speter /* Number of bytes we actually consumed (i.e. line + EOF). 406251881Speter * We need to "return" the rest to the stream by moving its 407251881Speter * read pointer. 408251881Speter */ 409251881Speter total_parsed = eol_pos - str->data + eol_len; 410251881Speter 411251881Speter /* Terminate the string at the EOL postion and return it. */ 412251881Speter str->len = eol_pos - str->data; 413251881Speter str->data[str->len] = 0; 414251881Speter } 415251881Speter 416251881Speter /* Move the stream read pointer to the first position behind the EOL. 417251881Speter */ 418251881Speter SVN_ERR(svn_stream_seek(stream, mark)); 419251881Speter return svn_error_trace(svn_stream_skip(stream, total_parsed)); 420251881Speter} 421251881Speter 422251881Speter/* Guts of svn_stream_readline(). 423251881Speter * Returns the line read from STREAM in *STRINGBUF, and indicates 424251881Speter * end-of-file in *EOF. EOL must point to the desired end-of-line 425251881Speter * indicator. STRINGBUF is allocated in POOL. */ 426251881Speterstatic svn_error_t * 427251881Speterstream_readline(svn_stringbuf_t **stringbuf, 428251881Speter svn_boolean_t *eof, 429251881Speter const char *eol, 430251881Speter svn_stream_t *stream, 431251881Speter apr_pool_t *pool) 432251881Speter{ 433251881Speter *eof = FALSE; 434251881Speter 435251881Speter /* Often, we operate on APR file or string-based streams and know what 436251881Speter * EOL we are looking for. Optimize that common case. 437251881Speter */ 438251881Speter if (svn_stream_supports_mark(stream) && 439251881Speter svn_stream__is_buffered(stream)) 440251881Speter { 441251881Speter /* We can efficiently read chunks speculatively and reposition the 442251881Speter * stream pointer to the end of the line once we found that. 443251881Speter */ 444251881Speter SVN_ERR(stream_readline_chunky(stringbuf, 445251881Speter eof, 446251881Speter eol, 447251881Speter stream, 448251881Speter pool)); 449251881Speter } 450251881Speter else 451251881Speter { 452251881Speter /* Use the standard byte-byte implementation. 453251881Speter */ 454251881Speter SVN_ERR(stream_readline_bytewise(stringbuf, 455251881Speter eof, 456251881Speter eol, 457251881Speter stream, 458251881Speter pool)); 459251881Speter } 460251881Speter 461251881Speter return SVN_NO_ERROR; 462251881Speter} 463251881Speter 464251881Spetersvn_error_t * 465251881Spetersvn_stream_readline(svn_stream_t *stream, 466251881Speter svn_stringbuf_t **stringbuf, 467251881Speter const char *eol, 468251881Speter svn_boolean_t *eof, 469251881Speter apr_pool_t *pool) 470251881Speter{ 471251881Speter return svn_error_trace(stream_readline(stringbuf, eof, eol, stream, 472251881Speter pool)); 473251881Speter} 474251881Speter 475251881Spetersvn_error_t *svn_stream_copy3(svn_stream_t *from, svn_stream_t *to, 476251881Speter svn_cancel_func_t cancel_func, 477251881Speter void *cancel_baton, 478251881Speter apr_pool_t *scratch_pool) 479251881Speter{ 480251881Speter char *buf = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE); 481251881Speter svn_error_t *err; 482251881Speter svn_error_t *err2; 483251881Speter 484251881Speter /* Read and write chunks until we get a short read, indicating the 485251881Speter end of the stream. (We can't get a short write without an 486251881Speter associated error.) */ 487251881Speter while (1) 488251881Speter { 489251881Speter apr_size_t len = SVN__STREAM_CHUNK_SIZE; 490251881Speter 491251881Speter if (cancel_func) 492251881Speter { 493251881Speter err = cancel_func(cancel_baton); 494251881Speter if (err) 495251881Speter break; 496251881Speter } 497251881Speter 498251881Speter err = svn_stream_read(from, buf, &len); 499251881Speter if (err) 500251881Speter break; 501251881Speter 502251881Speter if (len > 0) 503251881Speter err = svn_stream_write(to, buf, &len); 504251881Speter 505251881Speter if (err || (len != SVN__STREAM_CHUNK_SIZE)) 506251881Speter break; 507251881Speter } 508251881Speter 509251881Speter err2 = svn_error_compose_create(svn_stream_close(from), 510251881Speter svn_stream_close(to)); 511251881Speter 512251881Speter return svn_error_compose_create(err, err2); 513251881Speter} 514251881Speter 515251881Spetersvn_error_t * 516251881Spetersvn_stream_contents_same2(svn_boolean_t *same, 517251881Speter svn_stream_t *stream1, 518251881Speter svn_stream_t *stream2, 519251881Speter apr_pool_t *pool) 520251881Speter{ 521251881Speter char *buf1 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); 522251881Speter char *buf2 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); 523251881Speter apr_size_t bytes_read1 = SVN__STREAM_CHUNK_SIZE; 524251881Speter apr_size_t bytes_read2 = SVN__STREAM_CHUNK_SIZE; 525251881Speter svn_error_t *err = NULL; 526251881Speter 527251881Speter *same = TRUE; /* assume TRUE, until disproved below */ 528251881Speter while (bytes_read1 == SVN__STREAM_CHUNK_SIZE 529251881Speter && bytes_read2 == SVN__STREAM_CHUNK_SIZE) 530251881Speter { 531251881Speter err = svn_stream_read(stream1, buf1, &bytes_read1); 532251881Speter if (err) 533251881Speter break; 534251881Speter err = svn_stream_read(stream2, buf2, &bytes_read2); 535251881Speter if (err) 536251881Speter break; 537251881Speter 538251881Speter if ((bytes_read1 != bytes_read2) 539251881Speter || (memcmp(buf1, buf2, bytes_read1))) 540251881Speter { 541251881Speter *same = FALSE; 542251881Speter break; 543251881Speter } 544251881Speter } 545251881Speter 546251881Speter return svn_error_compose_create(err, 547251881Speter svn_error_compose_create( 548251881Speter svn_stream_close(stream1), 549251881Speter svn_stream_close(stream2))); 550251881Speter} 551251881Speter 552251881Speter 553251881Speter/*** Stream implementation utilities ***/ 554251881Speter 555251881Speter/* Skip data from any stream by reading and simply discarding it. */ 556251881Speterstatic svn_error_t * 557251881Speterskip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_fn) 558251881Speter{ 559251881Speter apr_size_t bytes_read = 1; 560251881Speter char buffer[4096]; 561251881Speter apr_size_t to_read = len; 562251881Speter 563251881Speter while ((to_read > 0) && (bytes_read > 0)) 564251881Speter { 565251881Speter bytes_read = sizeof(buffer) < to_read ? sizeof(buffer) : to_read; 566251881Speter SVN_ERR(read_fn(baton, buffer, &bytes_read)); 567251881Speter to_read -= bytes_read; 568251881Speter } 569251881Speter 570251881Speter return SVN_NO_ERROR; 571251881Speter} 572251881Speter 573251881Speter 574251881Speter 575251881Speter/*** Generic readable empty stream ***/ 576251881Speter 577251881Speterstatic svn_error_t * 578251881Speterread_handler_empty(void *baton, char *buffer, apr_size_t *len) 579251881Speter{ 580251881Speter *len = 0; 581251881Speter return SVN_NO_ERROR; 582251881Speter} 583251881Speter 584251881Speterstatic svn_error_t * 585251881Speterwrite_handler_empty(void *baton, const char *data, apr_size_t *len) 586251881Speter{ 587251881Speter return SVN_NO_ERROR; 588251881Speter} 589251881Speter 590251881Speterstatic svn_error_t * 591251881Spetermark_handler_empty(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 592251881Speter{ 593251881Speter *mark = NULL; /* Seek to start of stream marker */ 594251881Speter return SVN_NO_ERROR; 595251881Speter} 596251881Speter 597251881Speterstatic svn_error_t * 598251881Speterseek_handler_empty(void *baton, const svn_stream_mark_t *mark) 599251881Speter{ 600251881Speter return SVN_NO_ERROR; 601251881Speter} 602251881Speter 603251881Speterstatic svn_boolean_t 604251881Speteris_buffered_handler_empty(void *baton) 605251881Speter{ 606251881Speter return FALSE; 607251881Speter} 608251881Speter 609251881Speter 610251881Spetersvn_stream_t * 611251881Spetersvn_stream_empty(apr_pool_t *pool) 612251881Speter{ 613251881Speter svn_stream_t *stream; 614251881Speter 615251881Speter stream = svn_stream_create(NULL, pool); 616251881Speter svn_stream_set_read(stream, read_handler_empty); 617251881Speter svn_stream_set_write(stream, write_handler_empty); 618251881Speter svn_stream_set_mark(stream, mark_handler_empty); 619251881Speter svn_stream_set_seek(stream, seek_handler_empty); 620251881Speter svn_stream__set_is_buffered(stream, is_buffered_handler_empty); 621251881Speter return stream; 622251881Speter} 623251881Speter 624251881Speter 625251881Speter 626251881Speter/*** Stream duplication support ***/ 627251881Speterstruct baton_tee { 628251881Speter svn_stream_t *out1; 629251881Speter svn_stream_t *out2; 630251881Speter}; 631251881Speter 632251881Speter 633251881Speterstatic svn_error_t * 634251881Speterwrite_handler_tee(void *baton, const char *data, apr_size_t *len) 635251881Speter{ 636251881Speter struct baton_tee *bt = baton; 637251881Speter 638251881Speter SVN_ERR(svn_stream_write(bt->out1, data, len)); 639251881Speter SVN_ERR(svn_stream_write(bt->out2, data, len)); 640251881Speter 641251881Speter return SVN_NO_ERROR; 642251881Speter} 643251881Speter 644251881Speter 645251881Speterstatic svn_error_t * 646251881Speterclose_handler_tee(void *baton) 647251881Speter{ 648251881Speter struct baton_tee *bt = baton; 649251881Speter 650251881Speter SVN_ERR(svn_stream_close(bt->out1)); 651251881Speter SVN_ERR(svn_stream_close(bt->out2)); 652251881Speter 653251881Speter return SVN_NO_ERROR; 654251881Speter} 655251881Speter 656251881Speter 657251881Spetersvn_stream_t * 658251881Spetersvn_stream_tee(svn_stream_t *out1, 659251881Speter svn_stream_t *out2, 660251881Speter apr_pool_t *pool) 661251881Speter{ 662251881Speter struct baton_tee *baton; 663251881Speter svn_stream_t *stream; 664251881Speter 665251881Speter if (out1 == NULL) 666251881Speter return out2; 667251881Speter 668251881Speter if (out2 == NULL) 669251881Speter return out1; 670251881Speter 671251881Speter baton = apr_palloc(pool, sizeof(*baton)); 672251881Speter baton->out1 = out1; 673251881Speter baton->out2 = out2; 674251881Speter stream = svn_stream_create(baton, pool); 675251881Speter svn_stream_set_write(stream, write_handler_tee); 676251881Speter svn_stream_set_close(stream, close_handler_tee); 677251881Speter 678251881Speter return stream; 679251881Speter} 680251881Speter 681251881Speter 682251881Speter 683251881Speter/*** Ownership detaching stream ***/ 684251881Speter 685251881Speterstatic svn_error_t * 686251881Speterread_handler_disown(void *baton, char *buffer, apr_size_t *len) 687251881Speter{ 688251881Speter return svn_error_trace(svn_stream_read(baton, buffer, len)); 689251881Speter} 690251881Speter 691251881Speterstatic svn_error_t * 692251881Speterskip_handler_disown(void *baton, apr_size_t len) 693251881Speter{ 694251881Speter return svn_error_trace(svn_stream_skip(baton, len)); 695251881Speter} 696251881Speter 697251881Speterstatic svn_error_t * 698251881Speterwrite_handler_disown(void *baton, const char *buffer, apr_size_t *len) 699251881Speter{ 700251881Speter return svn_error_trace(svn_stream_write(baton, buffer, len)); 701251881Speter} 702251881Speter 703251881Speterstatic svn_error_t * 704251881Spetermark_handler_disown(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 705251881Speter{ 706251881Speter return svn_error_trace(svn_stream_mark(baton, mark, pool)); 707251881Speter} 708251881Speter 709251881Speterstatic svn_error_t * 710251881Speterseek_handler_disown(void *baton, const svn_stream_mark_t *mark) 711251881Speter{ 712251881Speter return svn_error_trace(svn_stream_seek(baton, mark)); 713251881Speter} 714251881Speter 715251881Speterstatic svn_boolean_t 716251881Speteris_buffered_handler_disown(void *baton) 717251881Speter{ 718251881Speter return svn_stream__is_buffered(baton); 719251881Speter} 720251881Speter 721251881Spetersvn_stream_t * 722251881Spetersvn_stream_disown(svn_stream_t *stream, apr_pool_t *pool) 723251881Speter{ 724251881Speter svn_stream_t *s = svn_stream_create(stream, pool); 725251881Speter 726251881Speter svn_stream_set_read(s, read_handler_disown); 727251881Speter svn_stream_set_skip(s, skip_handler_disown); 728251881Speter svn_stream_set_write(s, write_handler_disown); 729251881Speter svn_stream_set_mark(s, mark_handler_disown); 730251881Speter svn_stream_set_seek(s, seek_handler_disown); 731251881Speter svn_stream__set_is_buffered(s, is_buffered_handler_disown); 732251881Speter 733251881Speter return s; 734251881Speter} 735251881Speter 736251881Speter 737251881Speter 738251881Speter/*** Generic stream for APR files ***/ 739251881Speterstruct baton_apr { 740251881Speter apr_file_t *file; 741251881Speter apr_pool_t *pool; 742251881Speter}; 743251881Speter 744251881Speter/* svn_stream_mark_t for streams backed by APR files. */ 745251881Speterstruct mark_apr { 746251881Speter apr_off_t off; 747251881Speter}; 748251881Speter 749251881Speterstatic svn_error_t * 750251881Speterread_handler_apr(void *baton, char *buffer, apr_size_t *len) 751251881Speter{ 752251881Speter struct baton_apr *btn = baton; 753251881Speter svn_error_t *err; 754251881Speter svn_boolean_t eof; 755251881Speter 756251881Speter if (*len == 1) 757251881Speter { 758251881Speter err = svn_io_file_getc(buffer, btn->file, btn->pool); 759251881Speter if (err) 760251881Speter { 761251881Speter *len = 0; 762251881Speter if (APR_STATUS_IS_EOF(err->apr_err)) 763251881Speter { 764251881Speter svn_error_clear(err); 765251881Speter err = SVN_NO_ERROR; 766251881Speter } 767251881Speter } 768251881Speter } 769251881Speter else 770251881Speter err = svn_io_file_read_full2(btn->file, buffer, *len, len, 771251881Speter &eof, btn->pool); 772251881Speter 773251881Speter return svn_error_trace(err); 774251881Speter} 775251881Speter 776251881Speterstatic svn_error_t * 777251881Speterskip_handler_apr(void *baton, apr_size_t len) 778251881Speter{ 779251881Speter struct baton_apr *btn = baton; 780251881Speter apr_off_t offset = len; 781251881Speter 782251881Speter return svn_error_trace( 783251881Speter svn_io_file_seek(btn->file, APR_CUR, &offset, btn->pool)); 784251881Speter} 785251881Speter 786251881Speterstatic svn_error_t * 787251881Speterwrite_handler_apr(void *baton, const char *data, apr_size_t *len) 788251881Speter{ 789251881Speter struct baton_apr *btn = baton; 790251881Speter svn_error_t *err; 791251881Speter 792251881Speter if (*len == 1) 793251881Speter { 794251881Speter err = svn_io_file_putc(*data, btn->file, btn->pool); 795251881Speter if (err) 796251881Speter *len = 0; 797251881Speter } 798251881Speter else 799251881Speter err = svn_io_file_write_full(btn->file, data, *len, len, btn->pool); 800251881Speter 801251881Speter return svn_error_trace(err); 802251881Speter} 803251881Speter 804251881Speterstatic svn_error_t * 805251881Speterclose_handler_apr(void *baton) 806251881Speter{ 807251881Speter struct baton_apr *btn = baton; 808251881Speter 809251881Speter return svn_error_trace(svn_io_file_close(btn->file, btn->pool)); 810251881Speter} 811251881Speter 812251881Speterstatic svn_error_t * 813251881Spetermark_handler_apr(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 814251881Speter{ 815251881Speter struct baton_apr *btn = baton; 816251881Speter struct mark_apr *mark_apr; 817251881Speter 818251881Speter mark_apr = apr_palloc(pool, sizeof(*mark_apr)); 819251881Speter mark_apr->off = 0; 820251881Speter SVN_ERR(svn_io_file_seek(btn->file, APR_CUR, &mark_apr->off, btn->pool)); 821251881Speter *mark = (svn_stream_mark_t *)mark_apr; 822251881Speter return SVN_NO_ERROR; 823251881Speter} 824251881Speter 825251881Speterstatic svn_error_t * 826251881Speterseek_handler_apr(void *baton, const svn_stream_mark_t *mark) 827251881Speter{ 828251881Speter struct baton_apr *btn = baton; 829251881Speter apr_off_t offset = (mark != NULL) ? ((const struct mark_apr *)mark)->off : 0; 830251881Speter 831251881Speter SVN_ERR(svn_io_file_seek(btn->file, APR_SET, &offset, btn->pool)); 832251881Speter 833251881Speter return SVN_NO_ERROR; 834251881Speter} 835251881Speter 836251881Speterstatic svn_boolean_t 837251881Speteris_buffered_handler_apr(void *baton) 838251881Speter{ 839251881Speter struct baton_apr *btn = baton; 840251881Speter return (apr_file_flags_get(btn->file) & APR_BUFFERED) != 0; 841251881Speter} 842251881Speter 843251881Spetersvn_error_t * 844251881Spetersvn_stream_open_readonly(svn_stream_t **stream, 845251881Speter const char *path, 846251881Speter apr_pool_t *result_pool, 847251881Speter apr_pool_t *scratch_pool) 848251881Speter{ 849251881Speter apr_file_t *file; 850251881Speter 851251881Speter SVN_ERR(svn_io_file_open(&file, path, APR_READ | APR_BUFFERED, 852251881Speter APR_OS_DEFAULT, result_pool)); 853251881Speter *stream = svn_stream_from_aprfile2(file, FALSE, result_pool); 854251881Speter 855251881Speter return SVN_NO_ERROR; 856251881Speter} 857251881Speter 858251881Speter 859251881Spetersvn_error_t * 860251881Spetersvn_stream_open_writable(svn_stream_t **stream, 861251881Speter const char *path, 862251881Speter apr_pool_t *result_pool, 863251881Speter apr_pool_t *scratch_pool) 864251881Speter{ 865251881Speter apr_file_t *file; 866251881Speter 867251881Speter SVN_ERR(svn_io_file_open(&file, path, 868251881Speter APR_WRITE 869251881Speter | APR_BUFFERED 870251881Speter | APR_CREATE 871251881Speter | APR_EXCL, 872251881Speter APR_OS_DEFAULT, result_pool)); 873251881Speter *stream = svn_stream_from_aprfile2(file, FALSE, result_pool); 874251881Speter 875251881Speter return SVN_NO_ERROR; 876251881Speter} 877251881Speter 878251881Speter 879251881Spetersvn_error_t * 880251881Spetersvn_stream_open_unique(svn_stream_t **stream, 881251881Speter const char **temp_path, 882251881Speter const char *dirpath, 883251881Speter svn_io_file_del_t delete_when, 884251881Speter apr_pool_t *result_pool, 885251881Speter apr_pool_t *scratch_pool) 886251881Speter{ 887251881Speter apr_file_t *file; 888251881Speter 889251881Speter SVN_ERR(svn_io_open_unique_file3(&file, temp_path, dirpath, 890251881Speter delete_when, result_pool, scratch_pool)); 891251881Speter *stream = svn_stream_from_aprfile2(file, FALSE, result_pool); 892251881Speter 893251881Speter return SVN_NO_ERROR; 894251881Speter} 895251881Speter 896251881Speter 897251881Spetersvn_stream_t * 898251881Spetersvn_stream_from_aprfile2(apr_file_t *file, 899251881Speter svn_boolean_t disown, 900251881Speter apr_pool_t *pool) 901251881Speter{ 902251881Speter struct baton_apr *baton; 903251881Speter svn_stream_t *stream; 904251881Speter 905251881Speter if (file == NULL) 906251881Speter return svn_stream_empty(pool); 907251881Speter 908251881Speter baton = apr_palloc(pool, sizeof(*baton)); 909251881Speter baton->file = file; 910251881Speter baton->pool = pool; 911251881Speter stream = svn_stream_create(baton, pool); 912251881Speter svn_stream_set_read(stream, read_handler_apr); 913251881Speter svn_stream_set_write(stream, write_handler_apr); 914251881Speter svn_stream_set_skip(stream, skip_handler_apr); 915251881Speter svn_stream_set_mark(stream, mark_handler_apr); 916251881Speter svn_stream_set_seek(stream, seek_handler_apr); 917251881Speter svn_stream__set_is_buffered(stream, is_buffered_handler_apr); 918253734Speter stream->file = file; 919251881Speter 920251881Speter if (! disown) 921251881Speter svn_stream_set_close(stream, close_handler_apr); 922251881Speter 923251881Speter return stream; 924251881Speter} 925251881Speter 926253734Speterapr_file_t * 927253734Spetersvn_stream__aprfile(svn_stream_t *stream) 928253734Speter{ 929253734Speter return stream->file; 930253734Speter} 931253734Speter 932251881Speter 933251881Speter/* Compressed stream support */ 934251881Speter 935251881Speter#define ZBUFFER_SIZE 4096 /* The size of the buffer the 936251881Speter compressed stream uses to read from 937251881Speter the substream. Basically an 938251881Speter arbitrary value, picked to be about 939251881Speter page-sized. */ 940251881Speter 941251881Speterstruct zbaton { 942251881Speter z_stream *in; /* compressed stream for reading */ 943251881Speter z_stream *out; /* compressed stream for writing */ 944251881Speter svn_read_fn_t read; /* substream's read function */ 945251881Speter svn_write_fn_t write; /* substream's write function */ 946251881Speter svn_close_fn_t close; /* substream's close function */ 947251881Speter void *read_buffer; /* buffer used for reading from 948251881Speter substream */ 949251881Speter int read_flush; /* what flush mode to use while 950251881Speter reading */ 951251881Speter apr_pool_t *pool; /* The pool this baton is allocated 952251881Speter on */ 953251881Speter void *subbaton; /* The substream's baton */ 954251881Speter}; 955251881Speter 956251881Speter/* zlib alloc function. opaque is the pool we need. */ 957251881Speterstatic voidpf 958251881Speterzalloc(voidpf opaque, uInt items, uInt size) 959251881Speter{ 960251881Speter apr_pool_t *pool = opaque; 961251881Speter 962251881Speter return apr_palloc(pool, items * size); 963251881Speter} 964251881Speter 965251881Speter/* zlib free function */ 966251881Speterstatic void 967251881Speterzfree(voidpf opaque, voidpf address) 968251881Speter{ 969251881Speter /* Empty, since we allocate on the pool */ 970251881Speter} 971251881Speter 972251881Speter/* Helper function to figure out the sync mode */ 973251881Speterstatic svn_error_t * 974251881Speterread_helper_gz(svn_read_fn_t read_fn, 975251881Speter void *baton, 976251881Speter char *buffer, 977251881Speter uInt *len, int *zflush) 978251881Speter{ 979251881Speter uInt orig_len = *len; 980251881Speter 981251881Speter /* There's no reason this value should grow bigger than the range of 982251881Speter uInt, but Subversion's API requires apr_size_t. */ 983251881Speter apr_size_t apr_len = (apr_size_t) *len; 984251881Speter 985251881Speter SVN_ERR((*read_fn)(baton, buffer, &apr_len)); 986251881Speter 987251881Speter /* Type cast back to uInt type that zlib uses. On LP64 platforms 988251881Speter apr_size_t will be bigger than uInt. */ 989251881Speter *len = (uInt) apr_len; 990251881Speter 991251881Speter /* I wanted to use Z_FINISH here, but we need to know our buffer is 992251881Speter big enough */ 993251881Speter *zflush = (*len) < orig_len ? Z_SYNC_FLUSH : Z_SYNC_FLUSH; 994251881Speter 995251881Speter return SVN_NO_ERROR; 996251881Speter} 997251881Speter 998251881Speter/* Handle reading from a compressed stream */ 999251881Speterstatic svn_error_t * 1000251881Speterread_handler_gz(void *baton, char *buffer, apr_size_t *len) 1001251881Speter{ 1002251881Speter struct zbaton *btn = baton; 1003251881Speter int zerr; 1004251881Speter 1005251881Speter if (btn->in == NULL) 1006251881Speter { 1007251881Speter btn->in = apr_palloc(btn->pool, sizeof(z_stream)); 1008251881Speter btn->in->zalloc = zalloc; 1009251881Speter btn->in->zfree = zfree; 1010251881Speter btn->in->opaque = btn->pool; 1011251881Speter btn->read_buffer = apr_palloc(btn->pool, ZBUFFER_SIZE); 1012251881Speter btn->in->next_in = btn->read_buffer; 1013251881Speter btn->in->avail_in = ZBUFFER_SIZE; 1014251881Speter 1015251881Speter SVN_ERR(read_helper_gz(btn->read, btn->subbaton, btn->read_buffer, 1016251881Speter &btn->in->avail_in, &btn->read_flush)); 1017251881Speter 1018251881Speter zerr = inflateInit(btn->in); 1019251881Speter SVN_ERR(svn_error__wrap_zlib(zerr, "inflateInit", btn->in->msg)); 1020251881Speter } 1021251881Speter 1022251881Speter btn->in->next_out = (Bytef *) buffer; 1023251881Speter btn->in->avail_out = (uInt) *len; 1024251881Speter 1025251881Speter while (btn->in->avail_out > 0) 1026251881Speter { 1027251881Speter if (btn->in->avail_in <= 0) 1028251881Speter { 1029251881Speter btn->in->avail_in = ZBUFFER_SIZE; 1030251881Speter btn->in->next_in = btn->read_buffer; 1031251881Speter SVN_ERR(read_helper_gz(btn->read, btn->subbaton, btn->read_buffer, 1032251881Speter &btn->in->avail_in, &btn->read_flush)); 1033251881Speter } 1034251881Speter 1035251881Speter /* Short read means underlying stream has run out. */ 1036251881Speter if (btn->in->avail_in == 0) 1037251881Speter { 1038251881Speter *len = 0; 1039251881Speter return SVN_NO_ERROR; 1040251881Speter } 1041251881Speter 1042251881Speter zerr = inflate(btn->in, btn->read_flush); 1043251881Speter if (zerr == Z_STREAM_END) 1044251881Speter break; 1045251881Speter else if (zerr != Z_OK) 1046251881Speter return svn_error_trace(svn_error__wrap_zlib(zerr, "inflate", 1047251881Speter btn->in->msg)); 1048251881Speter } 1049251881Speter 1050251881Speter *len -= btn->in->avail_out; 1051251881Speter return SVN_NO_ERROR; 1052251881Speter} 1053251881Speter 1054251881Speter/* Compress data and write it to the substream */ 1055251881Speterstatic svn_error_t * 1056251881Speterwrite_handler_gz(void *baton, const char *buffer, apr_size_t *len) 1057251881Speter{ 1058251881Speter struct zbaton *btn = baton; 1059251881Speter apr_pool_t *subpool; 1060251881Speter void *write_buf; 1061251881Speter apr_size_t buf_size, write_len; 1062251881Speter int zerr; 1063251881Speter 1064251881Speter if (btn->out == NULL) 1065251881Speter { 1066251881Speter btn->out = apr_palloc(btn->pool, sizeof(z_stream)); 1067251881Speter btn->out->zalloc = zalloc; 1068251881Speter btn->out->zfree = zfree; 1069251881Speter btn->out->opaque = btn->pool; 1070251881Speter 1071251881Speter zerr = deflateInit(btn->out, Z_DEFAULT_COMPRESSION); 1072251881Speter SVN_ERR(svn_error__wrap_zlib(zerr, "deflateInit", btn->out->msg)); 1073251881Speter } 1074251881Speter 1075251881Speter /* The largest buffer we should need is 0.1% larger than the 1076251881Speter compressed data, + 12 bytes. This info comes from zlib.h. */ 1077251881Speter buf_size = *len + (*len / 1000) + 13; 1078251881Speter subpool = svn_pool_create(btn->pool); 1079251881Speter write_buf = apr_palloc(subpool, buf_size); 1080251881Speter 1081251881Speter btn->out->next_in = (Bytef *) buffer; /* Casting away const! */ 1082251881Speter btn->out->avail_in = (uInt) *len; 1083251881Speter 1084251881Speter while (btn->out->avail_in > 0) 1085251881Speter { 1086251881Speter btn->out->next_out = write_buf; 1087251881Speter btn->out->avail_out = (uInt) buf_size; 1088251881Speter 1089251881Speter zerr = deflate(btn->out, Z_NO_FLUSH); 1090251881Speter SVN_ERR(svn_error__wrap_zlib(zerr, "deflate", btn->out->msg)); 1091251881Speter write_len = buf_size - btn->out->avail_out; 1092251881Speter if (write_len > 0) 1093251881Speter SVN_ERR(btn->write(btn->subbaton, write_buf, &write_len)); 1094251881Speter } 1095251881Speter 1096251881Speter svn_pool_destroy(subpool); 1097251881Speter 1098251881Speter return SVN_NO_ERROR; 1099251881Speter} 1100251881Speter 1101251881Speter/* Handle flushing and closing the stream */ 1102251881Speterstatic svn_error_t * 1103251881Speterclose_handler_gz(void *baton) 1104251881Speter{ 1105251881Speter struct zbaton *btn = baton; 1106251881Speter int zerr; 1107251881Speter 1108251881Speter if (btn->in != NULL) 1109251881Speter { 1110251881Speter zerr = inflateEnd(btn->in); 1111251881Speter SVN_ERR(svn_error__wrap_zlib(zerr, "inflateEnd", btn->in->msg)); 1112251881Speter } 1113251881Speter 1114251881Speter if (btn->out != NULL) 1115251881Speter { 1116251881Speter void *buf; 1117251881Speter apr_size_t write_len; 1118251881Speter 1119251881Speter buf = apr_palloc(btn->pool, ZBUFFER_SIZE); 1120251881Speter 1121251881Speter while (TRUE) 1122251881Speter { 1123251881Speter btn->out->next_out = buf; 1124251881Speter btn->out->avail_out = ZBUFFER_SIZE; 1125251881Speter 1126251881Speter zerr = deflate(btn->out, Z_FINISH); 1127251881Speter if (zerr != Z_STREAM_END && zerr != Z_OK) 1128251881Speter return svn_error_trace(svn_error__wrap_zlib(zerr, "deflate", 1129251881Speter btn->out->msg)); 1130251881Speter write_len = ZBUFFER_SIZE - btn->out->avail_out; 1131251881Speter if (write_len > 0) 1132251881Speter SVN_ERR(btn->write(btn->subbaton, buf, &write_len)); 1133251881Speter if (zerr == Z_STREAM_END) 1134251881Speter break; 1135251881Speter } 1136251881Speter 1137251881Speter zerr = deflateEnd(btn->out); 1138251881Speter SVN_ERR(svn_error__wrap_zlib(zerr, "deflateEnd", btn->out->msg)); 1139251881Speter } 1140251881Speter 1141251881Speter if (btn->close != NULL) 1142251881Speter return svn_error_trace(btn->close(btn->subbaton)); 1143251881Speter else 1144251881Speter return SVN_NO_ERROR; 1145251881Speter} 1146251881Speter 1147251881Speter 1148251881Spetersvn_stream_t * 1149251881Spetersvn_stream_compressed(svn_stream_t *stream, apr_pool_t *pool) 1150251881Speter{ 1151251881Speter struct svn_stream_t *zstream; 1152251881Speter struct zbaton *baton; 1153251881Speter 1154251881Speter assert(stream != NULL); 1155251881Speter 1156251881Speter baton = apr_palloc(pool, sizeof(*baton)); 1157251881Speter baton->in = baton->out = NULL; 1158251881Speter baton->read = stream->read_fn; 1159251881Speter baton->write = stream->write_fn; 1160251881Speter baton->close = stream->close_fn; 1161251881Speter baton->subbaton = stream->baton; 1162251881Speter baton->pool = pool; 1163251881Speter baton->read_buffer = NULL; 1164251881Speter baton->read_flush = Z_SYNC_FLUSH; 1165251881Speter 1166251881Speter zstream = svn_stream_create(baton, pool); 1167251881Speter svn_stream_set_read(zstream, read_handler_gz); 1168251881Speter svn_stream_set_write(zstream, write_handler_gz); 1169251881Speter svn_stream_set_close(zstream, close_handler_gz); 1170251881Speter 1171251881Speter return zstream; 1172251881Speter} 1173251881Speter 1174251881Speter 1175251881Speter/* Checksummed stream support */ 1176251881Speter 1177251881Speterstruct checksum_stream_baton 1178251881Speter{ 1179251881Speter svn_checksum_ctx_t *read_ctx, *write_ctx; 1180251881Speter svn_checksum_t **read_checksum; /* Output value. */ 1181251881Speter svn_checksum_t **write_checksum; /* Output value. */ 1182251881Speter svn_stream_t *proxy; 1183251881Speter 1184251881Speter /* True if more data should be read when closing the stream. */ 1185251881Speter svn_boolean_t read_more; 1186251881Speter 1187251881Speter /* Pool to allocate read buffer and output values from. */ 1188251881Speter apr_pool_t *pool; 1189251881Speter}; 1190251881Speter 1191251881Speterstatic svn_error_t * 1192251881Speterread_handler_checksum(void *baton, char *buffer, apr_size_t *len) 1193251881Speter{ 1194251881Speter struct checksum_stream_baton *btn = baton; 1195251881Speter apr_size_t saved_len = *len; 1196251881Speter 1197251881Speter SVN_ERR(svn_stream_read(btn->proxy, buffer, len)); 1198251881Speter 1199251881Speter if (btn->read_checksum) 1200251881Speter SVN_ERR(svn_checksum_update(btn->read_ctx, buffer, *len)); 1201251881Speter 1202251881Speter if (saved_len != *len) 1203251881Speter btn->read_more = FALSE; 1204251881Speter 1205251881Speter return SVN_NO_ERROR; 1206251881Speter} 1207251881Speter 1208251881Speter 1209251881Speterstatic svn_error_t * 1210251881Speterwrite_handler_checksum(void *baton, const char *buffer, apr_size_t *len) 1211251881Speter{ 1212251881Speter struct checksum_stream_baton *btn = baton; 1213251881Speter 1214251881Speter if (btn->write_checksum && *len > 0) 1215251881Speter SVN_ERR(svn_checksum_update(btn->write_ctx, buffer, *len)); 1216251881Speter 1217251881Speter return svn_error_trace(svn_stream_write(btn->proxy, buffer, len)); 1218251881Speter} 1219251881Speter 1220251881Speter 1221251881Speterstatic svn_error_t * 1222251881Speterclose_handler_checksum(void *baton) 1223251881Speter{ 1224251881Speter struct checksum_stream_baton *btn = baton; 1225251881Speter 1226251881Speter /* If we're supposed to drain the stream, do so before finalizing the 1227251881Speter checksum. */ 1228251881Speter if (btn->read_more) 1229251881Speter { 1230251881Speter char *buf = apr_palloc(btn->pool, SVN__STREAM_CHUNK_SIZE); 1231251881Speter apr_size_t len = SVN__STREAM_CHUNK_SIZE; 1232251881Speter 1233251881Speter do 1234251881Speter { 1235251881Speter SVN_ERR(read_handler_checksum(baton, buf, &len)); 1236251881Speter } 1237251881Speter while (btn->read_more); 1238251881Speter } 1239251881Speter 1240251881Speter if (btn->read_ctx) 1241251881Speter SVN_ERR(svn_checksum_final(btn->read_checksum, btn->read_ctx, btn->pool)); 1242251881Speter 1243251881Speter if (btn->write_ctx) 1244251881Speter SVN_ERR(svn_checksum_final(btn->write_checksum, btn->write_ctx, btn->pool)); 1245251881Speter 1246251881Speter return svn_error_trace(svn_stream_close(btn->proxy)); 1247251881Speter} 1248251881Speter 1249251881Speter 1250251881Spetersvn_stream_t * 1251251881Spetersvn_stream_checksummed2(svn_stream_t *stream, 1252251881Speter svn_checksum_t **read_checksum, 1253251881Speter svn_checksum_t **write_checksum, 1254251881Speter svn_checksum_kind_t checksum_kind, 1255251881Speter svn_boolean_t read_all, 1256251881Speter apr_pool_t *pool) 1257251881Speter{ 1258251881Speter svn_stream_t *s; 1259251881Speter struct checksum_stream_baton *baton; 1260251881Speter 1261251881Speter if (read_checksum == NULL && write_checksum == NULL) 1262251881Speter return stream; 1263251881Speter 1264251881Speter baton = apr_palloc(pool, sizeof(*baton)); 1265251881Speter if (read_checksum) 1266251881Speter baton->read_ctx = svn_checksum_ctx_create(checksum_kind, pool); 1267251881Speter else 1268251881Speter baton->read_ctx = NULL; 1269251881Speter 1270251881Speter if (write_checksum) 1271251881Speter baton->write_ctx = svn_checksum_ctx_create(checksum_kind, pool); 1272251881Speter else 1273251881Speter baton->write_ctx = NULL; 1274251881Speter 1275251881Speter baton->read_checksum = read_checksum; 1276251881Speter baton->write_checksum = write_checksum; 1277251881Speter baton->proxy = stream; 1278251881Speter baton->read_more = read_all; 1279251881Speter baton->pool = pool; 1280251881Speter 1281251881Speter s = svn_stream_create(baton, pool); 1282251881Speter svn_stream_set_read(s, read_handler_checksum); 1283251881Speter svn_stream_set_write(s, write_handler_checksum); 1284251881Speter svn_stream_set_close(s, close_handler_checksum); 1285251881Speter return s; 1286251881Speter} 1287251881Speter 1288251881Speterstruct md5_stream_baton 1289251881Speter{ 1290251881Speter const unsigned char **read_digest; 1291251881Speter const unsigned char **write_digest; 1292251881Speter svn_checksum_t *read_checksum; 1293251881Speter svn_checksum_t *write_checksum; 1294251881Speter svn_stream_t *proxy; 1295251881Speter apr_pool_t *pool; 1296251881Speter}; 1297251881Speter 1298251881Speterstatic svn_error_t * 1299251881Speterread_handler_md5(void *baton, char *buffer, apr_size_t *len) 1300251881Speter{ 1301251881Speter struct md5_stream_baton *btn = baton; 1302251881Speter return svn_error_trace(svn_stream_read(btn->proxy, buffer, len)); 1303251881Speter} 1304251881Speter 1305251881Speterstatic svn_error_t * 1306251881Speterskip_handler_md5(void *baton, apr_size_t len) 1307251881Speter{ 1308251881Speter struct md5_stream_baton *btn = baton; 1309251881Speter return svn_error_trace(svn_stream_skip(btn->proxy, len)); 1310251881Speter} 1311251881Speter 1312251881Speterstatic svn_error_t * 1313251881Speterwrite_handler_md5(void *baton, const char *buffer, apr_size_t *len) 1314251881Speter{ 1315251881Speter struct md5_stream_baton *btn = baton; 1316251881Speter return svn_error_trace(svn_stream_write(btn->proxy, buffer, len)); 1317251881Speter} 1318251881Speter 1319251881Speterstatic svn_error_t * 1320251881Speterclose_handler_md5(void *baton) 1321251881Speter{ 1322251881Speter struct md5_stream_baton *btn = baton; 1323251881Speter 1324251881Speter SVN_ERR(svn_stream_close(btn->proxy)); 1325251881Speter 1326251881Speter if (btn->read_digest) 1327251881Speter *btn->read_digest 1328251881Speter = apr_pmemdup(btn->pool, btn->read_checksum->digest, 1329251881Speter APR_MD5_DIGESTSIZE); 1330251881Speter 1331251881Speter if (btn->write_digest) 1332251881Speter *btn->write_digest 1333251881Speter = apr_pmemdup(btn->pool, btn->write_checksum->digest, 1334251881Speter APR_MD5_DIGESTSIZE); 1335251881Speter 1336251881Speter return SVN_NO_ERROR; 1337251881Speter} 1338251881Speter 1339251881Speter 1340251881Spetersvn_stream_t * 1341251881Spetersvn_stream_checksummed(svn_stream_t *stream, 1342251881Speter const unsigned char **read_digest, 1343251881Speter const unsigned char **write_digest, 1344251881Speter svn_boolean_t read_all, 1345251881Speter apr_pool_t *pool) 1346251881Speter{ 1347251881Speter svn_stream_t *s; 1348251881Speter struct md5_stream_baton *baton; 1349251881Speter 1350251881Speter if (! read_digest && ! write_digest) 1351251881Speter return stream; 1352251881Speter 1353251881Speter baton = apr_palloc(pool, sizeof(*baton)); 1354251881Speter baton->read_digest = read_digest; 1355251881Speter baton->write_digest = write_digest; 1356251881Speter baton->pool = pool; 1357251881Speter 1358251881Speter /* Set BATON->proxy to a stream that will fill in BATON->read_checksum 1359251881Speter * and BATON->write_checksum (if we want them) when it is closed. */ 1360251881Speter baton->proxy 1361251881Speter = svn_stream_checksummed2(stream, 1362251881Speter read_digest ? &baton->read_checksum : NULL, 1363251881Speter write_digest ? &baton->write_checksum : NULL, 1364251881Speter svn_checksum_md5, 1365251881Speter read_all, pool); 1366251881Speter 1367251881Speter /* Create a stream that will forward its read/write/close operations to 1368251881Speter * BATON->proxy and will fill in *READ_DIGEST and *WRITE_DIGEST (if we 1369251881Speter * want them) after it closes BATON->proxy. */ 1370251881Speter s = svn_stream_create(baton, pool); 1371251881Speter svn_stream_set_read(s, read_handler_md5); 1372251881Speter svn_stream_set_skip(s, skip_handler_md5); 1373251881Speter svn_stream_set_write(s, write_handler_md5); 1374251881Speter svn_stream_set_close(s, close_handler_md5); 1375251881Speter return s; 1376251881Speter} 1377251881Speter 1378251881Speter 1379251881Speter 1380251881Speter 1381251881Speter/* Miscellaneous stream functions. */ 1382251881Speterstruct stringbuf_stream_baton 1383251881Speter{ 1384251881Speter svn_stringbuf_t *str; 1385251881Speter apr_size_t amt_read; 1386251881Speter}; 1387251881Speter 1388251881Speter/* svn_stream_mark_t for streams backed by stringbufs. */ 1389251881Speterstruct stringbuf_stream_mark { 1390251881Speter apr_size_t pos; 1391251881Speter}; 1392251881Speter 1393251881Speterstatic svn_error_t * 1394251881Speterread_handler_stringbuf(void *baton, char *buffer, apr_size_t *len) 1395251881Speter{ 1396251881Speter struct stringbuf_stream_baton *btn = baton; 1397251881Speter apr_size_t left_to_read = btn->str->len - btn->amt_read; 1398251881Speter 1399251881Speter *len = (*len > left_to_read) ? left_to_read : *len; 1400251881Speter memcpy(buffer, btn->str->data + btn->amt_read, *len); 1401251881Speter btn->amt_read += *len; 1402251881Speter return SVN_NO_ERROR; 1403251881Speter} 1404251881Speter 1405251881Speterstatic svn_error_t * 1406251881Speterskip_handler_stringbuf(void *baton, apr_size_t len) 1407251881Speter{ 1408251881Speter struct stringbuf_stream_baton *btn = baton; 1409251881Speter apr_size_t left_to_read = btn->str->len - btn->amt_read; 1410251881Speter 1411251881Speter len = (len > left_to_read) ? left_to_read : len; 1412251881Speter btn->amt_read += len; 1413251881Speter return SVN_NO_ERROR; 1414251881Speter} 1415251881Speter 1416251881Speterstatic svn_error_t * 1417251881Speterwrite_handler_stringbuf(void *baton, const char *data, apr_size_t *len) 1418251881Speter{ 1419251881Speter struct stringbuf_stream_baton *btn = baton; 1420251881Speter 1421251881Speter svn_stringbuf_appendbytes(btn->str, data, *len); 1422251881Speter return SVN_NO_ERROR; 1423251881Speter} 1424251881Speter 1425251881Speterstatic svn_error_t * 1426251881Spetermark_handler_stringbuf(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 1427251881Speter{ 1428251881Speter struct stringbuf_stream_baton *btn; 1429251881Speter struct stringbuf_stream_mark *stringbuf_stream_mark; 1430251881Speter 1431251881Speter btn = baton; 1432251881Speter 1433251881Speter stringbuf_stream_mark = apr_palloc(pool, sizeof(*stringbuf_stream_mark)); 1434251881Speter stringbuf_stream_mark->pos = btn->amt_read; 1435251881Speter *mark = (svn_stream_mark_t *)stringbuf_stream_mark; 1436251881Speter return SVN_NO_ERROR; 1437251881Speter} 1438251881Speter 1439251881Speterstatic svn_error_t * 1440251881Speterseek_handler_stringbuf(void *baton, const svn_stream_mark_t *mark) 1441251881Speter{ 1442251881Speter struct stringbuf_stream_baton *btn = baton; 1443251881Speter 1444251881Speter if (mark != NULL) 1445251881Speter { 1446251881Speter const struct stringbuf_stream_mark *stringbuf_stream_mark; 1447251881Speter 1448251881Speter stringbuf_stream_mark = (const struct stringbuf_stream_mark *)mark; 1449251881Speter btn->amt_read = stringbuf_stream_mark->pos; 1450251881Speter } 1451251881Speter else 1452251881Speter btn->amt_read = 0; 1453251881Speter 1454251881Speter return SVN_NO_ERROR; 1455251881Speter} 1456251881Speter 1457251881Speterstatic svn_boolean_t 1458251881Speteris_buffered_handler_stringbuf(void *baton) 1459251881Speter{ 1460251881Speter return TRUE; 1461251881Speter} 1462251881Speter 1463251881Spetersvn_stream_t * 1464251881Spetersvn_stream_from_stringbuf(svn_stringbuf_t *str, 1465251881Speter apr_pool_t *pool) 1466251881Speter{ 1467251881Speter svn_stream_t *stream; 1468251881Speter struct stringbuf_stream_baton *baton; 1469251881Speter 1470251881Speter if (! str) 1471251881Speter return svn_stream_empty(pool); 1472251881Speter 1473251881Speter baton = apr_palloc(pool, sizeof(*baton)); 1474251881Speter baton->str = str; 1475251881Speter baton->amt_read = 0; 1476251881Speter stream = svn_stream_create(baton, pool); 1477251881Speter svn_stream_set_read(stream, read_handler_stringbuf); 1478251881Speter svn_stream_set_skip(stream, skip_handler_stringbuf); 1479251881Speter svn_stream_set_write(stream, write_handler_stringbuf); 1480251881Speter svn_stream_set_mark(stream, mark_handler_stringbuf); 1481251881Speter svn_stream_set_seek(stream, seek_handler_stringbuf); 1482251881Speter svn_stream__set_is_buffered(stream, is_buffered_handler_stringbuf); 1483251881Speter return stream; 1484251881Speter} 1485251881Speter 1486251881Speterstruct string_stream_baton 1487251881Speter{ 1488251881Speter const svn_string_t *str; 1489251881Speter apr_size_t amt_read; 1490251881Speter}; 1491251881Speter 1492251881Speter/* svn_stream_mark_t for streams backed by stringbufs. */ 1493251881Speterstruct string_stream_mark { 1494251881Speter apr_size_t pos; 1495251881Speter}; 1496251881Speter 1497251881Speterstatic svn_error_t * 1498251881Speterread_handler_string(void *baton, char *buffer, apr_size_t *len) 1499251881Speter{ 1500251881Speter struct string_stream_baton *btn = baton; 1501251881Speter apr_size_t left_to_read = btn->str->len - btn->amt_read; 1502251881Speter 1503251881Speter *len = (*len > left_to_read) ? left_to_read : *len; 1504251881Speter memcpy(buffer, btn->str->data + btn->amt_read, *len); 1505251881Speter btn->amt_read += *len; 1506251881Speter return SVN_NO_ERROR; 1507251881Speter} 1508251881Speter 1509251881Speterstatic svn_error_t * 1510251881Spetermark_handler_string(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 1511251881Speter{ 1512251881Speter struct string_stream_baton *btn; 1513251881Speter struct string_stream_mark *marker; 1514251881Speter 1515251881Speter btn = baton; 1516251881Speter 1517251881Speter marker = apr_palloc(pool, sizeof(*marker)); 1518251881Speter marker->pos = btn->amt_read; 1519251881Speter *mark = (svn_stream_mark_t *)marker; 1520251881Speter return SVN_NO_ERROR; 1521251881Speter} 1522251881Speter 1523251881Speterstatic svn_error_t * 1524251881Speterseek_handler_string(void *baton, const svn_stream_mark_t *mark) 1525251881Speter{ 1526251881Speter struct string_stream_baton *btn = baton; 1527251881Speter 1528251881Speter if (mark != NULL) 1529251881Speter { 1530251881Speter const struct string_stream_mark *marker; 1531251881Speter 1532251881Speter marker = (const struct string_stream_mark *)mark; 1533251881Speter btn->amt_read = marker->pos; 1534251881Speter } 1535251881Speter else 1536251881Speter btn->amt_read = 0; 1537251881Speter 1538251881Speter return SVN_NO_ERROR; 1539251881Speter} 1540251881Speter 1541251881Speterstatic svn_error_t * 1542251881Speterskip_handler_string(void *baton, apr_size_t len) 1543251881Speter{ 1544251881Speter struct string_stream_baton *btn = baton; 1545251881Speter apr_size_t left_to_read = btn->str->len - btn->amt_read; 1546251881Speter 1547251881Speter len = (len > left_to_read) ? left_to_read : len; 1548251881Speter btn->amt_read += len; 1549251881Speter return SVN_NO_ERROR; 1550251881Speter} 1551251881Speter 1552251881Speterstatic svn_boolean_t 1553251881Speteris_buffered_handler_string(void *baton) 1554251881Speter{ 1555251881Speter return TRUE; 1556251881Speter} 1557251881Speter 1558251881Spetersvn_stream_t * 1559251881Spetersvn_stream_from_string(const svn_string_t *str, 1560251881Speter apr_pool_t *pool) 1561251881Speter{ 1562251881Speter svn_stream_t *stream; 1563251881Speter struct string_stream_baton *baton; 1564251881Speter 1565251881Speter if (! str) 1566251881Speter return svn_stream_empty(pool); 1567251881Speter 1568251881Speter baton = apr_palloc(pool, sizeof(*baton)); 1569251881Speter baton->str = str; 1570251881Speter baton->amt_read = 0; 1571251881Speter stream = svn_stream_create(baton, pool); 1572251881Speter svn_stream_set_read(stream, read_handler_string); 1573251881Speter svn_stream_set_mark(stream, mark_handler_string); 1574251881Speter svn_stream_set_seek(stream, seek_handler_string); 1575251881Speter svn_stream_set_skip(stream, skip_handler_string); 1576251881Speter svn_stream__set_is_buffered(stream, is_buffered_handler_string); 1577251881Speter return stream; 1578251881Speter} 1579251881Speter 1580251881Speter 1581251881Spetersvn_error_t * 1582251881Spetersvn_stream_for_stdin(svn_stream_t **in, apr_pool_t *pool) 1583251881Speter{ 1584251881Speter apr_file_t *stdin_file; 1585251881Speter apr_status_t apr_err; 1586251881Speter 1587251881Speter apr_err = apr_file_open_stdin(&stdin_file, pool); 1588251881Speter if (apr_err) 1589251881Speter return svn_error_wrap_apr(apr_err, "Can't open stdin"); 1590251881Speter 1591251881Speter *in = svn_stream_from_aprfile2(stdin_file, TRUE, pool); 1592251881Speter 1593251881Speter return SVN_NO_ERROR; 1594251881Speter} 1595251881Speter 1596251881Speter 1597251881Spetersvn_error_t * 1598251881Spetersvn_stream_for_stdout(svn_stream_t **out, apr_pool_t *pool) 1599251881Speter{ 1600251881Speter apr_file_t *stdout_file; 1601251881Speter apr_status_t apr_err; 1602251881Speter 1603251881Speter apr_err = apr_file_open_stdout(&stdout_file, pool); 1604251881Speter if (apr_err) 1605251881Speter return svn_error_wrap_apr(apr_err, "Can't open stdout"); 1606251881Speter 1607251881Speter *out = svn_stream_from_aprfile2(stdout_file, TRUE, pool); 1608251881Speter 1609251881Speter return SVN_NO_ERROR; 1610251881Speter} 1611251881Speter 1612251881Speter 1613251881Spetersvn_error_t * 1614251881Spetersvn_stream_for_stderr(svn_stream_t **err, apr_pool_t *pool) 1615251881Speter{ 1616251881Speter apr_file_t *stderr_file; 1617251881Speter apr_status_t apr_err; 1618251881Speter 1619251881Speter apr_err = apr_file_open_stderr(&stderr_file, pool); 1620251881Speter if (apr_err) 1621251881Speter return svn_error_wrap_apr(apr_err, "Can't open stderr"); 1622251881Speter 1623251881Speter *err = svn_stream_from_aprfile2(stderr_file, TRUE, pool); 1624251881Speter 1625251881Speter return SVN_NO_ERROR; 1626251881Speter} 1627251881Speter 1628251881Speter 1629251881Spetersvn_error_t * 1630251881Spetersvn_string_from_stream(svn_string_t **result, 1631251881Speter svn_stream_t *stream, 1632251881Speter apr_pool_t *result_pool, 1633251881Speter apr_pool_t *scratch_pool) 1634251881Speter{ 1635251881Speter svn_stringbuf_t *work = svn_stringbuf_create_ensure(SVN__STREAM_CHUNK_SIZE, 1636251881Speter result_pool); 1637251881Speter char *buffer = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE); 1638251881Speter 1639251881Speter while (1) 1640251881Speter { 1641251881Speter apr_size_t len = SVN__STREAM_CHUNK_SIZE; 1642251881Speter 1643251881Speter SVN_ERR(svn_stream_read(stream, buffer, &len)); 1644251881Speter svn_stringbuf_appendbytes(work, buffer, len); 1645251881Speter 1646251881Speter if (len < SVN__STREAM_CHUNK_SIZE) 1647251881Speter break; 1648251881Speter } 1649251881Speter 1650251881Speter SVN_ERR(svn_stream_close(stream)); 1651251881Speter 1652251881Speter *result = apr_palloc(result_pool, sizeof(**result)); 1653251881Speter (*result)->data = work->data; 1654251881Speter (*result)->len = work->len; 1655251881Speter 1656251881Speter return SVN_NO_ERROR; 1657251881Speter} 1658251881Speter 1659251881Speter 1660251881Speter/* These are somewhat arbirary, if we ever get good empirical data as to 1661251881Speter actually valid values, feel free to update them. */ 1662251881Speter#define BUFFER_BLOCK_SIZE 1024 1663251881Speter#define BUFFER_MAX_SIZE 100000 1664251881Speter 1665251881Spetersvn_stream_t * 1666251881Spetersvn_stream_buffered(apr_pool_t *result_pool) 1667251881Speter{ 1668251881Speter return svn_stream__from_spillbuf(BUFFER_BLOCK_SIZE, BUFFER_MAX_SIZE, 1669251881Speter result_pool); 1670251881Speter} 1671251881Speter 1672251881Speter 1673251881Speter 1674251881Speter/*** Lazyopen Streams ***/ 1675251881Speter 1676251881Speter/* Custom baton for lazyopen-style wrapper streams. */ 1677251881Spetertypedef struct lazyopen_baton_t { 1678251881Speter 1679251881Speter /* Callback function and baton for opening the wrapped stream. */ 1680251881Speter svn_stream_lazyopen_func_t open_func; 1681251881Speter void *open_baton; 1682251881Speter 1683251881Speter /* The wrapped stream, or NULL if the stream hasn't yet been 1684251881Speter opened. */ 1685251881Speter svn_stream_t *real_stream; 1686251881Speter apr_pool_t *pool; 1687251881Speter 1688251881Speter /* Whether to open the wrapped stream on a close call. */ 1689251881Speter svn_boolean_t open_on_close; 1690251881Speter 1691251881Speter} lazyopen_baton_t; 1692251881Speter 1693251881Speter 1694251881Speter/* Use B->open_func/baton to create and set B->real_stream iff it 1695251881Speter isn't already set. */ 1696251881Speterstatic svn_error_t * 1697251881Speterlazyopen_if_unopened(lazyopen_baton_t *b) 1698251881Speter{ 1699251881Speter if (b->real_stream == NULL) 1700251881Speter { 1701251881Speter svn_stream_t *stream; 1702251881Speter apr_pool_t *scratch_pool = svn_pool_create(b->pool); 1703251881Speter 1704251881Speter SVN_ERR(b->open_func(&stream, b->open_baton, 1705251881Speter b->pool, scratch_pool)); 1706251881Speter 1707251881Speter svn_pool_destroy(scratch_pool); 1708251881Speter 1709251881Speter b->real_stream = stream; 1710251881Speter } 1711251881Speter 1712251881Speter return SVN_NO_ERROR; 1713251881Speter} 1714251881Speter 1715251881Speter/* Implements svn_read_fn_t */ 1716251881Speterstatic svn_error_t * 1717251881Speterread_handler_lazyopen(void *baton, 1718251881Speter char *buffer, 1719251881Speter apr_size_t *len) 1720251881Speter{ 1721251881Speter lazyopen_baton_t *b = baton; 1722251881Speter 1723251881Speter SVN_ERR(lazyopen_if_unopened(b)); 1724251881Speter SVN_ERR(svn_stream_read(b->real_stream, buffer, len)); 1725251881Speter 1726251881Speter return SVN_NO_ERROR; 1727251881Speter} 1728251881Speter 1729251881Speter/* Implements svn_stream_skip_fn_t */ 1730251881Speterstatic svn_error_t * 1731251881Speterskip_handler_lazyopen(void *baton, 1732251881Speter apr_size_t len) 1733251881Speter{ 1734251881Speter lazyopen_baton_t *b = baton; 1735251881Speter 1736251881Speter SVN_ERR(lazyopen_if_unopened(b)); 1737251881Speter SVN_ERR(svn_stream_skip(b->real_stream, len)); 1738251881Speter 1739251881Speter return SVN_NO_ERROR; 1740251881Speter} 1741251881Speter 1742251881Speter/* Implements svn_write_fn_t */ 1743251881Speterstatic svn_error_t * 1744251881Speterwrite_handler_lazyopen(void *baton, 1745251881Speter const char *data, 1746251881Speter apr_size_t *len) 1747251881Speter{ 1748251881Speter lazyopen_baton_t *b = baton; 1749251881Speter 1750251881Speter SVN_ERR(lazyopen_if_unopened(b)); 1751251881Speter SVN_ERR(svn_stream_write(b->real_stream, data, len)); 1752251881Speter 1753251881Speter return SVN_NO_ERROR; 1754251881Speter} 1755251881Speter 1756251881Speter/* Implements svn_close_fn_t */ 1757251881Speterstatic svn_error_t * 1758251881Speterclose_handler_lazyopen(void *baton) 1759251881Speter{ 1760251881Speter lazyopen_baton_t *b = baton; 1761251881Speter 1762251881Speter if (b->open_on_close) 1763251881Speter SVN_ERR(lazyopen_if_unopened(b)); 1764251881Speter if (b->real_stream) 1765251881Speter SVN_ERR(svn_stream_close(b->real_stream)); 1766251881Speter 1767251881Speter return SVN_NO_ERROR; 1768251881Speter} 1769251881Speter 1770251881Speter/* Implements svn_stream_mark_fn_t */ 1771251881Speterstatic svn_error_t * 1772251881Spetermark_handler_lazyopen(void *baton, 1773251881Speter svn_stream_mark_t **mark, 1774251881Speter apr_pool_t *pool) 1775251881Speter{ 1776251881Speter lazyopen_baton_t *b = baton; 1777251881Speter 1778251881Speter SVN_ERR(lazyopen_if_unopened(b)); 1779251881Speter SVN_ERR(svn_stream_mark(b->real_stream, mark, pool)); 1780251881Speter 1781251881Speter return SVN_NO_ERROR; 1782251881Speter} 1783251881Speter 1784251881Speter/* Implements svn_stream_seek_fn_t */ 1785251881Speterstatic svn_error_t * 1786251881Speterseek_handler_lazyopen(void *baton, 1787251881Speter const svn_stream_mark_t *mark) 1788251881Speter{ 1789251881Speter lazyopen_baton_t *b = baton; 1790251881Speter 1791251881Speter SVN_ERR(lazyopen_if_unopened(b)); 1792251881Speter SVN_ERR(svn_stream_seek(b->real_stream, mark)); 1793251881Speter 1794251881Speter return SVN_NO_ERROR; 1795251881Speter} 1796251881Speter 1797251881Speter/* Implements svn_stream__is_buffered_fn_t */ 1798251881Speterstatic svn_boolean_t 1799251881Speteris_buffered_lazyopen(void *baton) 1800251881Speter{ 1801251881Speter lazyopen_baton_t *b = baton; 1802251881Speter 1803251881Speter /* No lazy open as we cannot handle an open error. */ 1804251881Speter if (!b->real_stream) 1805251881Speter return FALSE; 1806251881Speter 1807251881Speter return svn_stream__is_buffered(b->real_stream); 1808251881Speter} 1809251881Speter 1810251881Spetersvn_stream_t * 1811251881Spetersvn_stream_lazyopen_create(svn_stream_lazyopen_func_t open_func, 1812251881Speter void *open_baton, 1813251881Speter svn_boolean_t open_on_close, 1814251881Speter apr_pool_t *result_pool) 1815251881Speter{ 1816251881Speter lazyopen_baton_t *lob = apr_pcalloc(result_pool, sizeof(*lob)); 1817251881Speter svn_stream_t *stream; 1818251881Speter 1819251881Speter lob->open_func = open_func; 1820251881Speter lob->open_baton = open_baton; 1821251881Speter lob->real_stream = NULL; 1822251881Speter lob->pool = result_pool; 1823251881Speter lob->open_on_close = open_on_close; 1824251881Speter 1825251881Speter stream = svn_stream_create(lob, result_pool); 1826251881Speter svn_stream_set_read(stream, read_handler_lazyopen); 1827251881Speter svn_stream_set_skip(stream, skip_handler_lazyopen); 1828251881Speter svn_stream_set_write(stream, write_handler_lazyopen); 1829251881Speter svn_stream_set_close(stream, close_handler_lazyopen); 1830251881Speter svn_stream_set_mark(stream, mark_handler_lazyopen); 1831251881Speter svn_stream_set_seek(stream, seek_handler_lazyopen); 1832251881Speter svn_stream__set_is_buffered(stream, is_buffered_lazyopen); 1833251881Speter 1834251881Speter return stream; 1835251881Speter} 1836