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> 32299742Sdim#include <apr_poll.h> 33299742Sdim#include <apr_portable.h> 34251881Speter 35251881Speter#include <zlib.h> 36251881Speter 37251881Speter#include "svn_pools.h" 38251881Speter#include "svn_io.h" 39251881Speter#include "svn_error.h" 40251881Speter#include "svn_string.h" 41251881Speter#include "svn_utf.h" 42251881Speter#include "svn_checksum.h" 43251881Speter#include "svn_path.h" 44251881Speter#include "svn_private_config.h" 45299742Sdim#include "private/svn_atomic.h" 46251881Speter#include "private/svn_error_private.h" 47251881Speter#include "private/svn_eol_private.h" 48251881Speter#include "private/svn_io_private.h" 49251881Speter#include "private/svn_subr_private.h" 50299742Sdim#include "private/svn_utf_private.h" 51251881Speter 52251881Speter 53251881Speterstruct svn_stream_t { 54251881Speter void *baton; 55251881Speter svn_read_fn_t read_fn; 56299742Sdim svn_read_fn_t read_full_fn; 57251881Speter svn_stream_skip_fn_t skip_fn; 58251881Speter svn_write_fn_t write_fn; 59251881Speter svn_close_fn_t close_fn; 60251881Speter svn_stream_mark_fn_t mark_fn; 61251881Speter svn_stream_seek_fn_t seek_fn; 62299742Sdim svn_stream_data_available_fn_t data_available_fn; 63251881Speter svn_stream__is_buffered_fn_t is_buffered_fn; 64253734Speter apr_file_t *file; /* Maybe NULL */ 65251881Speter}; 66251881Speter 67251881Speter 68251881Speter/*** Forward declarations. ***/ 69251881Speter 70251881Speterstatic svn_error_t * 71299742Sdimskip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_full_fn); 72251881Speter 73251881Speter 74251881Speter/*** Generic streams. ***/ 75251881Speter 76251881Spetersvn_stream_t * 77251881Spetersvn_stream_create(void *baton, apr_pool_t *pool) 78251881Speter{ 79251881Speter svn_stream_t *stream; 80251881Speter 81299742Sdim stream = apr_pcalloc(pool, sizeof(*stream)); 82251881Speter stream->baton = baton; 83251881Speter return stream; 84251881Speter} 85251881Speter 86251881Speter 87251881Spetervoid 88251881Spetersvn_stream_set_baton(svn_stream_t *stream, void *baton) 89251881Speter{ 90251881Speter stream->baton = baton; 91251881Speter} 92251881Speter 93251881Speter 94251881Spetervoid 95299742Sdimsvn_stream_set_read2(svn_stream_t *stream, 96299742Sdim svn_read_fn_t read_fn, 97299742Sdim svn_read_fn_t read_full_fn) 98251881Speter{ 99251881Speter stream->read_fn = read_fn; 100299742Sdim stream->read_full_fn = read_full_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 134299742Sdimsvn_stream_set_data_available(svn_stream_t *stream, 135299742Sdim svn_stream_data_available_fn_t data_available_fn) 136299742Sdim{ 137299742Sdim stream->data_available_fn = data_available_fn; 138299742Sdim} 139299742Sdim 140299742Sdimvoid 141251881Spetersvn_stream__set_is_buffered(svn_stream_t *stream, 142251881Speter svn_stream__is_buffered_fn_t is_buffered_fn) 143251881Speter{ 144251881Speter stream->is_buffered_fn = is_buffered_fn; 145251881Speter} 146251881Speter 147299742Sdim/* Standard implementation for svn_stream_read_full() based on 148299742Sdim multiple svn_stream_read2() calls (in separate function to make 149299742Sdim it more likely for svn_stream_read_full to be inlined) */ 150299742Sdimstatic svn_error_t * 151299742Sdimfull_read_fallback(svn_stream_t *stream, char *buffer, apr_size_t *len) 152299742Sdim{ 153299742Sdim apr_size_t remaining = *len; 154299742Sdim while (remaining > 0) 155299742Sdim { 156299742Sdim apr_size_t length = remaining; 157299742Sdim SVN_ERR(svn_stream_read2(stream, buffer, &length)); 158299742Sdim 159299742Sdim if (length == 0) 160299742Sdim { 161299742Sdim *len -= remaining; 162299742Sdim return SVN_NO_ERROR; 163299742Sdim } 164299742Sdim 165299742Sdim remaining -= length; 166299742Sdim buffer += length; 167299742Sdim } 168299742Sdim 169299742Sdim return SVN_NO_ERROR; 170299742Sdim} 171299742Sdim 172299742Sdimsvn_boolean_t 173299742Sdimsvn_stream_supports_partial_read(svn_stream_t *stream) 174299742Sdim{ 175299742Sdim return stream->read_fn != NULL; 176299742Sdim} 177299742Sdim 178251881Spetersvn_error_t * 179299742Sdimsvn_stream_read2(svn_stream_t *stream, char *buffer, apr_size_t *len) 180251881Speter{ 181299742Sdim if (stream->read_fn == NULL) 182299742Sdim return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, NULL, NULL); 183299742Sdim 184251881Speter return svn_error_trace(stream->read_fn(stream->baton, buffer, len)); 185251881Speter} 186251881Speter 187299742Sdimsvn_error_t * 188299742Sdimsvn_stream_read_full(svn_stream_t *stream, char *buffer, apr_size_t *len) 189299742Sdim{ 190299742Sdim if (stream->read_full_fn == NULL) 191299742Sdim return svn_error_trace(full_read_fallback(stream, buffer, len)); 192251881Speter 193299742Sdim return svn_error_trace(stream->read_full_fn(stream->baton, buffer, len)); 194299742Sdim} 195299742Sdim 196251881Spetersvn_error_t * 197251881Spetersvn_stream_skip(svn_stream_t *stream, apr_size_t len) 198251881Speter{ 199251881Speter if (stream->skip_fn == NULL) 200251881Speter return svn_error_trace( 201299742Sdim skip_default_handler(stream->baton, len, stream->read_full_fn)); 202251881Speter 203251881Speter return svn_error_trace(stream->skip_fn(stream->baton, len)); 204251881Speter} 205251881Speter 206251881Speter 207251881Spetersvn_error_t * 208251881Spetersvn_stream_write(svn_stream_t *stream, const char *data, apr_size_t *len) 209251881Speter{ 210299742Sdim if (stream->write_fn == NULL) 211299742Sdim return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, NULL, NULL); 212299742Sdim 213251881Speter return svn_error_trace(stream->write_fn(stream->baton, data, len)); 214251881Speter} 215251881Speter 216251881Speter 217251881Spetersvn_error_t * 218251881Spetersvn_stream_reset(svn_stream_t *stream) 219251881Speter{ 220251881Speter return svn_error_trace( 221251881Speter svn_stream_seek(stream, NULL)); 222251881Speter} 223251881Speter 224251881Spetersvn_boolean_t 225251881Spetersvn_stream_supports_mark(svn_stream_t *stream) 226251881Speter{ 227251881Speter return stream->mark_fn != NULL; 228251881Speter} 229251881Speter 230251881Spetersvn_error_t * 231251881Spetersvn_stream_mark(svn_stream_t *stream, svn_stream_mark_t **mark, 232251881Speter apr_pool_t *pool) 233251881Speter{ 234251881Speter if (stream->mark_fn == NULL) 235251881Speter return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL); 236251881Speter 237251881Speter return svn_error_trace(stream->mark_fn(stream->baton, mark, pool)); 238251881Speter} 239251881Speter 240251881Spetersvn_error_t * 241251881Spetersvn_stream_seek(svn_stream_t *stream, const svn_stream_mark_t *mark) 242251881Speter{ 243251881Speter if (stream->seek_fn == NULL) 244251881Speter return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL); 245251881Speter 246251881Speter return svn_error_trace(stream->seek_fn(stream->baton, mark)); 247251881Speter} 248251881Speter 249299742Sdimsvn_error_t * 250299742Sdimsvn_stream_data_available(svn_stream_t *stream, 251299742Sdim svn_boolean_t *data_available) 252299742Sdim{ 253299742Sdim if (stream->data_available_fn == NULL) 254299742Sdim return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, NULL, NULL); 255299742Sdim 256299742Sdim return svn_error_trace(stream->data_available_fn(stream->baton, 257299742Sdim data_available)); 258299742Sdim} 259299742Sdim 260251881Spetersvn_boolean_t 261251881Spetersvn_stream__is_buffered(svn_stream_t *stream) 262251881Speter{ 263251881Speter if (stream->is_buffered_fn == NULL) 264251881Speter return FALSE; 265251881Speter 266251881Speter return stream->is_buffered_fn(stream->baton); 267251881Speter} 268251881Speter 269251881Spetersvn_error_t * 270251881Spetersvn_stream_close(svn_stream_t *stream) 271251881Speter{ 272251881Speter if (stream->close_fn == NULL) 273251881Speter return SVN_NO_ERROR; 274251881Speter return svn_error_trace(stream->close_fn(stream->baton)); 275251881Speter} 276251881Speter 277251881Spetersvn_error_t * 278251881Spetersvn_stream_puts(svn_stream_t *stream, 279251881Speter const char *str) 280251881Speter{ 281251881Speter apr_size_t len; 282251881Speter len = strlen(str); 283251881Speter return svn_error_trace(svn_stream_write(stream, str, &len)); 284251881Speter} 285251881Speter 286251881Spetersvn_error_t * 287251881Spetersvn_stream_printf(svn_stream_t *stream, 288251881Speter apr_pool_t *pool, 289251881Speter const char *fmt, 290251881Speter ...) 291251881Speter{ 292251881Speter const char *message; 293251881Speter va_list ap; 294251881Speter 295251881Speter va_start(ap, fmt); 296251881Speter message = apr_pvsprintf(pool, fmt, ap); 297251881Speter va_end(ap); 298251881Speter 299251881Speter return svn_error_trace(svn_stream_puts(stream, message)); 300251881Speter} 301251881Speter 302251881Speter 303251881Spetersvn_error_t * 304251881Spetersvn_stream_printf_from_utf8(svn_stream_t *stream, 305251881Speter const char *encoding, 306251881Speter apr_pool_t *pool, 307251881Speter const char *fmt, 308251881Speter ...) 309251881Speter{ 310251881Speter const char *message, *translated; 311251881Speter va_list ap; 312251881Speter 313251881Speter va_start(ap, fmt); 314251881Speter message = apr_pvsprintf(pool, fmt, ap); 315251881Speter va_end(ap); 316251881Speter 317251881Speter SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated, message, encoding, 318251881Speter pool)); 319251881Speter 320251881Speter return svn_error_trace(svn_stream_puts(stream, translated)); 321251881Speter} 322251881Speter 323251881Speter/* Guts of svn_stream_readline(). 324251881Speter * Returns the line read from STREAM in *STRINGBUF, and indicates 325251881Speter * end-of-file in *EOF. If DETECT_EOL is TRUE, the end-of-line indicator 326251881Speter * is detected automatically and returned in *EOL. 327251881Speter * If DETECT_EOL is FALSE, *EOL must point to the desired end-of-line 328251881Speter * indicator. STRINGBUF is allocated in POOL. */ 329251881Speterstatic svn_error_t * 330251881Speterstream_readline_bytewise(svn_stringbuf_t **stringbuf, 331251881Speter svn_boolean_t *eof, 332251881Speter const char *eol, 333251881Speter svn_stream_t *stream, 334251881Speter apr_pool_t *pool) 335251881Speter{ 336251881Speter svn_stringbuf_t *str; 337251881Speter apr_size_t numbytes; 338251881Speter const char *match; 339251881Speter char c; 340251881Speter 341251881Speter /* Since we're reading one character at a time, let's at least 342251881Speter optimize for the 90% case. 90% of the time, we can avoid the 343251881Speter stringbuf ever having to realloc() itself if we start it out at 344251881Speter 80 chars. */ 345299742Sdim str = svn_stringbuf_create_ensure(SVN__LINE_CHUNK_SIZE, pool); 346251881Speter 347251881Speter /* Read into STR up to and including the next EOL sequence. */ 348251881Speter match = eol; 349251881Speter while (*match) 350251881Speter { 351251881Speter numbytes = 1; 352299742Sdim SVN_ERR(svn_stream_read_full(stream, &c, &numbytes)); 353251881Speter if (numbytes != 1) 354251881Speter { 355251881Speter /* a 'short' read means the stream has run out. */ 356251881Speter *eof = TRUE; 357251881Speter *stringbuf = str; 358251881Speter return SVN_NO_ERROR; 359251881Speter } 360251881Speter 361251881Speter if (c == *match) 362251881Speter match++; 363251881Speter else 364251881Speter match = eol; 365251881Speter 366251881Speter svn_stringbuf_appendbyte(str, c); 367251881Speter } 368251881Speter 369251881Speter *eof = FALSE; 370251881Speter svn_stringbuf_chop(str, match - eol); 371251881Speter *stringbuf = str; 372251881Speter 373251881Speter return SVN_NO_ERROR; 374251881Speter} 375251881Speter 376251881Speterstatic svn_error_t * 377251881Speterstream_readline_chunky(svn_stringbuf_t **stringbuf, 378251881Speter svn_boolean_t *eof, 379251881Speter const char *eol, 380251881Speter svn_stream_t *stream, 381251881Speter apr_pool_t *pool) 382251881Speter{ 383251881Speter /* Read larger chunks of data at once into this buffer and scan 384251881Speter * that for EOL. A good chunk size should be about 80 chars since 385251881Speter * most text lines will be shorter. However, don't use a much 386251881Speter * larger value because filling the buffer from the stream takes 387251881Speter * time as well. 388251881Speter */ 389299742Sdim char buffer[SVN__LINE_CHUNK_SIZE+1]; 390251881Speter 391251881Speter /* variables */ 392251881Speter svn_stream_mark_t *mark; 393251881Speter apr_size_t numbytes; 394251881Speter const char *eol_pos; 395251881Speter apr_size_t total_parsed = 0; 396251881Speter 397251881Speter /* invariant for this call */ 398251881Speter const size_t eol_len = strlen(eol); 399251881Speter 400251881Speter /* Remember the line start so this plus the line length will be 401251881Speter * the position to move to at the end of this function. 402251881Speter */ 403251881Speter SVN_ERR(svn_stream_mark(stream, &mark, pool)); 404251881Speter 405251881Speter /* Read the first chunk. */ 406299742Sdim numbytes = SVN__LINE_CHUNK_SIZE; 407299742Sdim SVN_ERR(svn_stream_read_full(stream, buffer, &numbytes)); 408251881Speter buffer[numbytes] = '\0'; 409251881Speter 410251881Speter /* Look for the EOL in this first chunk. If we find it, we are done here. 411251881Speter */ 412251881Speter eol_pos = strstr(buffer, eol); 413251881Speter if (eol_pos != NULL) 414251881Speter { 415251881Speter *stringbuf = svn_stringbuf_ncreate(buffer, eol_pos - buffer, pool); 416251881Speter total_parsed = eol_pos - buffer + eol_len; 417251881Speter } 418299742Sdim else if (numbytes < SVN__LINE_CHUNK_SIZE) 419251881Speter { 420251881Speter /* We hit EOF but not EOL. 421251881Speter */ 422251881Speter *stringbuf = svn_stringbuf_ncreate(buffer, numbytes, pool); 423251881Speter *eof = TRUE; 424251881Speter return SVN_NO_ERROR; 425251881Speter } 426251881Speter else 427251881Speter { 428251881Speter /* A larger buffer for the string is needed. */ 429251881Speter svn_stringbuf_t *str; 430299742Sdim str = svn_stringbuf_create_ensure(2*SVN__LINE_CHUNK_SIZE, pool); 431251881Speter svn_stringbuf_appendbytes(str, buffer, numbytes); 432251881Speter *stringbuf = str; 433251881Speter 434251881Speter /* Loop reading chunks until an EOL was found. If we hit EOF, fall 435251881Speter * back to the standard implementation. */ 436251881Speter do 437251881Speter { 438251881Speter /* Append the next chunk to the string read so far. 439251881Speter */ 440299742Sdim svn_stringbuf_ensure(str, str->len + SVN__LINE_CHUNK_SIZE); 441299742Sdim numbytes = SVN__LINE_CHUNK_SIZE; 442299742Sdim SVN_ERR(svn_stream_read_full(stream, str->data + str->len, &numbytes)); 443251881Speter str->len += numbytes; 444251881Speter str->data[str->len] = '\0'; 445251881Speter 446251881Speter /* Look for the EOL in the new data plus the last part of the 447251881Speter * previous chunk because the EOL may span over the boundary 448251881Speter * between both chunks. 449251881Speter */ 450251881Speter eol_pos = strstr(str->data + str->len - numbytes - (eol_len-1), eol); 451251881Speter 452299742Sdim if ((numbytes < SVN__LINE_CHUNK_SIZE) && (eol_pos == NULL)) 453251881Speter { 454251881Speter /* We hit EOF instead of EOL. */ 455251881Speter *eof = TRUE; 456251881Speter return SVN_NO_ERROR; 457251881Speter } 458251881Speter } 459251881Speter while (eol_pos == NULL); 460251881Speter 461251881Speter /* Number of bytes we actually consumed (i.e. line + EOF). 462251881Speter * We need to "return" the rest to the stream by moving its 463251881Speter * read pointer. 464251881Speter */ 465251881Speter total_parsed = eol_pos - str->data + eol_len; 466251881Speter 467251881Speter /* Terminate the string at the EOL postion and return it. */ 468251881Speter str->len = eol_pos - str->data; 469251881Speter str->data[str->len] = 0; 470251881Speter } 471251881Speter 472251881Speter /* Move the stream read pointer to the first position behind the EOL. 473251881Speter */ 474251881Speter SVN_ERR(svn_stream_seek(stream, mark)); 475251881Speter return svn_error_trace(svn_stream_skip(stream, total_parsed)); 476251881Speter} 477251881Speter 478251881Speter/* Guts of svn_stream_readline(). 479251881Speter * Returns the line read from STREAM in *STRINGBUF, and indicates 480251881Speter * end-of-file in *EOF. EOL must point to the desired end-of-line 481251881Speter * indicator. STRINGBUF is allocated in POOL. */ 482251881Speterstatic svn_error_t * 483251881Speterstream_readline(svn_stringbuf_t **stringbuf, 484251881Speter svn_boolean_t *eof, 485251881Speter const char *eol, 486251881Speter svn_stream_t *stream, 487251881Speter apr_pool_t *pool) 488251881Speter{ 489251881Speter *eof = FALSE; 490251881Speter 491251881Speter /* Often, we operate on APR file or string-based streams and know what 492251881Speter * EOL we are looking for. Optimize that common case. 493251881Speter */ 494251881Speter if (svn_stream_supports_mark(stream) && 495251881Speter svn_stream__is_buffered(stream)) 496251881Speter { 497251881Speter /* We can efficiently read chunks speculatively and reposition the 498251881Speter * stream pointer to the end of the line once we found that. 499251881Speter */ 500251881Speter SVN_ERR(stream_readline_chunky(stringbuf, 501251881Speter eof, 502251881Speter eol, 503251881Speter stream, 504251881Speter pool)); 505251881Speter } 506251881Speter else 507251881Speter { 508251881Speter /* Use the standard byte-byte implementation. 509251881Speter */ 510251881Speter SVN_ERR(stream_readline_bytewise(stringbuf, 511251881Speter eof, 512251881Speter eol, 513251881Speter stream, 514251881Speter pool)); 515251881Speter } 516251881Speter 517251881Speter return SVN_NO_ERROR; 518251881Speter} 519251881Speter 520251881Spetersvn_error_t * 521251881Spetersvn_stream_readline(svn_stream_t *stream, 522251881Speter svn_stringbuf_t **stringbuf, 523251881Speter const char *eol, 524251881Speter svn_boolean_t *eof, 525251881Speter apr_pool_t *pool) 526251881Speter{ 527251881Speter return svn_error_trace(stream_readline(stringbuf, eof, eol, stream, 528251881Speter pool)); 529251881Speter} 530251881Speter 531251881Spetersvn_error_t *svn_stream_copy3(svn_stream_t *from, svn_stream_t *to, 532251881Speter svn_cancel_func_t cancel_func, 533251881Speter void *cancel_baton, 534251881Speter apr_pool_t *scratch_pool) 535251881Speter{ 536251881Speter char *buf = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE); 537251881Speter svn_error_t *err; 538251881Speter svn_error_t *err2; 539251881Speter 540251881Speter /* Read and write chunks until we get a short read, indicating the 541251881Speter end of the stream. (We can't get a short write without an 542251881Speter associated error.) */ 543251881Speter while (1) 544251881Speter { 545251881Speter apr_size_t len = SVN__STREAM_CHUNK_SIZE; 546251881Speter 547251881Speter if (cancel_func) 548251881Speter { 549251881Speter err = cancel_func(cancel_baton); 550251881Speter if (err) 551251881Speter break; 552251881Speter } 553251881Speter 554299742Sdim err = svn_stream_read_full(from, buf, &len); 555251881Speter if (err) 556251881Speter break; 557251881Speter 558251881Speter if (len > 0) 559251881Speter err = svn_stream_write(to, buf, &len); 560251881Speter 561251881Speter if (err || (len != SVN__STREAM_CHUNK_SIZE)) 562251881Speter break; 563251881Speter } 564251881Speter 565251881Speter err2 = svn_error_compose_create(svn_stream_close(from), 566251881Speter svn_stream_close(to)); 567251881Speter 568251881Speter return svn_error_compose_create(err, err2); 569251881Speter} 570251881Speter 571251881Spetersvn_error_t * 572251881Spetersvn_stream_contents_same2(svn_boolean_t *same, 573251881Speter svn_stream_t *stream1, 574251881Speter svn_stream_t *stream2, 575251881Speter apr_pool_t *pool) 576251881Speter{ 577251881Speter char *buf1 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); 578251881Speter char *buf2 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); 579251881Speter apr_size_t bytes_read1 = SVN__STREAM_CHUNK_SIZE; 580251881Speter apr_size_t bytes_read2 = SVN__STREAM_CHUNK_SIZE; 581251881Speter svn_error_t *err = NULL; 582251881Speter 583251881Speter *same = TRUE; /* assume TRUE, until disproved below */ 584251881Speter while (bytes_read1 == SVN__STREAM_CHUNK_SIZE 585251881Speter && bytes_read2 == SVN__STREAM_CHUNK_SIZE) 586251881Speter { 587299742Sdim err = svn_stream_read_full(stream1, buf1, &bytes_read1); 588251881Speter if (err) 589251881Speter break; 590299742Sdim err = svn_stream_read_full(stream2, buf2, &bytes_read2); 591251881Speter if (err) 592251881Speter break; 593251881Speter 594251881Speter if ((bytes_read1 != bytes_read2) 595251881Speter || (memcmp(buf1, buf2, bytes_read1))) 596251881Speter { 597251881Speter *same = FALSE; 598251881Speter break; 599251881Speter } 600251881Speter } 601251881Speter 602251881Speter return svn_error_compose_create(err, 603251881Speter svn_error_compose_create( 604251881Speter svn_stream_close(stream1), 605251881Speter svn_stream_close(stream2))); 606251881Speter} 607251881Speter 608251881Speter 609251881Speter/*** Stream implementation utilities ***/ 610251881Speter 611251881Speter/* Skip data from any stream by reading and simply discarding it. */ 612251881Speterstatic svn_error_t * 613299742Sdimskip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_full_fn) 614251881Speter{ 615251881Speter apr_size_t bytes_read = 1; 616251881Speter char buffer[4096]; 617251881Speter apr_size_t to_read = len; 618251881Speter 619251881Speter while ((to_read > 0) && (bytes_read > 0)) 620251881Speter { 621251881Speter bytes_read = sizeof(buffer) < to_read ? sizeof(buffer) : to_read; 622299742Sdim SVN_ERR(read_full_fn(baton, buffer, &bytes_read)); 623251881Speter to_read -= bytes_read; 624251881Speter } 625251881Speter 626251881Speter return SVN_NO_ERROR; 627251881Speter} 628251881Speter 629251881Speter 630251881Speter 631251881Speter/*** Generic readable empty stream ***/ 632251881Speter 633251881Speterstatic svn_error_t * 634251881Speterread_handler_empty(void *baton, char *buffer, apr_size_t *len) 635251881Speter{ 636251881Speter *len = 0; 637251881Speter return SVN_NO_ERROR; 638251881Speter} 639251881Speter 640251881Speterstatic svn_error_t * 641251881Speterwrite_handler_empty(void *baton, const char *data, apr_size_t *len) 642251881Speter{ 643251881Speter return SVN_NO_ERROR; 644251881Speter} 645251881Speter 646251881Speterstatic svn_error_t * 647251881Spetermark_handler_empty(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 648251881Speter{ 649251881Speter *mark = NULL; /* Seek to start of stream marker */ 650251881Speter return SVN_NO_ERROR; 651251881Speter} 652251881Speter 653251881Speterstatic svn_error_t * 654251881Speterseek_handler_empty(void *baton, const svn_stream_mark_t *mark) 655251881Speter{ 656251881Speter return SVN_NO_ERROR; 657251881Speter} 658251881Speter 659251881Speterstatic svn_boolean_t 660251881Speteris_buffered_handler_empty(void *baton) 661251881Speter{ 662251881Speter return FALSE; 663251881Speter} 664251881Speter 665251881Speter 666251881Spetersvn_stream_t * 667251881Spetersvn_stream_empty(apr_pool_t *pool) 668251881Speter{ 669251881Speter svn_stream_t *stream; 670251881Speter 671251881Speter stream = svn_stream_create(NULL, pool); 672299742Sdim svn_stream_set_read2(stream, read_handler_empty, read_handler_empty); 673251881Speter svn_stream_set_write(stream, write_handler_empty); 674251881Speter svn_stream_set_mark(stream, mark_handler_empty); 675251881Speter svn_stream_set_seek(stream, seek_handler_empty); 676251881Speter svn_stream__set_is_buffered(stream, is_buffered_handler_empty); 677251881Speter return stream; 678251881Speter} 679251881Speter 680251881Speter 681251881Speter 682251881Speter/*** Stream duplication support ***/ 683251881Speterstruct baton_tee { 684251881Speter svn_stream_t *out1; 685251881Speter svn_stream_t *out2; 686251881Speter}; 687251881Speter 688251881Speter 689251881Speterstatic svn_error_t * 690251881Speterwrite_handler_tee(void *baton, const char *data, apr_size_t *len) 691251881Speter{ 692251881Speter struct baton_tee *bt = baton; 693251881Speter 694251881Speter SVN_ERR(svn_stream_write(bt->out1, data, len)); 695251881Speter SVN_ERR(svn_stream_write(bt->out2, data, len)); 696251881Speter 697251881Speter return SVN_NO_ERROR; 698251881Speter} 699251881Speter 700251881Speter 701251881Speterstatic svn_error_t * 702251881Speterclose_handler_tee(void *baton) 703251881Speter{ 704251881Speter struct baton_tee *bt = baton; 705251881Speter 706251881Speter SVN_ERR(svn_stream_close(bt->out1)); 707251881Speter SVN_ERR(svn_stream_close(bt->out2)); 708251881Speter 709251881Speter return SVN_NO_ERROR; 710251881Speter} 711251881Speter 712251881Speter 713251881Spetersvn_stream_t * 714251881Spetersvn_stream_tee(svn_stream_t *out1, 715251881Speter svn_stream_t *out2, 716251881Speter apr_pool_t *pool) 717251881Speter{ 718251881Speter struct baton_tee *baton; 719251881Speter svn_stream_t *stream; 720251881Speter 721251881Speter if (out1 == NULL) 722251881Speter return out2; 723251881Speter 724251881Speter if (out2 == NULL) 725251881Speter return out1; 726251881Speter 727251881Speter baton = apr_palloc(pool, sizeof(*baton)); 728251881Speter baton->out1 = out1; 729251881Speter baton->out2 = out2; 730251881Speter stream = svn_stream_create(baton, pool); 731251881Speter svn_stream_set_write(stream, write_handler_tee); 732251881Speter svn_stream_set_close(stream, close_handler_tee); 733251881Speter 734251881Speter return stream; 735251881Speter} 736251881Speter 737251881Speter 738251881Speter 739251881Speter/*** Ownership detaching stream ***/ 740251881Speter 741251881Speterstatic svn_error_t * 742251881Speterread_handler_disown(void *baton, char *buffer, apr_size_t *len) 743251881Speter{ 744299742Sdim return svn_error_trace(svn_stream_read2(baton, buffer, len)); 745251881Speter} 746251881Speter 747251881Speterstatic svn_error_t * 748299742Sdimread_full_handler_disown(void *baton, char *buffer, apr_size_t *len) 749299742Sdim{ 750299742Sdim return svn_error_trace(svn_stream_read_full(baton, buffer, len)); 751299742Sdim} 752299742Sdim 753299742Sdimstatic svn_error_t * 754251881Speterskip_handler_disown(void *baton, apr_size_t len) 755251881Speter{ 756251881Speter return svn_error_trace(svn_stream_skip(baton, len)); 757251881Speter} 758251881Speter 759251881Speterstatic svn_error_t * 760251881Speterwrite_handler_disown(void *baton, const char *buffer, apr_size_t *len) 761251881Speter{ 762251881Speter return svn_error_trace(svn_stream_write(baton, buffer, len)); 763251881Speter} 764251881Speter 765251881Speterstatic svn_error_t * 766251881Spetermark_handler_disown(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 767251881Speter{ 768251881Speter return svn_error_trace(svn_stream_mark(baton, mark, pool)); 769251881Speter} 770251881Speter 771251881Speterstatic svn_error_t * 772251881Speterseek_handler_disown(void *baton, const svn_stream_mark_t *mark) 773251881Speter{ 774251881Speter return svn_error_trace(svn_stream_seek(baton, mark)); 775251881Speter} 776251881Speter 777299742Sdimstatic svn_error_t * 778299742Sdimdata_available_disown(void *baton, svn_boolean_t *data_available) 779299742Sdim{ 780299742Sdim return svn_error_trace(svn_stream_data_available(baton, data_available)); 781299742Sdim} 782299742Sdim 783251881Speterstatic svn_boolean_t 784251881Speteris_buffered_handler_disown(void *baton) 785251881Speter{ 786251881Speter return svn_stream__is_buffered(baton); 787251881Speter} 788251881Speter 789251881Spetersvn_stream_t * 790251881Spetersvn_stream_disown(svn_stream_t *stream, apr_pool_t *pool) 791251881Speter{ 792251881Speter svn_stream_t *s = svn_stream_create(stream, pool); 793251881Speter 794299742Sdim svn_stream_set_read2(s, read_handler_disown, read_full_handler_disown); 795251881Speter svn_stream_set_skip(s, skip_handler_disown); 796251881Speter svn_stream_set_write(s, write_handler_disown); 797251881Speter svn_stream_set_mark(s, mark_handler_disown); 798251881Speter svn_stream_set_seek(s, seek_handler_disown); 799299742Sdim svn_stream_set_data_available(s, data_available_disown); 800251881Speter svn_stream__set_is_buffered(s, is_buffered_handler_disown); 801251881Speter 802251881Speter return s; 803251881Speter} 804251881Speter 805251881Speter 806251881Speter 807251881Speter/*** Generic stream for APR files ***/ 808251881Speterstruct baton_apr { 809251881Speter apr_file_t *file; 810251881Speter apr_pool_t *pool; 811251881Speter}; 812251881Speter 813251881Speter/* svn_stream_mark_t for streams backed by APR files. */ 814251881Speterstruct mark_apr { 815251881Speter apr_off_t off; 816251881Speter}; 817251881Speter 818251881Speterstatic svn_error_t * 819251881Speterread_handler_apr(void *baton, char *buffer, apr_size_t *len) 820251881Speter{ 821251881Speter struct baton_apr *btn = baton; 822251881Speter svn_error_t *err; 823299742Sdim 824299742Sdim if (*len == 1) 825299742Sdim { 826299742Sdim err = svn_io_file_getc(buffer, btn->file, btn->pool); 827299742Sdim if (err) 828299742Sdim { 829299742Sdim *len = 0; 830299742Sdim if (APR_STATUS_IS_EOF(err->apr_err)) 831299742Sdim { 832299742Sdim svn_error_clear(err); 833299742Sdim err = SVN_NO_ERROR; 834299742Sdim } 835299742Sdim } 836299742Sdim } 837299742Sdim else 838299742Sdim { 839299742Sdim err = svn_io_file_read(btn->file, buffer, len, btn->pool); 840299742Sdim if (err && APR_STATUS_IS_EOF(err->apr_err)) 841299742Sdim { 842299742Sdim svn_error_clear(err); 843299742Sdim err = NULL; 844299742Sdim } 845299742Sdim } 846299742Sdim 847299742Sdim return svn_error_trace(err); 848299742Sdim} 849299742Sdim 850299742Sdimstatic svn_error_t * 851299742Sdimread_full_handler_apr(void *baton, char *buffer, apr_size_t *len) 852299742Sdim{ 853299742Sdim struct baton_apr *btn = baton; 854299742Sdim svn_error_t *err; 855251881Speter svn_boolean_t eof; 856251881Speter 857251881Speter if (*len == 1) 858251881Speter { 859251881Speter err = svn_io_file_getc(buffer, btn->file, btn->pool); 860251881Speter if (err) 861251881Speter { 862251881Speter *len = 0; 863251881Speter if (APR_STATUS_IS_EOF(err->apr_err)) 864251881Speter { 865251881Speter svn_error_clear(err); 866251881Speter err = SVN_NO_ERROR; 867251881Speter } 868251881Speter } 869251881Speter } 870251881Speter else 871251881Speter err = svn_io_file_read_full2(btn->file, buffer, *len, len, 872251881Speter &eof, btn->pool); 873251881Speter 874251881Speter return svn_error_trace(err); 875251881Speter} 876251881Speter 877251881Speterstatic svn_error_t * 878251881Speterskip_handler_apr(void *baton, apr_size_t len) 879251881Speter{ 880251881Speter struct baton_apr *btn = baton; 881251881Speter apr_off_t offset = len; 882251881Speter 883251881Speter return svn_error_trace( 884251881Speter svn_io_file_seek(btn->file, APR_CUR, &offset, btn->pool)); 885251881Speter} 886251881Speter 887251881Speterstatic svn_error_t * 888251881Speterwrite_handler_apr(void *baton, const char *data, apr_size_t *len) 889251881Speter{ 890251881Speter struct baton_apr *btn = baton; 891251881Speter svn_error_t *err; 892251881Speter 893251881Speter if (*len == 1) 894251881Speter { 895251881Speter err = svn_io_file_putc(*data, btn->file, btn->pool); 896251881Speter if (err) 897251881Speter *len = 0; 898251881Speter } 899251881Speter else 900251881Speter err = svn_io_file_write_full(btn->file, data, *len, len, btn->pool); 901251881Speter 902251881Speter return svn_error_trace(err); 903251881Speter} 904251881Speter 905251881Speterstatic svn_error_t * 906251881Speterclose_handler_apr(void *baton) 907251881Speter{ 908251881Speter struct baton_apr *btn = baton; 909251881Speter 910251881Speter return svn_error_trace(svn_io_file_close(btn->file, btn->pool)); 911251881Speter} 912251881Speter 913251881Speterstatic svn_error_t * 914251881Spetermark_handler_apr(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 915251881Speter{ 916251881Speter struct baton_apr *btn = baton; 917251881Speter struct mark_apr *mark_apr; 918251881Speter 919251881Speter mark_apr = apr_palloc(pool, sizeof(*mark_apr)); 920251881Speter mark_apr->off = 0; 921251881Speter SVN_ERR(svn_io_file_seek(btn->file, APR_CUR, &mark_apr->off, btn->pool)); 922251881Speter *mark = (svn_stream_mark_t *)mark_apr; 923251881Speter return SVN_NO_ERROR; 924251881Speter} 925251881Speter 926251881Speterstatic svn_error_t * 927251881Speterseek_handler_apr(void *baton, const svn_stream_mark_t *mark) 928251881Speter{ 929251881Speter struct baton_apr *btn = baton; 930251881Speter apr_off_t offset = (mark != NULL) ? ((const struct mark_apr *)mark)->off : 0; 931251881Speter 932251881Speter SVN_ERR(svn_io_file_seek(btn->file, APR_SET, &offset, btn->pool)); 933251881Speter 934251881Speter return SVN_NO_ERROR; 935251881Speter} 936251881Speter 937299742Sdimstatic svn_error_t * 938299742Sdimdata_available_handler_apr(void *baton, svn_boolean_t *data_available) 939299742Sdim{ 940299742Sdim struct baton_apr *btn = baton; 941299742Sdim apr_status_t status; 942299742Sdim#if !defined(WIN32) || APR_FILES_AS_SOCKETS 943299742Sdim apr_pollfd_t pfd; 944299742Sdim int n; 945299742Sdim 946299742Sdim pfd.desc_type = APR_POLL_FILE; 947299742Sdim pfd.desc.f = btn->file; 948299742Sdim pfd.p = btn->pool; /* If we had a scratch pool... Luckily apr doesn't 949299742Sdim store anything in this pool at this time */ 950299742Sdim pfd.reqevents = APR_POLLIN; 951299742Sdim 952299742Sdim status = apr_poll(&pfd, 1, &n, 0); 953299742Sdim 954299742Sdim if (status == APR_SUCCESS) 955299742Sdim { 956299742Sdim *data_available = (n > 0); 957299742Sdim return SVN_NO_ERROR; 958299742Sdim } 959299742Sdim else if (APR_STATUS_IS_EOF(status) || APR_STATUS_IS_TIMEUP(status)) 960299742Sdim { 961299742Sdim *data_available = FALSE; 962299742Sdim return SVN_NO_ERROR; 963299742Sdim } 964299742Sdim else 965299742Sdim { 966299742Sdim return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, 967299742Sdim svn_error_wrap_apr( 968299742Sdim status, 969299742Sdim _("Polling for available data on filestream " 970299742Sdim "failed")), 971299742Sdim NULL); 972299742Sdim } 973299742Sdim#else 974299742Sdim HANDLE h; 975299742Sdim DWORD dwAvail; 976299742Sdim status = apr_os_file_get(&h, btn->file); 977299742Sdim 978299742Sdim if (status) 979299742Sdim return svn_error_wrap_apr(status, NULL); 980299742Sdim 981299742Sdim if (PeekNamedPipe(h, NULL, 0, NULL, &dwAvail, NULL)) 982299742Sdim { 983299742Sdim *data_available = (dwAvail > 0); 984299742Sdim return SVN_NO_ERROR; 985299742Sdim } 986299742Sdim 987299742Sdim return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, 988299742Sdim svn_error_wrap_apr(apr_get_os_error(), NULL), 989299742Sdim _("Windows doesn't support polling on files")); 990299742Sdim#endif 991299742Sdim} 992299742Sdim 993251881Speterstatic svn_boolean_t 994251881Speteris_buffered_handler_apr(void *baton) 995251881Speter{ 996251881Speter struct baton_apr *btn = baton; 997251881Speter return (apr_file_flags_get(btn->file) & APR_BUFFERED) != 0; 998251881Speter} 999251881Speter 1000251881Spetersvn_error_t * 1001251881Spetersvn_stream_open_readonly(svn_stream_t **stream, 1002251881Speter const char *path, 1003251881Speter apr_pool_t *result_pool, 1004251881Speter apr_pool_t *scratch_pool) 1005251881Speter{ 1006251881Speter apr_file_t *file; 1007251881Speter 1008251881Speter SVN_ERR(svn_io_file_open(&file, path, APR_READ | APR_BUFFERED, 1009251881Speter APR_OS_DEFAULT, result_pool)); 1010251881Speter *stream = svn_stream_from_aprfile2(file, FALSE, result_pool); 1011251881Speter 1012251881Speter return SVN_NO_ERROR; 1013251881Speter} 1014251881Speter 1015251881Speter 1016251881Spetersvn_error_t * 1017251881Spetersvn_stream_open_writable(svn_stream_t **stream, 1018251881Speter const char *path, 1019251881Speter apr_pool_t *result_pool, 1020251881Speter apr_pool_t *scratch_pool) 1021251881Speter{ 1022251881Speter apr_file_t *file; 1023251881Speter 1024251881Speter SVN_ERR(svn_io_file_open(&file, path, 1025251881Speter APR_WRITE 1026251881Speter | APR_BUFFERED 1027251881Speter | APR_CREATE 1028251881Speter | APR_EXCL, 1029251881Speter APR_OS_DEFAULT, result_pool)); 1030251881Speter *stream = svn_stream_from_aprfile2(file, FALSE, result_pool); 1031251881Speter 1032251881Speter return SVN_NO_ERROR; 1033251881Speter} 1034251881Speter 1035251881Speter 1036251881Spetersvn_error_t * 1037251881Spetersvn_stream_open_unique(svn_stream_t **stream, 1038251881Speter const char **temp_path, 1039251881Speter const char *dirpath, 1040251881Speter svn_io_file_del_t delete_when, 1041251881Speter apr_pool_t *result_pool, 1042251881Speter apr_pool_t *scratch_pool) 1043251881Speter{ 1044251881Speter apr_file_t *file; 1045251881Speter 1046251881Speter SVN_ERR(svn_io_open_unique_file3(&file, temp_path, dirpath, 1047251881Speter delete_when, result_pool, scratch_pool)); 1048251881Speter *stream = svn_stream_from_aprfile2(file, FALSE, result_pool); 1049251881Speter 1050251881Speter return SVN_NO_ERROR; 1051251881Speter} 1052251881Speter 1053251881Speter 1054299742Sdim/* Helper function that creates a stream from an APR file. */ 1055299742Sdimstatic svn_stream_t * 1056299742Sdimmake_stream_from_apr_file(apr_file_t *file, 1057299742Sdim svn_boolean_t disown, 1058299742Sdim svn_boolean_t supports_seek, 1059299742Sdim apr_pool_t *pool) 1060251881Speter{ 1061251881Speter struct baton_apr *baton; 1062251881Speter svn_stream_t *stream; 1063251881Speter 1064251881Speter if (file == NULL) 1065251881Speter return svn_stream_empty(pool); 1066251881Speter 1067251881Speter baton = apr_palloc(pool, sizeof(*baton)); 1068251881Speter baton->file = file; 1069251881Speter baton->pool = pool; 1070251881Speter stream = svn_stream_create(baton, pool); 1071299742Sdim svn_stream_set_read2(stream, read_handler_apr, read_full_handler_apr); 1072251881Speter svn_stream_set_write(stream, write_handler_apr); 1073299742Sdim 1074299742Sdim if (supports_seek) 1075299742Sdim { 1076299742Sdim svn_stream_set_skip(stream, skip_handler_apr); 1077299742Sdim svn_stream_set_mark(stream, mark_handler_apr); 1078299742Sdim svn_stream_set_seek(stream, seek_handler_apr); 1079299742Sdim } 1080299742Sdim 1081299742Sdim svn_stream_set_data_available(stream, data_available_handler_apr); 1082251881Speter svn_stream__set_is_buffered(stream, is_buffered_handler_apr); 1083253734Speter stream->file = file; 1084251881Speter 1085251881Speter if (! disown) 1086251881Speter svn_stream_set_close(stream, close_handler_apr); 1087251881Speter 1088251881Speter return stream; 1089251881Speter} 1090251881Speter 1091299742Sdimsvn_stream_t * 1092299742Sdimsvn_stream_from_aprfile2(apr_file_t *file, 1093299742Sdim svn_boolean_t disown, 1094299742Sdim apr_pool_t *pool) 1095299742Sdim{ 1096299742Sdim return make_stream_from_apr_file(file, disown, TRUE, pool); 1097299742Sdim} 1098299742Sdim 1099253734Speterapr_file_t * 1100253734Spetersvn_stream__aprfile(svn_stream_t *stream) 1101253734Speter{ 1102253734Speter return stream->file; 1103253734Speter} 1104253734Speter 1105251881Speter 1106251881Speter/* Compressed stream support */ 1107251881Speter 1108251881Speter#define ZBUFFER_SIZE 4096 /* The size of the buffer the 1109251881Speter compressed stream uses to read from 1110251881Speter the substream. Basically an 1111251881Speter arbitrary value, picked to be about 1112251881Speter page-sized. */ 1113251881Speter 1114251881Speterstruct zbaton { 1115251881Speter z_stream *in; /* compressed stream for reading */ 1116251881Speter z_stream *out; /* compressed stream for writing */ 1117299742Sdim void *substream; /* The substream */ 1118251881Speter void *read_buffer; /* buffer used for reading from 1119251881Speter substream */ 1120251881Speter int read_flush; /* what flush mode to use while 1121251881Speter reading */ 1122251881Speter apr_pool_t *pool; /* The pool this baton is allocated 1123251881Speter on */ 1124251881Speter}; 1125251881Speter 1126251881Speter/* zlib alloc function. opaque is the pool we need. */ 1127251881Speterstatic voidpf 1128251881Speterzalloc(voidpf opaque, uInt items, uInt size) 1129251881Speter{ 1130251881Speter apr_pool_t *pool = opaque; 1131251881Speter 1132251881Speter return apr_palloc(pool, items * size); 1133251881Speter} 1134251881Speter 1135251881Speter/* zlib free function */ 1136251881Speterstatic void 1137251881Speterzfree(voidpf opaque, voidpf address) 1138251881Speter{ 1139251881Speter /* Empty, since we allocate on the pool */ 1140251881Speter} 1141251881Speter 1142251881Speter/* Helper function to figure out the sync mode */ 1143251881Speterstatic svn_error_t * 1144299742Sdimread_helper_gz(svn_stream_t *substream, 1145251881Speter char *buffer, 1146251881Speter uInt *len, int *zflush) 1147251881Speter{ 1148251881Speter uInt orig_len = *len; 1149251881Speter 1150251881Speter /* There's no reason this value should grow bigger than the range of 1151251881Speter uInt, but Subversion's API requires apr_size_t. */ 1152251881Speter apr_size_t apr_len = (apr_size_t) *len; 1153251881Speter 1154299742Sdim SVN_ERR(svn_stream_read_full(substream, buffer, &apr_len)); 1155251881Speter 1156251881Speter /* Type cast back to uInt type that zlib uses. On LP64 platforms 1157251881Speter apr_size_t will be bigger than uInt. */ 1158251881Speter *len = (uInt) apr_len; 1159251881Speter 1160251881Speter /* I wanted to use Z_FINISH here, but we need to know our buffer is 1161251881Speter big enough */ 1162251881Speter *zflush = (*len) < orig_len ? Z_SYNC_FLUSH : Z_SYNC_FLUSH; 1163251881Speter 1164251881Speter return SVN_NO_ERROR; 1165251881Speter} 1166251881Speter 1167251881Speter/* Handle reading from a compressed stream */ 1168251881Speterstatic svn_error_t * 1169251881Speterread_handler_gz(void *baton, char *buffer, apr_size_t *len) 1170251881Speter{ 1171251881Speter struct zbaton *btn = baton; 1172251881Speter int zerr; 1173251881Speter 1174251881Speter if (btn->in == NULL) 1175251881Speter { 1176251881Speter btn->in = apr_palloc(btn->pool, sizeof(z_stream)); 1177251881Speter btn->in->zalloc = zalloc; 1178251881Speter btn->in->zfree = zfree; 1179251881Speter btn->in->opaque = btn->pool; 1180251881Speter btn->read_buffer = apr_palloc(btn->pool, ZBUFFER_SIZE); 1181251881Speter btn->in->next_in = btn->read_buffer; 1182251881Speter btn->in->avail_in = ZBUFFER_SIZE; 1183251881Speter 1184299742Sdim SVN_ERR(read_helper_gz(btn->substream, btn->read_buffer, 1185251881Speter &btn->in->avail_in, &btn->read_flush)); 1186251881Speter 1187251881Speter zerr = inflateInit(btn->in); 1188251881Speter SVN_ERR(svn_error__wrap_zlib(zerr, "inflateInit", btn->in->msg)); 1189251881Speter } 1190251881Speter 1191251881Speter btn->in->next_out = (Bytef *) buffer; 1192251881Speter btn->in->avail_out = (uInt) *len; 1193251881Speter 1194251881Speter while (btn->in->avail_out > 0) 1195251881Speter { 1196251881Speter if (btn->in->avail_in <= 0) 1197251881Speter { 1198251881Speter btn->in->avail_in = ZBUFFER_SIZE; 1199251881Speter btn->in->next_in = btn->read_buffer; 1200299742Sdim SVN_ERR(read_helper_gz(btn->substream, btn->read_buffer, 1201251881Speter &btn->in->avail_in, &btn->read_flush)); 1202251881Speter } 1203251881Speter 1204251881Speter /* Short read means underlying stream has run out. */ 1205251881Speter if (btn->in->avail_in == 0) 1206251881Speter { 1207251881Speter *len = 0; 1208251881Speter return SVN_NO_ERROR; 1209251881Speter } 1210251881Speter 1211251881Speter zerr = inflate(btn->in, btn->read_flush); 1212251881Speter if (zerr == Z_STREAM_END) 1213251881Speter break; 1214251881Speter else if (zerr != Z_OK) 1215251881Speter return svn_error_trace(svn_error__wrap_zlib(zerr, "inflate", 1216251881Speter btn->in->msg)); 1217251881Speter } 1218251881Speter 1219251881Speter *len -= btn->in->avail_out; 1220251881Speter return SVN_NO_ERROR; 1221251881Speter} 1222251881Speter 1223251881Speter/* Compress data and write it to the substream */ 1224251881Speterstatic svn_error_t * 1225251881Speterwrite_handler_gz(void *baton, const char *buffer, apr_size_t *len) 1226251881Speter{ 1227251881Speter struct zbaton *btn = baton; 1228251881Speter apr_pool_t *subpool; 1229251881Speter void *write_buf; 1230251881Speter apr_size_t buf_size, write_len; 1231251881Speter int zerr; 1232251881Speter 1233251881Speter if (btn->out == NULL) 1234251881Speter { 1235251881Speter btn->out = apr_palloc(btn->pool, sizeof(z_stream)); 1236251881Speter btn->out->zalloc = zalloc; 1237251881Speter btn->out->zfree = zfree; 1238251881Speter btn->out->opaque = btn->pool; 1239251881Speter 1240251881Speter zerr = deflateInit(btn->out, Z_DEFAULT_COMPRESSION); 1241251881Speter SVN_ERR(svn_error__wrap_zlib(zerr, "deflateInit", btn->out->msg)); 1242251881Speter } 1243251881Speter 1244251881Speter /* The largest buffer we should need is 0.1% larger than the 1245251881Speter compressed data, + 12 bytes. This info comes from zlib.h. */ 1246251881Speter buf_size = *len + (*len / 1000) + 13; 1247251881Speter subpool = svn_pool_create(btn->pool); 1248251881Speter write_buf = apr_palloc(subpool, buf_size); 1249251881Speter 1250251881Speter btn->out->next_in = (Bytef *) buffer; /* Casting away const! */ 1251251881Speter btn->out->avail_in = (uInt) *len; 1252251881Speter 1253251881Speter while (btn->out->avail_in > 0) 1254251881Speter { 1255251881Speter btn->out->next_out = write_buf; 1256251881Speter btn->out->avail_out = (uInt) buf_size; 1257251881Speter 1258251881Speter zerr = deflate(btn->out, Z_NO_FLUSH); 1259251881Speter SVN_ERR(svn_error__wrap_zlib(zerr, "deflate", btn->out->msg)); 1260251881Speter write_len = buf_size - btn->out->avail_out; 1261251881Speter if (write_len > 0) 1262299742Sdim SVN_ERR(svn_stream_write(btn->substream, write_buf, &write_len)); 1263251881Speter } 1264251881Speter 1265251881Speter svn_pool_destroy(subpool); 1266251881Speter 1267251881Speter return SVN_NO_ERROR; 1268251881Speter} 1269251881Speter 1270251881Speter/* Handle flushing and closing the stream */ 1271251881Speterstatic svn_error_t * 1272251881Speterclose_handler_gz(void *baton) 1273251881Speter{ 1274251881Speter struct zbaton *btn = baton; 1275251881Speter int zerr; 1276251881Speter 1277251881Speter if (btn->in != NULL) 1278251881Speter { 1279251881Speter zerr = inflateEnd(btn->in); 1280251881Speter SVN_ERR(svn_error__wrap_zlib(zerr, "inflateEnd", btn->in->msg)); 1281251881Speter } 1282251881Speter 1283251881Speter if (btn->out != NULL) 1284251881Speter { 1285251881Speter void *buf; 1286251881Speter apr_size_t write_len; 1287251881Speter 1288251881Speter buf = apr_palloc(btn->pool, ZBUFFER_SIZE); 1289251881Speter 1290251881Speter while (TRUE) 1291251881Speter { 1292251881Speter btn->out->next_out = buf; 1293251881Speter btn->out->avail_out = ZBUFFER_SIZE; 1294251881Speter 1295251881Speter zerr = deflate(btn->out, Z_FINISH); 1296251881Speter if (zerr != Z_STREAM_END && zerr != Z_OK) 1297251881Speter return svn_error_trace(svn_error__wrap_zlib(zerr, "deflate", 1298251881Speter btn->out->msg)); 1299251881Speter write_len = ZBUFFER_SIZE - btn->out->avail_out; 1300251881Speter if (write_len > 0) 1301299742Sdim SVN_ERR(svn_stream_write(btn->substream, buf, &write_len)); 1302251881Speter if (zerr == Z_STREAM_END) 1303251881Speter break; 1304251881Speter } 1305251881Speter 1306251881Speter zerr = deflateEnd(btn->out); 1307251881Speter SVN_ERR(svn_error__wrap_zlib(zerr, "deflateEnd", btn->out->msg)); 1308251881Speter } 1309251881Speter 1310299742Sdim return svn_error_trace(svn_stream_close(btn->substream)); 1311251881Speter} 1312251881Speter 1313251881Speter 1314251881Spetersvn_stream_t * 1315251881Spetersvn_stream_compressed(svn_stream_t *stream, apr_pool_t *pool) 1316251881Speter{ 1317251881Speter struct svn_stream_t *zstream; 1318251881Speter struct zbaton *baton; 1319251881Speter 1320251881Speter assert(stream != NULL); 1321251881Speter 1322251881Speter baton = apr_palloc(pool, sizeof(*baton)); 1323251881Speter baton->in = baton->out = NULL; 1324299742Sdim baton->substream = stream; 1325251881Speter baton->pool = pool; 1326251881Speter baton->read_buffer = NULL; 1327251881Speter baton->read_flush = Z_SYNC_FLUSH; 1328251881Speter 1329251881Speter zstream = svn_stream_create(baton, pool); 1330299742Sdim svn_stream_set_read2(zstream, NULL /* only full read support */, 1331299742Sdim read_handler_gz); 1332251881Speter svn_stream_set_write(zstream, write_handler_gz); 1333251881Speter svn_stream_set_close(zstream, close_handler_gz); 1334251881Speter 1335251881Speter return zstream; 1336251881Speter} 1337251881Speter 1338251881Speter 1339251881Speter/* Checksummed stream support */ 1340251881Speter 1341251881Speterstruct checksum_stream_baton 1342251881Speter{ 1343251881Speter svn_checksum_ctx_t *read_ctx, *write_ctx; 1344251881Speter svn_checksum_t **read_checksum; /* Output value. */ 1345251881Speter svn_checksum_t **write_checksum; /* Output value. */ 1346251881Speter svn_stream_t *proxy; 1347251881Speter 1348251881Speter /* True if more data should be read when closing the stream. */ 1349251881Speter svn_boolean_t read_more; 1350251881Speter 1351251881Speter /* Pool to allocate read buffer and output values from. */ 1352251881Speter apr_pool_t *pool; 1353251881Speter}; 1354251881Speter 1355251881Speterstatic svn_error_t * 1356251881Speterread_handler_checksum(void *baton, char *buffer, apr_size_t *len) 1357251881Speter{ 1358251881Speter struct checksum_stream_baton *btn = baton; 1359299742Sdim 1360299742Sdim SVN_ERR(svn_stream_read2(btn->proxy, buffer, len)); 1361299742Sdim 1362299742Sdim if (btn->read_checksum) 1363299742Sdim SVN_ERR(svn_checksum_update(btn->read_ctx, buffer, *len)); 1364299742Sdim 1365299742Sdim return SVN_NO_ERROR; 1366299742Sdim} 1367299742Sdim 1368299742Sdimstatic svn_error_t * 1369299742Sdimread_full_handler_checksum(void *baton, char *buffer, apr_size_t *len) 1370299742Sdim{ 1371299742Sdim struct checksum_stream_baton *btn = baton; 1372251881Speter apr_size_t saved_len = *len; 1373251881Speter 1374299742Sdim SVN_ERR(svn_stream_read_full(btn->proxy, buffer, len)); 1375251881Speter 1376251881Speter if (btn->read_checksum) 1377251881Speter SVN_ERR(svn_checksum_update(btn->read_ctx, buffer, *len)); 1378251881Speter 1379251881Speter if (saved_len != *len) 1380251881Speter btn->read_more = FALSE; 1381251881Speter 1382251881Speter return SVN_NO_ERROR; 1383251881Speter} 1384251881Speter 1385251881Speter 1386251881Speterstatic svn_error_t * 1387251881Speterwrite_handler_checksum(void *baton, const char *buffer, apr_size_t *len) 1388251881Speter{ 1389251881Speter struct checksum_stream_baton *btn = baton; 1390251881Speter 1391251881Speter if (btn->write_checksum && *len > 0) 1392251881Speter SVN_ERR(svn_checksum_update(btn->write_ctx, buffer, *len)); 1393251881Speter 1394251881Speter return svn_error_trace(svn_stream_write(btn->proxy, buffer, len)); 1395251881Speter} 1396251881Speter 1397299742Sdimstatic svn_error_t * 1398299742Sdimdata_available_handler_checksum(void *baton, svn_boolean_t *data_available) 1399299742Sdim{ 1400299742Sdim struct checksum_stream_baton *btn = baton; 1401251881Speter 1402299742Sdim return svn_error_trace(svn_stream_data_available(btn->proxy, 1403299742Sdim data_available)); 1404299742Sdim} 1405299742Sdim 1406251881Speterstatic svn_error_t * 1407251881Speterclose_handler_checksum(void *baton) 1408251881Speter{ 1409251881Speter struct checksum_stream_baton *btn = baton; 1410251881Speter 1411251881Speter /* If we're supposed to drain the stream, do so before finalizing the 1412251881Speter checksum. */ 1413251881Speter if (btn->read_more) 1414251881Speter { 1415251881Speter char *buf = apr_palloc(btn->pool, SVN__STREAM_CHUNK_SIZE); 1416251881Speter apr_size_t len = SVN__STREAM_CHUNK_SIZE; 1417251881Speter 1418251881Speter do 1419251881Speter { 1420299742Sdim SVN_ERR(read_full_handler_checksum(baton, buf, &len)); 1421251881Speter } 1422251881Speter while (btn->read_more); 1423251881Speter } 1424251881Speter 1425251881Speter if (btn->read_ctx) 1426251881Speter SVN_ERR(svn_checksum_final(btn->read_checksum, btn->read_ctx, btn->pool)); 1427251881Speter 1428251881Speter if (btn->write_ctx) 1429251881Speter SVN_ERR(svn_checksum_final(btn->write_checksum, btn->write_ctx, btn->pool)); 1430251881Speter 1431251881Speter return svn_error_trace(svn_stream_close(btn->proxy)); 1432251881Speter} 1433251881Speter 1434251881Speter 1435251881Spetersvn_stream_t * 1436251881Spetersvn_stream_checksummed2(svn_stream_t *stream, 1437251881Speter svn_checksum_t **read_checksum, 1438251881Speter svn_checksum_t **write_checksum, 1439251881Speter svn_checksum_kind_t checksum_kind, 1440251881Speter svn_boolean_t read_all, 1441251881Speter apr_pool_t *pool) 1442251881Speter{ 1443251881Speter svn_stream_t *s; 1444251881Speter struct checksum_stream_baton *baton; 1445251881Speter 1446251881Speter if (read_checksum == NULL && write_checksum == NULL) 1447251881Speter return stream; 1448251881Speter 1449251881Speter baton = apr_palloc(pool, sizeof(*baton)); 1450251881Speter if (read_checksum) 1451251881Speter baton->read_ctx = svn_checksum_ctx_create(checksum_kind, pool); 1452251881Speter else 1453251881Speter baton->read_ctx = NULL; 1454251881Speter 1455251881Speter if (write_checksum) 1456251881Speter baton->write_ctx = svn_checksum_ctx_create(checksum_kind, pool); 1457251881Speter else 1458251881Speter baton->write_ctx = NULL; 1459251881Speter 1460251881Speter baton->read_checksum = read_checksum; 1461251881Speter baton->write_checksum = write_checksum; 1462251881Speter baton->proxy = stream; 1463251881Speter baton->read_more = read_all; 1464251881Speter baton->pool = pool; 1465251881Speter 1466251881Speter s = svn_stream_create(baton, pool); 1467299742Sdim svn_stream_set_read2(s, read_handler_checksum, read_full_handler_checksum); 1468251881Speter svn_stream_set_write(s, write_handler_checksum); 1469299742Sdim svn_stream_set_data_available(s, data_available_handler_checksum); 1470251881Speter svn_stream_set_close(s, close_handler_checksum); 1471251881Speter return s; 1472251881Speter} 1473251881Speter 1474299742Sdim/* Miscellaneous stream functions. */ 1475251881Speter 1476299742Sdimsvn_error_t * 1477299742Sdimsvn_stringbuf_from_stream(svn_stringbuf_t **str, 1478299742Sdim svn_stream_t *stream, 1479299742Sdim apr_size_t len_hint, 1480299742Sdim apr_pool_t *result_pool) 1481251881Speter{ 1482299742Sdim#define MIN_READ_SIZE 64 1483251881Speter 1484299742Sdim apr_size_t to_read = 0; 1485299742Sdim svn_stringbuf_t *text 1486299742Sdim = svn_stringbuf_create_ensure(len_hint ? len_hint : MIN_READ_SIZE, 1487299742Sdim result_pool); 1488251881Speter 1489299742Sdim do 1490299742Sdim { 1491299742Sdim to_read = text->blocksize - 1 - text->len; 1492299742Sdim SVN_ERR(svn_stream_read_full(stream, text->data + text->len, &to_read)); 1493299742Sdim text->len += to_read; 1494251881Speter 1495299742Sdim if (to_read && text->blocksize < text->len + MIN_READ_SIZE) 1496299742Sdim svn_stringbuf_ensure(text, text->blocksize * 2); 1497299742Sdim } 1498299742Sdim while (to_read); 1499251881Speter 1500299742Sdim text->data[text->len] = '\0'; 1501299742Sdim *str = text; 1502251881Speter 1503251881Speter return SVN_NO_ERROR; 1504251881Speter} 1505251881Speter 1506251881Speterstruct stringbuf_stream_baton 1507251881Speter{ 1508251881Speter svn_stringbuf_t *str; 1509251881Speter apr_size_t amt_read; 1510251881Speter}; 1511251881Speter 1512251881Speter/* svn_stream_mark_t for streams backed by stringbufs. */ 1513251881Speterstruct stringbuf_stream_mark { 1514251881Speter apr_size_t pos; 1515251881Speter}; 1516251881Speter 1517251881Speterstatic svn_error_t * 1518251881Speterread_handler_stringbuf(void *baton, char *buffer, apr_size_t *len) 1519251881Speter{ 1520251881Speter struct stringbuf_stream_baton *btn = baton; 1521251881Speter apr_size_t left_to_read = btn->str->len - btn->amt_read; 1522251881Speter 1523251881Speter *len = (*len > left_to_read) ? left_to_read : *len; 1524251881Speter memcpy(buffer, btn->str->data + btn->amt_read, *len); 1525251881Speter btn->amt_read += *len; 1526251881Speter return SVN_NO_ERROR; 1527251881Speter} 1528251881Speter 1529251881Speterstatic svn_error_t * 1530251881Speterskip_handler_stringbuf(void *baton, apr_size_t len) 1531251881Speter{ 1532251881Speter struct stringbuf_stream_baton *btn = baton; 1533251881Speter apr_size_t left_to_read = btn->str->len - btn->amt_read; 1534251881Speter 1535251881Speter len = (len > left_to_read) ? left_to_read : len; 1536251881Speter btn->amt_read += len; 1537251881Speter return SVN_NO_ERROR; 1538251881Speter} 1539251881Speter 1540251881Speterstatic svn_error_t * 1541251881Speterwrite_handler_stringbuf(void *baton, const char *data, apr_size_t *len) 1542251881Speter{ 1543251881Speter struct stringbuf_stream_baton *btn = baton; 1544251881Speter 1545251881Speter svn_stringbuf_appendbytes(btn->str, data, *len); 1546251881Speter return SVN_NO_ERROR; 1547251881Speter} 1548251881Speter 1549251881Speterstatic svn_error_t * 1550251881Spetermark_handler_stringbuf(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 1551251881Speter{ 1552251881Speter struct stringbuf_stream_baton *btn; 1553251881Speter struct stringbuf_stream_mark *stringbuf_stream_mark; 1554251881Speter 1555251881Speter btn = baton; 1556251881Speter 1557251881Speter stringbuf_stream_mark = apr_palloc(pool, sizeof(*stringbuf_stream_mark)); 1558251881Speter stringbuf_stream_mark->pos = btn->amt_read; 1559251881Speter *mark = (svn_stream_mark_t *)stringbuf_stream_mark; 1560251881Speter return SVN_NO_ERROR; 1561251881Speter} 1562251881Speter 1563251881Speterstatic svn_error_t * 1564251881Speterseek_handler_stringbuf(void *baton, const svn_stream_mark_t *mark) 1565251881Speter{ 1566251881Speter struct stringbuf_stream_baton *btn = baton; 1567251881Speter 1568251881Speter if (mark != NULL) 1569251881Speter { 1570251881Speter const struct stringbuf_stream_mark *stringbuf_stream_mark; 1571251881Speter 1572251881Speter stringbuf_stream_mark = (const struct stringbuf_stream_mark *)mark; 1573251881Speter btn->amt_read = stringbuf_stream_mark->pos; 1574251881Speter } 1575251881Speter else 1576251881Speter btn->amt_read = 0; 1577251881Speter 1578251881Speter return SVN_NO_ERROR; 1579251881Speter} 1580251881Speter 1581299742Sdimstatic svn_error_t * 1582299742Sdimdata_available_handler_stringbuf(void *baton, svn_boolean_t *data_available) 1583299742Sdim{ 1584299742Sdim struct stringbuf_stream_baton *btn = baton; 1585299742Sdim 1586299742Sdim *data_available = ((btn->str->len - btn->amt_read) > 0); 1587299742Sdim return SVN_NO_ERROR; 1588299742Sdim} 1589299742Sdim 1590251881Speterstatic svn_boolean_t 1591251881Speteris_buffered_handler_stringbuf(void *baton) 1592251881Speter{ 1593251881Speter return TRUE; 1594251881Speter} 1595251881Speter 1596251881Spetersvn_stream_t * 1597251881Spetersvn_stream_from_stringbuf(svn_stringbuf_t *str, 1598251881Speter apr_pool_t *pool) 1599251881Speter{ 1600251881Speter svn_stream_t *stream; 1601251881Speter struct stringbuf_stream_baton *baton; 1602251881Speter 1603251881Speter if (! str) 1604251881Speter return svn_stream_empty(pool); 1605251881Speter 1606251881Speter baton = apr_palloc(pool, sizeof(*baton)); 1607251881Speter baton->str = str; 1608251881Speter baton->amt_read = 0; 1609251881Speter stream = svn_stream_create(baton, pool); 1610299742Sdim svn_stream_set_read2(stream, read_handler_stringbuf, read_handler_stringbuf); 1611251881Speter svn_stream_set_skip(stream, skip_handler_stringbuf); 1612251881Speter svn_stream_set_write(stream, write_handler_stringbuf); 1613251881Speter svn_stream_set_mark(stream, mark_handler_stringbuf); 1614251881Speter svn_stream_set_seek(stream, seek_handler_stringbuf); 1615299742Sdim svn_stream_set_data_available(stream, data_available_handler_stringbuf); 1616251881Speter svn_stream__set_is_buffered(stream, is_buffered_handler_stringbuf); 1617251881Speter return stream; 1618251881Speter} 1619251881Speter 1620251881Speterstruct string_stream_baton 1621251881Speter{ 1622251881Speter const svn_string_t *str; 1623251881Speter apr_size_t amt_read; 1624251881Speter}; 1625251881Speter 1626251881Speter/* svn_stream_mark_t for streams backed by stringbufs. */ 1627251881Speterstruct string_stream_mark { 1628251881Speter apr_size_t pos; 1629251881Speter}; 1630251881Speter 1631251881Speterstatic svn_error_t * 1632251881Speterread_handler_string(void *baton, char *buffer, apr_size_t *len) 1633251881Speter{ 1634251881Speter struct string_stream_baton *btn = baton; 1635251881Speter apr_size_t left_to_read = btn->str->len - btn->amt_read; 1636251881Speter 1637251881Speter *len = (*len > left_to_read) ? left_to_read : *len; 1638251881Speter memcpy(buffer, btn->str->data + btn->amt_read, *len); 1639251881Speter btn->amt_read += *len; 1640251881Speter return SVN_NO_ERROR; 1641251881Speter} 1642251881Speter 1643251881Speterstatic svn_error_t * 1644251881Spetermark_handler_string(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 1645251881Speter{ 1646251881Speter struct string_stream_baton *btn; 1647251881Speter struct string_stream_mark *marker; 1648251881Speter 1649251881Speter btn = baton; 1650251881Speter 1651251881Speter marker = apr_palloc(pool, sizeof(*marker)); 1652251881Speter marker->pos = btn->amt_read; 1653251881Speter *mark = (svn_stream_mark_t *)marker; 1654251881Speter return SVN_NO_ERROR; 1655251881Speter} 1656251881Speter 1657251881Speterstatic svn_error_t * 1658251881Speterseek_handler_string(void *baton, const svn_stream_mark_t *mark) 1659251881Speter{ 1660251881Speter struct string_stream_baton *btn = baton; 1661251881Speter 1662251881Speter if (mark != NULL) 1663251881Speter { 1664251881Speter const struct string_stream_mark *marker; 1665251881Speter 1666251881Speter marker = (const struct string_stream_mark *)mark; 1667251881Speter btn->amt_read = marker->pos; 1668251881Speter } 1669251881Speter else 1670251881Speter btn->amt_read = 0; 1671251881Speter 1672251881Speter return SVN_NO_ERROR; 1673251881Speter} 1674251881Speter 1675251881Speterstatic svn_error_t * 1676251881Speterskip_handler_string(void *baton, apr_size_t len) 1677251881Speter{ 1678251881Speter struct string_stream_baton *btn = baton; 1679251881Speter apr_size_t left_to_read = btn->str->len - btn->amt_read; 1680251881Speter 1681251881Speter len = (len > left_to_read) ? left_to_read : len; 1682251881Speter btn->amt_read += len; 1683251881Speter return SVN_NO_ERROR; 1684251881Speter} 1685251881Speter 1686299742Sdimstatic svn_error_t * 1687299742Sdimdata_available_handler_string(void *baton, svn_boolean_t *data_available) 1688299742Sdim{ 1689299742Sdim struct string_stream_baton *btn = baton; 1690299742Sdim 1691299742Sdim *data_available = ((btn->str->len - btn->amt_read) > 0); 1692299742Sdim return SVN_NO_ERROR; 1693299742Sdim} 1694299742Sdim 1695251881Speterstatic svn_boolean_t 1696251881Speteris_buffered_handler_string(void *baton) 1697251881Speter{ 1698251881Speter return TRUE; 1699251881Speter} 1700251881Speter 1701251881Spetersvn_stream_t * 1702251881Spetersvn_stream_from_string(const svn_string_t *str, 1703251881Speter apr_pool_t *pool) 1704251881Speter{ 1705251881Speter svn_stream_t *stream; 1706251881Speter struct string_stream_baton *baton; 1707251881Speter 1708251881Speter if (! str) 1709251881Speter return svn_stream_empty(pool); 1710251881Speter 1711251881Speter baton = apr_palloc(pool, sizeof(*baton)); 1712251881Speter baton->str = str; 1713251881Speter baton->amt_read = 0; 1714251881Speter stream = svn_stream_create(baton, pool); 1715299742Sdim svn_stream_set_read2(stream, read_handler_string, read_handler_string); 1716251881Speter svn_stream_set_mark(stream, mark_handler_string); 1717251881Speter svn_stream_set_seek(stream, seek_handler_string); 1718251881Speter svn_stream_set_skip(stream, skip_handler_string); 1719299742Sdim svn_stream_set_data_available(stream, data_available_handler_string); 1720251881Speter svn_stream__set_is_buffered(stream, is_buffered_handler_string); 1721251881Speter return stream; 1722251881Speter} 1723251881Speter 1724251881Speter 1725251881Spetersvn_error_t * 1726251881Spetersvn_stream_for_stdin(svn_stream_t **in, apr_pool_t *pool) 1727251881Speter{ 1728251881Speter apr_file_t *stdin_file; 1729251881Speter apr_status_t apr_err; 1730251881Speter 1731251881Speter apr_err = apr_file_open_stdin(&stdin_file, pool); 1732251881Speter if (apr_err) 1733251881Speter return svn_error_wrap_apr(apr_err, "Can't open stdin"); 1734251881Speter 1735299742Sdim /* STDIN may or may not support positioning requests, but generally 1736299742Sdim it does not, or the behavior is implementation-specific. Hence, 1737299742Sdim we cannot safely advertise mark(), seek() and non-default skip() 1738299742Sdim support. */ 1739299742Sdim *in = make_stream_from_apr_file(stdin_file, TRUE, FALSE, pool); 1740251881Speter 1741251881Speter return SVN_NO_ERROR; 1742251881Speter} 1743251881Speter 1744251881Speter 1745251881Spetersvn_error_t * 1746251881Spetersvn_stream_for_stdout(svn_stream_t **out, apr_pool_t *pool) 1747251881Speter{ 1748251881Speter apr_file_t *stdout_file; 1749251881Speter apr_status_t apr_err; 1750251881Speter 1751251881Speter apr_err = apr_file_open_stdout(&stdout_file, pool); 1752251881Speter if (apr_err) 1753251881Speter return svn_error_wrap_apr(apr_err, "Can't open stdout"); 1754251881Speter 1755299742Sdim /* STDOUT may or may not support positioning requests, but generally 1756299742Sdim it does not, or the behavior is implementation-specific. Hence, 1757299742Sdim we cannot safely advertise mark(), seek() and non-default skip() 1758299742Sdim support. */ 1759299742Sdim *out = make_stream_from_apr_file(stdout_file, TRUE, FALSE, pool); 1760251881Speter 1761251881Speter return SVN_NO_ERROR; 1762251881Speter} 1763251881Speter 1764251881Speter 1765251881Spetersvn_error_t * 1766251881Spetersvn_stream_for_stderr(svn_stream_t **err, apr_pool_t *pool) 1767251881Speter{ 1768251881Speter apr_file_t *stderr_file; 1769251881Speter apr_status_t apr_err; 1770251881Speter 1771251881Speter apr_err = apr_file_open_stderr(&stderr_file, pool); 1772251881Speter if (apr_err) 1773251881Speter return svn_error_wrap_apr(apr_err, "Can't open stderr"); 1774251881Speter 1775299742Sdim /* STDERR may or may not support positioning requests, but generally 1776299742Sdim it does not, or the behavior is implementation-specific. Hence, 1777299742Sdim we cannot safely advertise mark(), seek() and non-default skip() 1778299742Sdim support. */ 1779299742Sdim *err = make_stream_from_apr_file(stderr_file, TRUE, FALSE, pool); 1780251881Speter 1781251881Speter return SVN_NO_ERROR; 1782251881Speter} 1783251881Speter 1784251881Speter 1785251881Spetersvn_error_t * 1786251881Spetersvn_string_from_stream(svn_string_t **result, 1787251881Speter svn_stream_t *stream, 1788251881Speter apr_pool_t *result_pool, 1789251881Speter apr_pool_t *scratch_pool) 1790251881Speter{ 1791251881Speter svn_stringbuf_t *work = svn_stringbuf_create_ensure(SVN__STREAM_CHUNK_SIZE, 1792251881Speter result_pool); 1793251881Speter char *buffer = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE); 1794251881Speter 1795251881Speter while (1) 1796251881Speter { 1797251881Speter apr_size_t len = SVN__STREAM_CHUNK_SIZE; 1798251881Speter 1799299742Sdim SVN_ERR(svn_stream_read_full(stream, buffer, &len)); 1800251881Speter svn_stringbuf_appendbytes(work, buffer, len); 1801251881Speter 1802251881Speter if (len < SVN__STREAM_CHUNK_SIZE) 1803251881Speter break; 1804251881Speter } 1805251881Speter 1806251881Speter SVN_ERR(svn_stream_close(stream)); 1807251881Speter 1808251881Speter *result = apr_palloc(result_pool, sizeof(**result)); 1809251881Speter (*result)->data = work->data; 1810251881Speter (*result)->len = work->len; 1811251881Speter 1812251881Speter return SVN_NO_ERROR; 1813251881Speter} 1814251881Speter 1815251881Speter 1816299742Sdim/* These are somewhat arbitrary, if we ever get good empirical data as to 1817251881Speter actually valid values, feel free to update them. */ 1818251881Speter#define BUFFER_BLOCK_SIZE 1024 1819251881Speter#define BUFFER_MAX_SIZE 100000 1820251881Speter 1821251881Spetersvn_stream_t * 1822251881Spetersvn_stream_buffered(apr_pool_t *result_pool) 1823251881Speter{ 1824299742Sdim return svn_stream__from_spillbuf(svn_spillbuf__create(BUFFER_BLOCK_SIZE, 1825299742Sdim BUFFER_MAX_SIZE, 1826299742Sdim result_pool), 1827251881Speter result_pool); 1828251881Speter} 1829251881Speter 1830251881Speter 1831251881Speter 1832251881Speter/*** Lazyopen Streams ***/ 1833251881Speter 1834251881Speter/* Custom baton for lazyopen-style wrapper streams. */ 1835251881Spetertypedef struct lazyopen_baton_t { 1836251881Speter 1837251881Speter /* Callback function and baton for opening the wrapped stream. */ 1838251881Speter svn_stream_lazyopen_func_t open_func; 1839251881Speter void *open_baton; 1840251881Speter 1841251881Speter /* The wrapped stream, or NULL if the stream hasn't yet been 1842251881Speter opened. */ 1843251881Speter svn_stream_t *real_stream; 1844251881Speter apr_pool_t *pool; 1845251881Speter 1846251881Speter /* Whether to open the wrapped stream on a close call. */ 1847251881Speter svn_boolean_t open_on_close; 1848251881Speter 1849251881Speter} lazyopen_baton_t; 1850251881Speter 1851251881Speter 1852251881Speter/* Use B->open_func/baton to create and set B->real_stream iff it 1853251881Speter isn't already set. */ 1854251881Speterstatic svn_error_t * 1855251881Speterlazyopen_if_unopened(lazyopen_baton_t *b) 1856251881Speter{ 1857251881Speter if (b->real_stream == NULL) 1858251881Speter { 1859251881Speter svn_stream_t *stream; 1860251881Speter apr_pool_t *scratch_pool = svn_pool_create(b->pool); 1861251881Speter 1862251881Speter SVN_ERR(b->open_func(&stream, b->open_baton, 1863251881Speter b->pool, scratch_pool)); 1864251881Speter 1865251881Speter svn_pool_destroy(scratch_pool); 1866251881Speter 1867251881Speter b->real_stream = stream; 1868251881Speter } 1869251881Speter 1870251881Speter return SVN_NO_ERROR; 1871251881Speter} 1872251881Speter 1873251881Speter/* Implements svn_read_fn_t */ 1874251881Speterstatic svn_error_t * 1875251881Speterread_handler_lazyopen(void *baton, 1876251881Speter char *buffer, 1877251881Speter apr_size_t *len) 1878251881Speter{ 1879251881Speter lazyopen_baton_t *b = baton; 1880251881Speter 1881251881Speter SVN_ERR(lazyopen_if_unopened(b)); 1882299742Sdim SVN_ERR(svn_stream_read2(b->real_stream, buffer, len)); 1883251881Speter 1884251881Speter return SVN_NO_ERROR; 1885251881Speter} 1886251881Speter 1887299742Sdim/* Implements svn_read_fn_t */ 1888299742Sdimstatic svn_error_t * 1889299742Sdimread_full_handler_lazyopen(void *baton, 1890299742Sdim char *buffer, 1891299742Sdim apr_size_t *len) 1892299742Sdim{ 1893299742Sdim lazyopen_baton_t *b = baton; 1894299742Sdim 1895299742Sdim SVN_ERR(lazyopen_if_unopened(b)); 1896299742Sdim SVN_ERR(svn_stream_read_full(b->real_stream, buffer, len)); 1897299742Sdim 1898299742Sdim return SVN_NO_ERROR; 1899299742Sdim} 1900299742Sdim 1901251881Speter/* Implements svn_stream_skip_fn_t */ 1902251881Speterstatic svn_error_t * 1903251881Speterskip_handler_lazyopen(void *baton, 1904251881Speter apr_size_t len) 1905251881Speter{ 1906251881Speter lazyopen_baton_t *b = baton; 1907251881Speter 1908251881Speter SVN_ERR(lazyopen_if_unopened(b)); 1909251881Speter SVN_ERR(svn_stream_skip(b->real_stream, len)); 1910251881Speter 1911251881Speter return SVN_NO_ERROR; 1912251881Speter} 1913251881Speter 1914251881Speter/* Implements svn_write_fn_t */ 1915251881Speterstatic svn_error_t * 1916251881Speterwrite_handler_lazyopen(void *baton, 1917251881Speter const char *data, 1918251881Speter apr_size_t *len) 1919251881Speter{ 1920251881Speter lazyopen_baton_t *b = baton; 1921251881Speter 1922251881Speter SVN_ERR(lazyopen_if_unopened(b)); 1923251881Speter SVN_ERR(svn_stream_write(b->real_stream, data, len)); 1924251881Speter 1925251881Speter return SVN_NO_ERROR; 1926251881Speter} 1927251881Speter 1928251881Speter/* Implements svn_close_fn_t */ 1929251881Speterstatic svn_error_t * 1930251881Speterclose_handler_lazyopen(void *baton) 1931251881Speter{ 1932251881Speter lazyopen_baton_t *b = baton; 1933251881Speter 1934251881Speter if (b->open_on_close) 1935251881Speter SVN_ERR(lazyopen_if_unopened(b)); 1936251881Speter if (b->real_stream) 1937251881Speter SVN_ERR(svn_stream_close(b->real_stream)); 1938251881Speter 1939251881Speter return SVN_NO_ERROR; 1940251881Speter} 1941251881Speter 1942251881Speter/* Implements svn_stream_mark_fn_t */ 1943251881Speterstatic svn_error_t * 1944251881Spetermark_handler_lazyopen(void *baton, 1945251881Speter svn_stream_mark_t **mark, 1946251881Speter apr_pool_t *pool) 1947251881Speter{ 1948251881Speter lazyopen_baton_t *b = baton; 1949251881Speter 1950251881Speter SVN_ERR(lazyopen_if_unopened(b)); 1951251881Speter SVN_ERR(svn_stream_mark(b->real_stream, mark, pool)); 1952251881Speter 1953251881Speter return SVN_NO_ERROR; 1954251881Speter} 1955251881Speter 1956251881Speter/* Implements svn_stream_seek_fn_t */ 1957251881Speterstatic svn_error_t * 1958251881Speterseek_handler_lazyopen(void *baton, 1959251881Speter const svn_stream_mark_t *mark) 1960251881Speter{ 1961251881Speter lazyopen_baton_t *b = baton; 1962251881Speter 1963251881Speter SVN_ERR(lazyopen_if_unopened(b)); 1964251881Speter SVN_ERR(svn_stream_seek(b->real_stream, mark)); 1965251881Speter 1966251881Speter return SVN_NO_ERROR; 1967251881Speter} 1968251881Speter 1969299742Sdimstatic svn_error_t * 1970299742Sdimdata_available_handler_lazyopen(void *baton, 1971299742Sdim svn_boolean_t *data_available) 1972299742Sdim{ 1973299742Sdim lazyopen_baton_t *b = baton; 1974299742Sdim 1975299742Sdim SVN_ERR(lazyopen_if_unopened(b)); 1976299742Sdim return svn_error_trace(svn_stream_data_available(b->real_stream, 1977299742Sdim data_available)); 1978299742Sdim} 1979299742Sdim 1980251881Speter/* Implements svn_stream__is_buffered_fn_t */ 1981251881Speterstatic svn_boolean_t 1982251881Speteris_buffered_lazyopen(void *baton) 1983251881Speter{ 1984251881Speter lazyopen_baton_t *b = baton; 1985251881Speter 1986251881Speter /* No lazy open as we cannot handle an open error. */ 1987251881Speter if (!b->real_stream) 1988251881Speter return FALSE; 1989251881Speter 1990251881Speter return svn_stream__is_buffered(b->real_stream); 1991251881Speter} 1992251881Speter 1993251881Spetersvn_stream_t * 1994251881Spetersvn_stream_lazyopen_create(svn_stream_lazyopen_func_t open_func, 1995251881Speter void *open_baton, 1996251881Speter svn_boolean_t open_on_close, 1997251881Speter apr_pool_t *result_pool) 1998251881Speter{ 1999251881Speter lazyopen_baton_t *lob = apr_pcalloc(result_pool, sizeof(*lob)); 2000251881Speter svn_stream_t *stream; 2001251881Speter 2002251881Speter lob->open_func = open_func; 2003251881Speter lob->open_baton = open_baton; 2004251881Speter lob->real_stream = NULL; 2005251881Speter lob->pool = result_pool; 2006251881Speter lob->open_on_close = open_on_close; 2007251881Speter 2008251881Speter stream = svn_stream_create(lob, result_pool); 2009299742Sdim svn_stream_set_read2(stream, read_handler_lazyopen, 2010299742Sdim read_full_handler_lazyopen); 2011251881Speter svn_stream_set_skip(stream, skip_handler_lazyopen); 2012251881Speter svn_stream_set_write(stream, write_handler_lazyopen); 2013251881Speter svn_stream_set_close(stream, close_handler_lazyopen); 2014251881Speter svn_stream_set_mark(stream, mark_handler_lazyopen); 2015251881Speter svn_stream_set_seek(stream, seek_handler_lazyopen); 2016299742Sdim svn_stream_set_data_available(stream, data_available_handler_lazyopen); 2017251881Speter svn_stream__set_is_buffered(stream, is_buffered_lazyopen); 2018251881Speter 2019251881Speter return stream; 2020251881Speter} 2021299742Sdim 2022299742Sdim/* Baton for install streams */ 2023299742Sdimstruct install_baton_t 2024299742Sdim{ 2025299742Sdim struct baton_apr baton_apr; 2026299742Sdim const char *tmp_path; 2027299742Sdim}; 2028299742Sdim 2029299742Sdim#ifdef WIN32 2030299742Sdim 2031299742Sdim/* Create and open a tempfile in DIRECTORY. Return its handle and path */ 2032299742Sdimstatic svn_error_t * 2033299742Sdimcreate_tempfile(HANDLE *hFile, 2034299742Sdim const char **file_path, 2035299742Sdim const char *directory, 2036299742Sdim apr_pool_t *result_pool, 2037299742Sdim apr_pool_t *scratch_pool) 2038299742Sdim{ 2039299742Sdim const char *unique_name; 2040299742Sdim apr_pool_t *iterpool = svn_pool_create(scratch_pool); 2041299742Sdim static svn_atomic_t tempname_counter; 2042299742Sdim int baseNr = (GetTickCount() << 11) + 13 * svn_atomic_inc(&tempname_counter) 2043299742Sdim + GetCurrentProcessId(); 2044299742Sdim int i = 0; 2045299742Sdim HANDLE h; 2046299742Sdim 2047299742Sdim /* Shares common idea with io.c's temp_file_create */ 2048299742Sdim 2049299742Sdim do 2050299742Sdim { 2051299742Sdim apr_uint32_t unique_nr; 2052299742Sdim WCHAR *w_name; 2053299742Sdim 2054299742Sdim /* Generate a number that should be unique for this application and 2055299742Sdim usually for the entire computer to reduce the number of cycles 2056299742Sdim through this loop. (A bit of calculation is much cheaper than 2057299742Sdim disk io) */ 2058299742Sdim unique_nr = baseNr + 7 * i++; 2059299742Sdim 2060299742Sdim 2061299742Sdim svn_pool_clear(iterpool); 2062299742Sdim unique_name = svn_dirent_join(directory, 2063299742Sdim apr_psprintf(iterpool, "svn-%X", 2064299742Sdim unique_nr), 2065299742Sdim iterpool); 2066299742Sdim 2067299742Sdim SVN_ERR(svn_io__utf8_to_unicode_longpath(&w_name, unique_name, 2068299742Sdim iterpool)); 2069299742Sdim 2070299742Sdim /* Create a completely not-sharable file to avoid indexers, and other 2071299742Sdim filesystem watchers locking the file while we are still writing. 2072299742Sdim 2073299742Sdim We need DELETE privileges to move the file. */ 2074299742Sdim h = CreateFileW(w_name, GENERIC_WRITE | DELETE, 0 /* share */, 2075299742Sdim NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); 2076299742Sdim 2077299742Sdim if (h == INVALID_HANDLE_VALUE) 2078299742Sdim { 2079299742Sdim apr_status_t status = apr_get_os_error(); 2080299742Sdim if (i > 1000) 2081299742Sdim return svn_error_createf(SVN_ERR_IO_UNIQUE_NAMES_EXHAUSTED, 2082299742Sdim svn_error_wrap_apr(status, NULL), 2083299742Sdim _("Unable to make name in '%s'"), 2084299742Sdim svn_dirent_local_style(directory, scratch_pool)); 2085299742Sdim 2086299742Sdim if (!APR_STATUS_IS_EEXIST(status) && !APR_STATUS_IS_EACCES(status)) 2087299742Sdim return svn_error_wrap_apr(status, NULL); 2088299742Sdim } 2089299742Sdim } 2090299742Sdim while (h == INVALID_HANDLE_VALUE); 2091299742Sdim 2092299742Sdim *hFile = h; 2093299742Sdim *file_path = apr_pstrdup(result_pool, unique_name); 2094299742Sdim svn_pool_destroy(iterpool); 2095299742Sdim 2096299742Sdim return SVN_NO_ERROR; 2097299742Sdim} 2098299742Sdim 2099299742Sdim/* Implements svn_close_fn_t */ 2100299742Sdimstatic svn_error_t * 2101299742Sdiminstall_close(void *baton) 2102299742Sdim{ 2103299742Sdim struct install_baton_t *ib = baton; 2104299742Sdim 2105299742Sdim /* Flush the data cached in APR, but don't close the file yet */ 2106299742Sdim SVN_ERR(svn_io_file_flush(ib->baton_apr.file, ib->baton_apr.pool)); 2107299742Sdim 2108299742Sdim return SVN_NO_ERROR; 2109299742Sdim} 2110299742Sdim 2111299742Sdim#endif /* WIN32 */ 2112299742Sdim 2113299742Sdimsvn_error_t * 2114299742Sdimsvn_stream__create_for_install(svn_stream_t **install_stream, 2115299742Sdim const char *tmp_abspath, 2116299742Sdim apr_pool_t *result_pool, 2117299742Sdim apr_pool_t *scratch_pool) 2118299742Sdim{ 2119299742Sdim apr_file_t *file; 2120299742Sdim struct install_baton_t *ib; 2121299742Sdim const char *tmp_path; 2122299742Sdim 2123299742Sdim#ifdef WIN32 2124299742Sdim HANDLE hInstall; 2125299742Sdim apr_status_t status; 2126299742Sdim 2127299742Sdim SVN_ERR_ASSERT(svn_dirent_is_absolute(tmp_abspath)); 2128299742Sdim 2129299742Sdim SVN_ERR(create_tempfile(&hInstall, &tmp_path, tmp_abspath, 2130299742Sdim scratch_pool, scratch_pool)); 2131299742Sdim 2132299742Sdim /* Wrap as a standard APR file to allow sharing implementation. 2133299742Sdim 2134299742Sdim But do note that some file functions (such as retrieving the name) 2135299742Sdim don't work on this wrapper. */ 2136299742Sdim /* ### Buffered, or not? */ 2137299742Sdim status = apr_os_file_put(&file, &hInstall, 2138299742Sdim APR_WRITE | APR_BINARY | APR_BUFFERED, 2139299742Sdim result_pool); 2140299742Sdim 2141299742Sdim if (status) 2142299742Sdim { 2143299742Sdim CloseHandle(hInstall); 2144299742Sdim return svn_error_wrap_apr(status, NULL); 2145299742Sdim } 2146299742Sdim 2147299742Sdim tmp_path = svn_dirent_internal_style(tmp_path, result_pool); 2148299742Sdim#else 2149299742Sdim 2150299742Sdim SVN_ERR_ASSERT(svn_dirent_is_absolute(tmp_abspath)); 2151299742Sdim 2152299742Sdim SVN_ERR(svn_io_open_unique_file3(&file, &tmp_path, tmp_abspath, 2153299742Sdim svn_io_file_del_none, 2154299742Sdim result_pool, scratch_pool)); 2155299742Sdim#endif 2156299742Sdim *install_stream = svn_stream_from_aprfile2(file, FALSE, result_pool); 2157299742Sdim 2158299742Sdim ib = apr_pcalloc(result_pool, sizeof(*ib)); 2159299742Sdim ib->baton_apr = *(struct baton_apr*)(*install_stream)->baton; 2160299742Sdim 2161299742Sdim assert((void*)&ib->baton_apr == (void*)ib); /* baton pointer is the same */ 2162299742Sdim 2163299742Sdim (*install_stream)->baton = ib; 2164299742Sdim 2165299742Sdim ib->tmp_path = tmp_path; 2166299742Sdim 2167299742Sdim#ifdef WIN32 2168299742Sdim /* Don't close the file on stream close; flush instead */ 2169299742Sdim svn_stream_set_close(*install_stream, install_close); 2170299742Sdim#else 2171299742Sdim /* ### Install pool cleanup handler for tempfile? */ 2172299742Sdim#endif 2173299742Sdim 2174299742Sdim return SVN_NO_ERROR; 2175299742Sdim} 2176299742Sdim 2177299742Sdimsvn_error_t * 2178299742Sdimsvn_stream__install_stream(svn_stream_t *install_stream, 2179299742Sdim const char *final_abspath, 2180299742Sdim svn_boolean_t make_parents, 2181299742Sdim apr_pool_t *scratch_pool) 2182299742Sdim{ 2183299742Sdim struct install_baton_t *ib = install_stream->baton; 2184299742Sdim svn_error_t *err; 2185299742Sdim 2186299742Sdim SVN_ERR_ASSERT(svn_dirent_is_absolute(final_abspath)); 2187299742Sdim#ifdef WIN32 2188299742Sdim err = svn_io__win_rename_open_file(ib->baton_apr.file, ib->tmp_path, 2189299742Sdim final_abspath, scratch_pool); 2190299742Sdim if (make_parents && err && APR_STATUS_IS_ENOENT(err->apr_err)) 2191299742Sdim { 2192299742Sdim svn_error_t *err2; 2193299742Sdim 2194299742Sdim err2 = svn_io_make_dir_recursively(svn_dirent_dirname(final_abspath, 2195299742Sdim scratch_pool), 2196299742Sdim scratch_pool); 2197299742Sdim 2198299742Sdim if (err2) 2199299742Sdim return svn_error_trace(svn_error_compose_create(err, err2)); 2200299742Sdim else 2201299742Sdim svn_error_clear(err); 2202299742Sdim 2203299742Sdim err = svn_io__win_rename_open_file(ib->baton_apr.file, ib->tmp_path, 2204299742Sdim final_abspath, scratch_pool); 2205299742Sdim } 2206299742Sdim 2207299742Sdim /* ### rhuijben: I wouldn't be surprised if we later find out that we 2208299742Sdim have to fall back to close+rename on some specific 2209299742Sdim error values here, to support some non standard NAS 2210299742Sdim and filesystem scenarios. */ 2211299742Sdim if (err && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE) 2212299742Sdim { 2213299742Sdim /* Rename open files is not supported on this platform: fallback to 2214299742Sdim svn_io_file_rename2(). */ 2215299742Sdim svn_error_clear(err); 2216299742Sdim err = SVN_NO_ERROR; 2217299742Sdim 2218299742Sdim SVN_ERR(svn_io_file_close(ib->baton_apr.file, scratch_pool)); 2219299742Sdim } 2220299742Sdim else 2221299742Sdim { 2222299742Sdim return svn_error_compose_create(err, 2223299742Sdim svn_io_file_close(ib->baton_apr.file, 2224299742Sdim scratch_pool)); 2225299742Sdim } 2226299742Sdim#endif 2227299742Sdim 2228299742Sdim err = svn_io_file_rename(ib->tmp_path, final_abspath, scratch_pool); 2229299742Sdim 2230299742Sdim /* A missing directory is too common to not cover here. */ 2231299742Sdim if (make_parents && err && APR_STATUS_IS_ENOENT(err->apr_err)) 2232299742Sdim { 2233299742Sdim svn_error_t *err2; 2234299742Sdim 2235299742Sdim err2 = svn_io_make_dir_recursively(svn_dirent_dirname(final_abspath, 2236299742Sdim scratch_pool), 2237299742Sdim scratch_pool); 2238299742Sdim 2239299742Sdim if (err2) 2240299742Sdim /* Creating directory didn't work: Return all errors */ 2241299742Sdim return svn_error_trace(svn_error_compose_create(err, err2)); 2242299742Sdim else 2243299742Sdim /* We could create a directory: retry install */ 2244299742Sdim svn_error_clear(err); 2245299742Sdim 2246299742Sdim SVN_ERR(svn_io_file_rename(ib->tmp_path, final_abspath, scratch_pool)); 2247299742Sdim } 2248299742Sdim else 2249299742Sdim SVN_ERR(err); 2250299742Sdim 2251299742Sdim return SVN_NO_ERROR; 2252299742Sdim} 2253299742Sdim 2254299742Sdimsvn_error_t * 2255299742Sdimsvn_stream__install_get_info(apr_finfo_t *finfo, 2256299742Sdim svn_stream_t *install_stream, 2257299742Sdim apr_int32_t wanted, 2258299742Sdim apr_pool_t *scratch_pool) 2259299742Sdim{ 2260299742Sdim struct install_baton_t *ib = install_stream->baton; 2261299742Sdim 2262299742Sdim#ifdef WIN32 2263299742Sdim /* On WIN32 the file is still open, so we can obtain the information 2264299742Sdim from the handle without race conditions */ 2265299742Sdim apr_status_t status; 2266299742Sdim 2267299742Sdim status = apr_file_info_get(finfo, wanted, ib->baton_apr.file); 2268299742Sdim 2269299742Sdim if (status) 2270299742Sdim return svn_error_wrap_apr(status, NULL); 2271299742Sdim#else 2272299742Sdim SVN_ERR(svn_io_stat(finfo, ib->tmp_path, wanted, scratch_pool)); 2273299742Sdim#endif 2274299742Sdim 2275299742Sdim return SVN_NO_ERROR; 2276299742Sdim} 2277299742Sdim 2278299742Sdimsvn_error_t * 2279299742Sdimsvn_stream__install_delete(svn_stream_t *install_stream, 2280299742Sdim apr_pool_t *scratch_pool) 2281299742Sdim{ 2282299742Sdim struct install_baton_t *ib = install_stream->baton; 2283299742Sdim 2284299742Sdim#ifdef WIN32 2285299742Sdim svn_error_t *err; 2286299742Sdim 2287299742Sdim /* Mark the file as delete on close to avoid having to reopen 2288299742Sdim the file as part of the delete handling. */ 2289299742Sdim err = svn_io__win_delete_file_on_close(ib->baton_apr.file, ib->tmp_path, 2290299742Sdim scratch_pool); 2291299742Sdim if (err == SVN_NO_ERROR) 2292299742Sdim { 2293299742Sdim SVN_ERR(svn_io_file_close(ib->baton_apr.file, scratch_pool)); 2294299742Sdim return SVN_NO_ERROR; /* File is already gone */ 2295299742Sdim } 2296299742Sdim 2297299742Sdim /* Deleting file on close may be unsupported, so ignore errors and 2298299742Sdim fallback to svn_io_remove_file2(). */ 2299299742Sdim svn_error_clear(err); 2300299742Sdim SVN_ERR(svn_io_file_close(ib->baton_apr.file, scratch_pool)); 2301299742Sdim#endif 2302299742Sdim 2303299742Sdim return svn_error_trace(svn_io_remove_file2(ib->tmp_path, FALSE, 2304299742Sdim scratch_pool)); 2305299742Sdim} 2306