stream.c revision 299742
1/* 2 * stream.c: svn_stream operations 3 * 4 * ==================================================================== 5 * Licensed to the Apache Software Foundation (ASF) under one 6 * or more contributor license agreements. See the NOTICE file 7 * distributed with this work for additional information 8 * regarding copyright ownership. The ASF licenses this file 9 * to you under the Apache License, Version 2.0 (the 10 * "License"); you may not use this file except in compliance 11 * with the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, 16 * software distributed under the License is distributed on an 17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 * KIND, either express or implied. See the License for the 19 * specific language governing permissions and limitations 20 * under the License. 21 * ==================================================================== 22 */ 23 24#include <assert.h> 25#include <stdio.h> 26 27#include <apr.h> 28#include <apr_pools.h> 29#include <apr_strings.h> 30#include <apr_file_io.h> 31#include <apr_errno.h> 32#include <apr_poll.h> 33#include <apr_portable.h> 34 35#include <zlib.h> 36 37#include "svn_pools.h" 38#include "svn_io.h" 39#include "svn_error.h" 40#include "svn_string.h" 41#include "svn_utf.h" 42#include "svn_checksum.h" 43#include "svn_path.h" 44#include "svn_private_config.h" 45#include "private/svn_atomic.h" 46#include "private/svn_error_private.h" 47#include "private/svn_eol_private.h" 48#include "private/svn_io_private.h" 49#include "private/svn_subr_private.h" 50#include "private/svn_utf_private.h" 51 52 53struct svn_stream_t { 54 void *baton; 55 svn_read_fn_t read_fn; 56 svn_read_fn_t read_full_fn; 57 svn_stream_skip_fn_t skip_fn; 58 svn_write_fn_t write_fn; 59 svn_close_fn_t close_fn; 60 svn_stream_mark_fn_t mark_fn; 61 svn_stream_seek_fn_t seek_fn; 62 svn_stream_data_available_fn_t data_available_fn; 63 svn_stream__is_buffered_fn_t is_buffered_fn; 64 apr_file_t *file; /* Maybe NULL */ 65}; 66 67 68/*** Forward declarations. ***/ 69 70static svn_error_t * 71skip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_full_fn); 72 73 74/*** Generic streams. ***/ 75 76svn_stream_t * 77svn_stream_create(void *baton, apr_pool_t *pool) 78{ 79 svn_stream_t *stream; 80 81 stream = apr_pcalloc(pool, sizeof(*stream)); 82 stream->baton = baton; 83 return stream; 84} 85 86 87void 88svn_stream_set_baton(svn_stream_t *stream, void *baton) 89{ 90 stream->baton = baton; 91} 92 93 94void 95svn_stream_set_read2(svn_stream_t *stream, 96 svn_read_fn_t read_fn, 97 svn_read_fn_t read_full_fn) 98{ 99 stream->read_fn = read_fn; 100 stream->read_full_fn = read_full_fn; 101} 102 103void 104svn_stream_set_skip(svn_stream_t *stream, svn_stream_skip_fn_t skip_fn) 105{ 106 stream->skip_fn = skip_fn; 107} 108 109void 110svn_stream_set_write(svn_stream_t *stream, svn_write_fn_t write_fn) 111{ 112 stream->write_fn = write_fn; 113} 114 115void 116svn_stream_set_close(svn_stream_t *stream, svn_close_fn_t close_fn) 117{ 118 stream->close_fn = close_fn; 119} 120 121void 122svn_stream_set_mark(svn_stream_t *stream, svn_stream_mark_fn_t mark_fn) 123{ 124 stream->mark_fn = mark_fn; 125} 126 127void 128svn_stream_set_seek(svn_stream_t *stream, svn_stream_seek_fn_t seek_fn) 129{ 130 stream->seek_fn = seek_fn; 131} 132 133void 134svn_stream_set_data_available(svn_stream_t *stream, 135 svn_stream_data_available_fn_t data_available_fn) 136{ 137 stream->data_available_fn = data_available_fn; 138} 139 140void 141svn_stream__set_is_buffered(svn_stream_t *stream, 142 svn_stream__is_buffered_fn_t is_buffered_fn) 143{ 144 stream->is_buffered_fn = is_buffered_fn; 145} 146 147/* Standard implementation for svn_stream_read_full() based on 148 multiple svn_stream_read2() calls (in separate function to make 149 it more likely for svn_stream_read_full to be inlined) */ 150static svn_error_t * 151full_read_fallback(svn_stream_t *stream, char *buffer, apr_size_t *len) 152{ 153 apr_size_t remaining = *len; 154 while (remaining > 0) 155 { 156 apr_size_t length = remaining; 157 SVN_ERR(svn_stream_read2(stream, buffer, &length)); 158 159 if (length == 0) 160 { 161 *len -= remaining; 162 return SVN_NO_ERROR; 163 } 164 165 remaining -= length; 166 buffer += length; 167 } 168 169 return SVN_NO_ERROR; 170} 171 172svn_boolean_t 173svn_stream_supports_partial_read(svn_stream_t *stream) 174{ 175 return stream->read_fn != NULL; 176} 177 178svn_error_t * 179svn_stream_read2(svn_stream_t *stream, char *buffer, apr_size_t *len) 180{ 181 if (stream->read_fn == NULL) 182 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, NULL, NULL); 183 184 return svn_error_trace(stream->read_fn(stream->baton, buffer, len)); 185} 186 187svn_error_t * 188svn_stream_read_full(svn_stream_t *stream, char *buffer, apr_size_t *len) 189{ 190 if (stream->read_full_fn == NULL) 191 return svn_error_trace(full_read_fallback(stream, buffer, len)); 192 193 return svn_error_trace(stream->read_full_fn(stream->baton, buffer, len)); 194} 195 196svn_error_t * 197svn_stream_skip(svn_stream_t *stream, apr_size_t len) 198{ 199 if (stream->skip_fn == NULL) 200 return svn_error_trace( 201 skip_default_handler(stream->baton, len, stream->read_full_fn)); 202 203 return svn_error_trace(stream->skip_fn(stream->baton, len)); 204} 205 206 207svn_error_t * 208svn_stream_write(svn_stream_t *stream, const char *data, apr_size_t *len) 209{ 210 if (stream->write_fn == NULL) 211 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, NULL, NULL); 212 213 return svn_error_trace(stream->write_fn(stream->baton, data, len)); 214} 215 216 217svn_error_t * 218svn_stream_reset(svn_stream_t *stream) 219{ 220 return svn_error_trace( 221 svn_stream_seek(stream, NULL)); 222} 223 224svn_boolean_t 225svn_stream_supports_mark(svn_stream_t *stream) 226{ 227 return stream->mark_fn != NULL; 228} 229 230svn_error_t * 231svn_stream_mark(svn_stream_t *stream, svn_stream_mark_t **mark, 232 apr_pool_t *pool) 233{ 234 if (stream->mark_fn == NULL) 235 return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL); 236 237 return svn_error_trace(stream->mark_fn(stream->baton, mark, pool)); 238} 239 240svn_error_t * 241svn_stream_seek(svn_stream_t *stream, const svn_stream_mark_t *mark) 242{ 243 if (stream->seek_fn == NULL) 244 return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL); 245 246 return svn_error_trace(stream->seek_fn(stream->baton, mark)); 247} 248 249svn_error_t * 250svn_stream_data_available(svn_stream_t *stream, 251 svn_boolean_t *data_available) 252{ 253 if (stream->data_available_fn == NULL) 254 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, NULL, NULL); 255 256 return svn_error_trace(stream->data_available_fn(stream->baton, 257 data_available)); 258} 259 260svn_boolean_t 261svn_stream__is_buffered(svn_stream_t *stream) 262{ 263 if (stream->is_buffered_fn == NULL) 264 return FALSE; 265 266 return stream->is_buffered_fn(stream->baton); 267} 268 269svn_error_t * 270svn_stream_close(svn_stream_t *stream) 271{ 272 if (stream->close_fn == NULL) 273 return SVN_NO_ERROR; 274 return svn_error_trace(stream->close_fn(stream->baton)); 275} 276 277svn_error_t * 278svn_stream_puts(svn_stream_t *stream, 279 const char *str) 280{ 281 apr_size_t len; 282 len = strlen(str); 283 return svn_error_trace(svn_stream_write(stream, str, &len)); 284} 285 286svn_error_t * 287svn_stream_printf(svn_stream_t *stream, 288 apr_pool_t *pool, 289 const char *fmt, 290 ...) 291{ 292 const char *message; 293 va_list ap; 294 295 va_start(ap, fmt); 296 message = apr_pvsprintf(pool, fmt, ap); 297 va_end(ap); 298 299 return svn_error_trace(svn_stream_puts(stream, message)); 300} 301 302 303svn_error_t * 304svn_stream_printf_from_utf8(svn_stream_t *stream, 305 const char *encoding, 306 apr_pool_t *pool, 307 const char *fmt, 308 ...) 309{ 310 const char *message, *translated; 311 va_list ap; 312 313 va_start(ap, fmt); 314 message = apr_pvsprintf(pool, fmt, ap); 315 va_end(ap); 316 317 SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated, message, encoding, 318 pool)); 319 320 return svn_error_trace(svn_stream_puts(stream, translated)); 321} 322 323/* Guts of svn_stream_readline(). 324 * Returns the line read from STREAM in *STRINGBUF, and indicates 325 * end-of-file in *EOF. If DETECT_EOL is TRUE, the end-of-line indicator 326 * is detected automatically and returned in *EOL. 327 * If DETECT_EOL is FALSE, *EOL must point to the desired end-of-line 328 * indicator. STRINGBUF is allocated in POOL. */ 329static svn_error_t * 330stream_readline_bytewise(svn_stringbuf_t **stringbuf, 331 svn_boolean_t *eof, 332 const char *eol, 333 svn_stream_t *stream, 334 apr_pool_t *pool) 335{ 336 svn_stringbuf_t *str; 337 apr_size_t numbytes; 338 const char *match; 339 char c; 340 341 /* Since we're reading one character at a time, let's at least 342 optimize for the 90% case. 90% of the time, we can avoid the 343 stringbuf ever having to realloc() itself if we start it out at 344 80 chars. */ 345 str = svn_stringbuf_create_ensure(SVN__LINE_CHUNK_SIZE, pool); 346 347 /* Read into STR up to and including the next EOL sequence. */ 348 match = eol; 349 while (*match) 350 { 351 numbytes = 1; 352 SVN_ERR(svn_stream_read_full(stream, &c, &numbytes)); 353 if (numbytes != 1) 354 { 355 /* a 'short' read means the stream has run out. */ 356 *eof = TRUE; 357 *stringbuf = str; 358 return SVN_NO_ERROR; 359 } 360 361 if (c == *match) 362 match++; 363 else 364 match = eol; 365 366 svn_stringbuf_appendbyte(str, c); 367 } 368 369 *eof = FALSE; 370 svn_stringbuf_chop(str, match - eol); 371 *stringbuf = str; 372 373 return SVN_NO_ERROR; 374} 375 376static svn_error_t * 377stream_readline_chunky(svn_stringbuf_t **stringbuf, 378 svn_boolean_t *eof, 379 const char *eol, 380 svn_stream_t *stream, 381 apr_pool_t *pool) 382{ 383 /* Read larger chunks of data at once into this buffer and scan 384 * that for EOL. A good chunk size should be about 80 chars since 385 * most text lines will be shorter. However, don't use a much 386 * larger value because filling the buffer from the stream takes 387 * time as well. 388 */ 389 char buffer[SVN__LINE_CHUNK_SIZE+1]; 390 391 /* variables */ 392 svn_stream_mark_t *mark; 393 apr_size_t numbytes; 394 const char *eol_pos; 395 apr_size_t total_parsed = 0; 396 397 /* invariant for this call */ 398 const size_t eol_len = strlen(eol); 399 400 /* Remember the line start so this plus the line length will be 401 * the position to move to at the end of this function. 402 */ 403 SVN_ERR(svn_stream_mark(stream, &mark, pool)); 404 405 /* Read the first chunk. */ 406 numbytes = SVN__LINE_CHUNK_SIZE; 407 SVN_ERR(svn_stream_read_full(stream, buffer, &numbytes)); 408 buffer[numbytes] = '\0'; 409 410 /* Look for the EOL in this first chunk. If we find it, we are done here. 411 */ 412 eol_pos = strstr(buffer, eol); 413 if (eol_pos != NULL) 414 { 415 *stringbuf = svn_stringbuf_ncreate(buffer, eol_pos - buffer, pool); 416 total_parsed = eol_pos - buffer + eol_len; 417 } 418 else if (numbytes < SVN__LINE_CHUNK_SIZE) 419 { 420 /* We hit EOF but not EOL. 421 */ 422 *stringbuf = svn_stringbuf_ncreate(buffer, numbytes, pool); 423 *eof = TRUE; 424 return SVN_NO_ERROR; 425 } 426 else 427 { 428 /* A larger buffer for the string is needed. */ 429 svn_stringbuf_t *str; 430 str = svn_stringbuf_create_ensure(2*SVN__LINE_CHUNK_SIZE, pool); 431 svn_stringbuf_appendbytes(str, buffer, numbytes); 432 *stringbuf = str; 433 434 /* Loop reading chunks until an EOL was found. If we hit EOF, fall 435 * back to the standard implementation. */ 436 do 437 { 438 /* Append the next chunk to the string read so far. 439 */ 440 svn_stringbuf_ensure(str, str->len + SVN__LINE_CHUNK_SIZE); 441 numbytes = SVN__LINE_CHUNK_SIZE; 442 SVN_ERR(svn_stream_read_full(stream, str->data + str->len, &numbytes)); 443 str->len += numbytes; 444 str->data[str->len] = '\0'; 445 446 /* Look for the EOL in the new data plus the last part of the 447 * previous chunk because the EOL may span over the boundary 448 * between both chunks. 449 */ 450 eol_pos = strstr(str->data + str->len - numbytes - (eol_len-1), eol); 451 452 if ((numbytes < SVN__LINE_CHUNK_SIZE) && (eol_pos == NULL)) 453 { 454 /* We hit EOF instead of EOL. */ 455 *eof = TRUE; 456 return SVN_NO_ERROR; 457 } 458 } 459 while (eol_pos == NULL); 460 461 /* Number of bytes we actually consumed (i.e. line + EOF). 462 * We need to "return" the rest to the stream by moving its 463 * read pointer. 464 */ 465 total_parsed = eol_pos - str->data + eol_len; 466 467 /* Terminate the string at the EOL postion and return it. */ 468 str->len = eol_pos - str->data; 469 str->data[str->len] = 0; 470 } 471 472 /* Move the stream read pointer to the first position behind the EOL. 473 */ 474 SVN_ERR(svn_stream_seek(stream, mark)); 475 return svn_error_trace(svn_stream_skip(stream, total_parsed)); 476} 477 478/* Guts of svn_stream_readline(). 479 * Returns the line read from STREAM in *STRINGBUF, and indicates 480 * end-of-file in *EOF. EOL must point to the desired end-of-line 481 * indicator. STRINGBUF is allocated in POOL. */ 482static svn_error_t * 483stream_readline(svn_stringbuf_t **stringbuf, 484 svn_boolean_t *eof, 485 const char *eol, 486 svn_stream_t *stream, 487 apr_pool_t *pool) 488{ 489 *eof = FALSE; 490 491 /* Often, we operate on APR file or string-based streams and know what 492 * EOL we are looking for. Optimize that common case. 493 */ 494 if (svn_stream_supports_mark(stream) && 495 svn_stream__is_buffered(stream)) 496 { 497 /* We can efficiently read chunks speculatively and reposition the 498 * stream pointer to the end of the line once we found that. 499 */ 500 SVN_ERR(stream_readline_chunky(stringbuf, 501 eof, 502 eol, 503 stream, 504 pool)); 505 } 506 else 507 { 508 /* Use the standard byte-byte implementation. 509 */ 510 SVN_ERR(stream_readline_bytewise(stringbuf, 511 eof, 512 eol, 513 stream, 514 pool)); 515 } 516 517 return SVN_NO_ERROR; 518} 519 520svn_error_t * 521svn_stream_readline(svn_stream_t *stream, 522 svn_stringbuf_t **stringbuf, 523 const char *eol, 524 svn_boolean_t *eof, 525 apr_pool_t *pool) 526{ 527 return svn_error_trace(stream_readline(stringbuf, eof, eol, stream, 528 pool)); 529} 530 531svn_error_t *svn_stream_copy3(svn_stream_t *from, svn_stream_t *to, 532 svn_cancel_func_t cancel_func, 533 void *cancel_baton, 534 apr_pool_t *scratch_pool) 535{ 536 char *buf = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE); 537 svn_error_t *err; 538 svn_error_t *err2; 539 540 /* Read and write chunks until we get a short read, indicating the 541 end of the stream. (We can't get a short write without an 542 associated error.) */ 543 while (1) 544 { 545 apr_size_t len = SVN__STREAM_CHUNK_SIZE; 546 547 if (cancel_func) 548 { 549 err = cancel_func(cancel_baton); 550 if (err) 551 break; 552 } 553 554 err = svn_stream_read_full(from, buf, &len); 555 if (err) 556 break; 557 558 if (len > 0) 559 err = svn_stream_write(to, buf, &len); 560 561 if (err || (len != SVN__STREAM_CHUNK_SIZE)) 562 break; 563 } 564 565 err2 = svn_error_compose_create(svn_stream_close(from), 566 svn_stream_close(to)); 567 568 return svn_error_compose_create(err, err2); 569} 570 571svn_error_t * 572svn_stream_contents_same2(svn_boolean_t *same, 573 svn_stream_t *stream1, 574 svn_stream_t *stream2, 575 apr_pool_t *pool) 576{ 577 char *buf1 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); 578 char *buf2 = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); 579 apr_size_t bytes_read1 = SVN__STREAM_CHUNK_SIZE; 580 apr_size_t bytes_read2 = SVN__STREAM_CHUNK_SIZE; 581 svn_error_t *err = NULL; 582 583 *same = TRUE; /* assume TRUE, until disproved below */ 584 while (bytes_read1 == SVN__STREAM_CHUNK_SIZE 585 && bytes_read2 == SVN__STREAM_CHUNK_SIZE) 586 { 587 err = svn_stream_read_full(stream1, buf1, &bytes_read1); 588 if (err) 589 break; 590 err = svn_stream_read_full(stream2, buf2, &bytes_read2); 591 if (err) 592 break; 593 594 if ((bytes_read1 != bytes_read2) 595 || (memcmp(buf1, buf2, bytes_read1))) 596 { 597 *same = FALSE; 598 break; 599 } 600 } 601 602 return svn_error_compose_create(err, 603 svn_error_compose_create( 604 svn_stream_close(stream1), 605 svn_stream_close(stream2))); 606} 607 608 609/*** Stream implementation utilities ***/ 610 611/* Skip data from any stream by reading and simply discarding it. */ 612static svn_error_t * 613skip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_full_fn) 614{ 615 apr_size_t bytes_read = 1; 616 char buffer[4096]; 617 apr_size_t to_read = len; 618 619 while ((to_read > 0) && (bytes_read > 0)) 620 { 621 bytes_read = sizeof(buffer) < to_read ? sizeof(buffer) : to_read; 622 SVN_ERR(read_full_fn(baton, buffer, &bytes_read)); 623 to_read -= bytes_read; 624 } 625 626 return SVN_NO_ERROR; 627} 628 629 630 631/*** Generic readable empty stream ***/ 632 633static svn_error_t * 634read_handler_empty(void *baton, char *buffer, apr_size_t *len) 635{ 636 *len = 0; 637 return SVN_NO_ERROR; 638} 639 640static svn_error_t * 641write_handler_empty(void *baton, const char *data, apr_size_t *len) 642{ 643 return SVN_NO_ERROR; 644} 645 646static svn_error_t * 647mark_handler_empty(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 648{ 649 *mark = NULL; /* Seek to start of stream marker */ 650 return SVN_NO_ERROR; 651} 652 653static svn_error_t * 654seek_handler_empty(void *baton, const svn_stream_mark_t *mark) 655{ 656 return SVN_NO_ERROR; 657} 658 659static svn_boolean_t 660is_buffered_handler_empty(void *baton) 661{ 662 return FALSE; 663} 664 665 666svn_stream_t * 667svn_stream_empty(apr_pool_t *pool) 668{ 669 svn_stream_t *stream; 670 671 stream = svn_stream_create(NULL, pool); 672 svn_stream_set_read2(stream, read_handler_empty, read_handler_empty); 673 svn_stream_set_write(stream, write_handler_empty); 674 svn_stream_set_mark(stream, mark_handler_empty); 675 svn_stream_set_seek(stream, seek_handler_empty); 676 svn_stream__set_is_buffered(stream, is_buffered_handler_empty); 677 return stream; 678} 679 680 681 682/*** Stream duplication support ***/ 683struct baton_tee { 684 svn_stream_t *out1; 685 svn_stream_t *out2; 686}; 687 688 689static svn_error_t * 690write_handler_tee(void *baton, const char *data, apr_size_t *len) 691{ 692 struct baton_tee *bt = baton; 693 694 SVN_ERR(svn_stream_write(bt->out1, data, len)); 695 SVN_ERR(svn_stream_write(bt->out2, data, len)); 696 697 return SVN_NO_ERROR; 698} 699 700 701static svn_error_t * 702close_handler_tee(void *baton) 703{ 704 struct baton_tee *bt = baton; 705 706 SVN_ERR(svn_stream_close(bt->out1)); 707 SVN_ERR(svn_stream_close(bt->out2)); 708 709 return SVN_NO_ERROR; 710} 711 712 713svn_stream_t * 714svn_stream_tee(svn_stream_t *out1, 715 svn_stream_t *out2, 716 apr_pool_t *pool) 717{ 718 struct baton_tee *baton; 719 svn_stream_t *stream; 720 721 if (out1 == NULL) 722 return out2; 723 724 if (out2 == NULL) 725 return out1; 726 727 baton = apr_palloc(pool, sizeof(*baton)); 728 baton->out1 = out1; 729 baton->out2 = out2; 730 stream = svn_stream_create(baton, pool); 731 svn_stream_set_write(stream, write_handler_tee); 732 svn_stream_set_close(stream, close_handler_tee); 733 734 return stream; 735} 736 737 738 739/*** Ownership detaching stream ***/ 740 741static svn_error_t * 742read_handler_disown(void *baton, char *buffer, apr_size_t *len) 743{ 744 return svn_error_trace(svn_stream_read2(baton, buffer, len)); 745} 746 747static svn_error_t * 748read_full_handler_disown(void *baton, char *buffer, apr_size_t *len) 749{ 750 return svn_error_trace(svn_stream_read_full(baton, buffer, len)); 751} 752 753static svn_error_t * 754skip_handler_disown(void *baton, apr_size_t len) 755{ 756 return svn_error_trace(svn_stream_skip(baton, len)); 757} 758 759static svn_error_t * 760write_handler_disown(void *baton, const char *buffer, apr_size_t *len) 761{ 762 return svn_error_trace(svn_stream_write(baton, buffer, len)); 763} 764 765static svn_error_t * 766mark_handler_disown(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 767{ 768 return svn_error_trace(svn_stream_mark(baton, mark, pool)); 769} 770 771static svn_error_t * 772seek_handler_disown(void *baton, const svn_stream_mark_t *mark) 773{ 774 return svn_error_trace(svn_stream_seek(baton, mark)); 775} 776 777static svn_error_t * 778data_available_disown(void *baton, svn_boolean_t *data_available) 779{ 780 return svn_error_trace(svn_stream_data_available(baton, data_available)); 781} 782 783static svn_boolean_t 784is_buffered_handler_disown(void *baton) 785{ 786 return svn_stream__is_buffered(baton); 787} 788 789svn_stream_t * 790svn_stream_disown(svn_stream_t *stream, apr_pool_t *pool) 791{ 792 svn_stream_t *s = svn_stream_create(stream, pool); 793 794 svn_stream_set_read2(s, read_handler_disown, read_full_handler_disown); 795 svn_stream_set_skip(s, skip_handler_disown); 796 svn_stream_set_write(s, write_handler_disown); 797 svn_stream_set_mark(s, mark_handler_disown); 798 svn_stream_set_seek(s, seek_handler_disown); 799 svn_stream_set_data_available(s, data_available_disown); 800 svn_stream__set_is_buffered(s, is_buffered_handler_disown); 801 802 return s; 803} 804 805 806 807/*** Generic stream for APR files ***/ 808struct baton_apr { 809 apr_file_t *file; 810 apr_pool_t *pool; 811}; 812 813/* svn_stream_mark_t for streams backed by APR files. */ 814struct mark_apr { 815 apr_off_t off; 816}; 817 818static svn_error_t * 819read_handler_apr(void *baton, char *buffer, apr_size_t *len) 820{ 821 struct baton_apr *btn = baton; 822 svn_error_t *err; 823 824 if (*len == 1) 825 { 826 err = svn_io_file_getc(buffer, btn->file, btn->pool); 827 if (err) 828 { 829 *len = 0; 830 if (APR_STATUS_IS_EOF(err->apr_err)) 831 { 832 svn_error_clear(err); 833 err = SVN_NO_ERROR; 834 } 835 } 836 } 837 else 838 { 839 err = svn_io_file_read(btn->file, buffer, len, btn->pool); 840 if (err && APR_STATUS_IS_EOF(err->apr_err)) 841 { 842 svn_error_clear(err); 843 err = NULL; 844 } 845 } 846 847 return svn_error_trace(err); 848} 849 850static svn_error_t * 851read_full_handler_apr(void *baton, char *buffer, apr_size_t *len) 852{ 853 struct baton_apr *btn = baton; 854 svn_error_t *err; 855 svn_boolean_t eof; 856 857 if (*len == 1) 858 { 859 err = svn_io_file_getc(buffer, btn->file, btn->pool); 860 if (err) 861 { 862 *len = 0; 863 if (APR_STATUS_IS_EOF(err->apr_err)) 864 { 865 svn_error_clear(err); 866 err = SVN_NO_ERROR; 867 } 868 } 869 } 870 else 871 err = svn_io_file_read_full2(btn->file, buffer, *len, len, 872 &eof, btn->pool); 873 874 return svn_error_trace(err); 875} 876 877static svn_error_t * 878skip_handler_apr(void *baton, apr_size_t len) 879{ 880 struct baton_apr *btn = baton; 881 apr_off_t offset = len; 882 883 return svn_error_trace( 884 svn_io_file_seek(btn->file, APR_CUR, &offset, btn->pool)); 885} 886 887static svn_error_t * 888write_handler_apr(void *baton, const char *data, apr_size_t *len) 889{ 890 struct baton_apr *btn = baton; 891 svn_error_t *err; 892 893 if (*len == 1) 894 { 895 err = svn_io_file_putc(*data, btn->file, btn->pool); 896 if (err) 897 *len = 0; 898 } 899 else 900 err = svn_io_file_write_full(btn->file, data, *len, len, btn->pool); 901 902 return svn_error_trace(err); 903} 904 905static svn_error_t * 906close_handler_apr(void *baton) 907{ 908 struct baton_apr *btn = baton; 909 910 return svn_error_trace(svn_io_file_close(btn->file, btn->pool)); 911} 912 913static svn_error_t * 914mark_handler_apr(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 915{ 916 struct baton_apr *btn = baton; 917 struct mark_apr *mark_apr; 918 919 mark_apr = apr_palloc(pool, sizeof(*mark_apr)); 920 mark_apr->off = 0; 921 SVN_ERR(svn_io_file_seek(btn->file, APR_CUR, &mark_apr->off, btn->pool)); 922 *mark = (svn_stream_mark_t *)mark_apr; 923 return SVN_NO_ERROR; 924} 925 926static svn_error_t * 927seek_handler_apr(void *baton, const svn_stream_mark_t *mark) 928{ 929 struct baton_apr *btn = baton; 930 apr_off_t offset = (mark != NULL) ? ((const struct mark_apr *)mark)->off : 0; 931 932 SVN_ERR(svn_io_file_seek(btn->file, APR_SET, &offset, btn->pool)); 933 934 return SVN_NO_ERROR; 935} 936 937static svn_error_t * 938data_available_handler_apr(void *baton, svn_boolean_t *data_available) 939{ 940 struct baton_apr *btn = baton; 941 apr_status_t status; 942#if !defined(WIN32) || APR_FILES_AS_SOCKETS 943 apr_pollfd_t pfd; 944 int n; 945 946 pfd.desc_type = APR_POLL_FILE; 947 pfd.desc.f = btn->file; 948 pfd.p = btn->pool; /* If we had a scratch pool... Luckily apr doesn't 949 store anything in this pool at this time */ 950 pfd.reqevents = APR_POLLIN; 951 952 status = apr_poll(&pfd, 1, &n, 0); 953 954 if (status == APR_SUCCESS) 955 { 956 *data_available = (n > 0); 957 return SVN_NO_ERROR; 958 } 959 else if (APR_STATUS_IS_EOF(status) || APR_STATUS_IS_TIMEUP(status)) 960 { 961 *data_available = FALSE; 962 return SVN_NO_ERROR; 963 } 964 else 965 { 966 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, 967 svn_error_wrap_apr( 968 status, 969 _("Polling for available data on filestream " 970 "failed")), 971 NULL); 972 } 973#else 974 HANDLE h; 975 DWORD dwAvail; 976 status = apr_os_file_get(&h, btn->file); 977 978 if (status) 979 return svn_error_wrap_apr(status, NULL); 980 981 if (PeekNamedPipe(h, NULL, 0, NULL, &dwAvail, NULL)) 982 { 983 *data_available = (dwAvail > 0); 984 return SVN_NO_ERROR; 985 } 986 987 return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, 988 svn_error_wrap_apr(apr_get_os_error(), NULL), 989 _("Windows doesn't support polling on files")); 990#endif 991} 992 993static svn_boolean_t 994is_buffered_handler_apr(void *baton) 995{ 996 struct baton_apr *btn = baton; 997 return (apr_file_flags_get(btn->file) & APR_BUFFERED) != 0; 998} 999 1000svn_error_t * 1001svn_stream_open_readonly(svn_stream_t **stream, 1002 const char *path, 1003 apr_pool_t *result_pool, 1004 apr_pool_t *scratch_pool) 1005{ 1006 apr_file_t *file; 1007 1008 SVN_ERR(svn_io_file_open(&file, path, APR_READ | APR_BUFFERED, 1009 APR_OS_DEFAULT, result_pool)); 1010 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool); 1011 1012 return SVN_NO_ERROR; 1013} 1014 1015 1016svn_error_t * 1017svn_stream_open_writable(svn_stream_t **stream, 1018 const char *path, 1019 apr_pool_t *result_pool, 1020 apr_pool_t *scratch_pool) 1021{ 1022 apr_file_t *file; 1023 1024 SVN_ERR(svn_io_file_open(&file, path, 1025 APR_WRITE 1026 | APR_BUFFERED 1027 | APR_CREATE 1028 | APR_EXCL, 1029 APR_OS_DEFAULT, result_pool)); 1030 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool); 1031 1032 return SVN_NO_ERROR; 1033} 1034 1035 1036svn_error_t * 1037svn_stream_open_unique(svn_stream_t **stream, 1038 const char **temp_path, 1039 const char *dirpath, 1040 svn_io_file_del_t delete_when, 1041 apr_pool_t *result_pool, 1042 apr_pool_t *scratch_pool) 1043{ 1044 apr_file_t *file; 1045 1046 SVN_ERR(svn_io_open_unique_file3(&file, temp_path, dirpath, 1047 delete_when, result_pool, scratch_pool)); 1048 *stream = svn_stream_from_aprfile2(file, FALSE, result_pool); 1049 1050 return SVN_NO_ERROR; 1051} 1052 1053 1054/* Helper function that creates a stream from an APR file. */ 1055static svn_stream_t * 1056make_stream_from_apr_file(apr_file_t *file, 1057 svn_boolean_t disown, 1058 svn_boolean_t supports_seek, 1059 apr_pool_t *pool) 1060{ 1061 struct baton_apr *baton; 1062 svn_stream_t *stream; 1063 1064 if (file == NULL) 1065 return svn_stream_empty(pool); 1066 1067 baton = apr_palloc(pool, sizeof(*baton)); 1068 baton->file = file; 1069 baton->pool = pool; 1070 stream = svn_stream_create(baton, pool); 1071 svn_stream_set_read2(stream, read_handler_apr, read_full_handler_apr); 1072 svn_stream_set_write(stream, write_handler_apr); 1073 1074 if (supports_seek) 1075 { 1076 svn_stream_set_skip(stream, skip_handler_apr); 1077 svn_stream_set_mark(stream, mark_handler_apr); 1078 svn_stream_set_seek(stream, seek_handler_apr); 1079 } 1080 1081 svn_stream_set_data_available(stream, data_available_handler_apr); 1082 svn_stream__set_is_buffered(stream, is_buffered_handler_apr); 1083 stream->file = file; 1084 1085 if (! disown) 1086 svn_stream_set_close(stream, close_handler_apr); 1087 1088 return stream; 1089} 1090 1091svn_stream_t * 1092svn_stream_from_aprfile2(apr_file_t *file, 1093 svn_boolean_t disown, 1094 apr_pool_t *pool) 1095{ 1096 return make_stream_from_apr_file(file, disown, TRUE, pool); 1097} 1098 1099apr_file_t * 1100svn_stream__aprfile(svn_stream_t *stream) 1101{ 1102 return stream->file; 1103} 1104 1105 1106/* Compressed stream support */ 1107 1108#define ZBUFFER_SIZE 4096 /* The size of the buffer the 1109 compressed stream uses to read from 1110 the substream. Basically an 1111 arbitrary value, picked to be about 1112 page-sized. */ 1113 1114struct zbaton { 1115 z_stream *in; /* compressed stream for reading */ 1116 z_stream *out; /* compressed stream for writing */ 1117 void *substream; /* The substream */ 1118 void *read_buffer; /* buffer used for reading from 1119 substream */ 1120 int read_flush; /* what flush mode to use while 1121 reading */ 1122 apr_pool_t *pool; /* The pool this baton is allocated 1123 on */ 1124}; 1125 1126/* zlib alloc function. opaque is the pool we need. */ 1127static voidpf 1128zalloc(voidpf opaque, uInt items, uInt size) 1129{ 1130 apr_pool_t *pool = opaque; 1131 1132 return apr_palloc(pool, items * size); 1133} 1134 1135/* zlib free function */ 1136static void 1137zfree(voidpf opaque, voidpf address) 1138{ 1139 /* Empty, since we allocate on the pool */ 1140} 1141 1142/* Helper function to figure out the sync mode */ 1143static svn_error_t * 1144read_helper_gz(svn_stream_t *substream, 1145 char *buffer, 1146 uInt *len, int *zflush) 1147{ 1148 uInt orig_len = *len; 1149 1150 /* There's no reason this value should grow bigger than the range of 1151 uInt, but Subversion's API requires apr_size_t. */ 1152 apr_size_t apr_len = (apr_size_t) *len; 1153 1154 SVN_ERR(svn_stream_read_full(substream, buffer, &apr_len)); 1155 1156 /* Type cast back to uInt type that zlib uses. On LP64 platforms 1157 apr_size_t will be bigger than uInt. */ 1158 *len = (uInt) apr_len; 1159 1160 /* I wanted to use Z_FINISH here, but we need to know our buffer is 1161 big enough */ 1162 *zflush = (*len) < orig_len ? Z_SYNC_FLUSH : Z_SYNC_FLUSH; 1163 1164 return SVN_NO_ERROR; 1165} 1166 1167/* Handle reading from a compressed stream */ 1168static svn_error_t * 1169read_handler_gz(void *baton, char *buffer, apr_size_t *len) 1170{ 1171 struct zbaton *btn = baton; 1172 int zerr; 1173 1174 if (btn->in == NULL) 1175 { 1176 btn->in = apr_palloc(btn->pool, sizeof(z_stream)); 1177 btn->in->zalloc = zalloc; 1178 btn->in->zfree = zfree; 1179 btn->in->opaque = btn->pool; 1180 btn->read_buffer = apr_palloc(btn->pool, ZBUFFER_SIZE); 1181 btn->in->next_in = btn->read_buffer; 1182 btn->in->avail_in = ZBUFFER_SIZE; 1183 1184 SVN_ERR(read_helper_gz(btn->substream, btn->read_buffer, 1185 &btn->in->avail_in, &btn->read_flush)); 1186 1187 zerr = inflateInit(btn->in); 1188 SVN_ERR(svn_error__wrap_zlib(zerr, "inflateInit", btn->in->msg)); 1189 } 1190 1191 btn->in->next_out = (Bytef *) buffer; 1192 btn->in->avail_out = (uInt) *len; 1193 1194 while (btn->in->avail_out > 0) 1195 { 1196 if (btn->in->avail_in <= 0) 1197 { 1198 btn->in->avail_in = ZBUFFER_SIZE; 1199 btn->in->next_in = btn->read_buffer; 1200 SVN_ERR(read_helper_gz(btn->substream, btn->read_buffer, 1201 &btn->in->avail_in, &btn->read_flush)); 1202 } 1203 1204 /* Short read means underlying stream has run out. */ 1205 if (btn->in->avail_in == 0) 1206 { 1207 *len = 0; 1208 return SVN_NO_ERROR; 1209 } 1210 1211 zerr = inflate(btn->in, btn->read_flush); 1212 if (zerr == Z_STREAM_END) 1213 break; 1214 else if (zerr != Z_OK) 1215 return svn_error_trace(svn_error__wrap_zlib(zerr, "inflate", 1216 btn->in->msg)); 1217 } 1218 1219 *len -= btn->in->avail_out; 1220 return SVN_NO_ERROR; 1221} 1222 1223/* Compress data and write it to the substream */ 1224static svn_error_t * 1225write_handler_gz(void *baton, const char *buffer, apr_size_t *len) 1226{ 1227 struct zbaton *btn = baton; 1228 apr_pool_t *subpool; 1229 void *write_buf; 1230 apr_size_t buf_size, write_len; 1231 int zerr; 1232 1233 if (btn->out == NULL) 1234 { 1235 btn->out = apr_palloc(btn->pool, sizeof(z_stream)); 1236 btn->out->zalloc = zalloc; 1237 btn->out->zfree = zfree; 1238 btn->out->opaque = btn->pool; 1239 1240 zerr = deflateInit(btn->out, Z_DEFAULT_COMPRESSION); 1241 SVN_ERR(svn_error__wrap_zlib(zerr, "deflateInit", btn->out->msg)); 1242 } 1243 1244 /* The largest buffer we should need is 0.1% larger than the 1245 compressed data, + 12 bytes. This info comes from zlib.h. */ 1246 buf_size = *len + (*len / 1000) + 13; 1247 subpool = svn_pool_create(btn->pool); 1248 write_buf = apr_palloc(subpool, buf_size); 1249 1250 btn->out->next_in = (Bytef *) buffer; /* Casting away const! */ 1251 btn->out->avail_in = (uInt) *len; 1252 1253 while (btn->out->avail_in > 0) 1254 { 1255 btn->out->next_out = write_buf; 1256 btn->out->avail_out = (uInt) buf_size; 1257 1258 zerr = deflate(btn->out, Z_NO_FLUSH); 1259 SVN_ERR(svn_error__wrap_zlib(zerr, "deflate", btn->out->msg)); 1260 write_len = buf_size - btn->out->avail_out; 1261 if (write_len > 0) 1262 SVN_ERR(svn_stream_write(btn->substream, write_buf, &write_len)); 1263 } 1264 1265 svn_pool_destroy(subpool); 1266 1267 return SVN_NO_ERROR; 1268} 1269 1270/* Handle flushing and closing the stream */ 1271static svn_error_t * 1272close_handler_gz(void *baton) 1273{ 1274 struct zbaton *btn = baton; 1275 int zerr; 1276 1277 if (btn->in != NULL) 1278 { 1279 zerr = inflateEnd(btn->in); 1280 SVN_ERR(svn_error__wrap_zlib(zerr, "inflateEnd", btn->in->msg)); 1281 } 1282 1283 if (btn->out != NULL) 1284 { 1285 void *buf; 1286 apr_size_t write_len; 1287 1288 buf = apr_palloc(btn->pool, ZBUFFER_SIZE); 1289 1290 while (TRUE) 1291 { 1292 btn->out->next_out = buf; 1293 btn->out->avail_out = ZBUFFER_SIZE; 1294 1295 zerr = deflate(btn->out, Z_FINISH); 1296 if (zerr != Z_STREAM_END && zerr != Z_OK) 1297 return svn_error_trace(svn_error__wrap_zlib(zerr, "deflate", 1298 btn->out->msg)); 1299 write_len = ZBUFFER_SIZE - btn->out->avail_out; 1300 if (write_len > 0) 1301 SVN_ERR(svn_stream_write(btn->substream, buf, &write_len)); 1302 if (zerr == Z_STREAM_END) 1303 break; 1304 } 1305 1306 zerr = deflateEnd(btn->out); 1307 SVN_ERR(svn_error__wrap_zlib(zerr, "deflateEnd", btn->out->msg)); 1308 } 1309 1310 return svn_error_trace(svn_stream_close(btn->substream)); 1311} 1312 1313 1314svn_stream_t * 1315svn_stream_compressed(svn_stream_t *stream, apr_pool_t *pool) 1316{ 1317 struct svn_stream_t *zstream; 1318 struct zbaton *baton; 1319 1320 assert(stream != NULL); 1321 1322 baton = apr_palloc(pool, sizeof(*baton)); 1323 baton->in = baton->out = NULL; 1324 baton->substream = stream; 1325 baton->pool = pool; 1326 baton->read_buffer = NULL; 1327 baton->read_flush = Z_SYNC_FLUSH; 1328 1329 zstream = svn_stream_create(baton, pool); 1330 svn_stream_set_read2(zstream, NULL /* only full read support */, 1331 read_handler_gz); 1332 svn_stream_set_write(zstream, write_handler_gz); 1333 svn_stream_set_close(zstream, close_handler_gz); 1334 1335 return zstream; 1336} 1337 1338 1339/* Checksummed stream support */ 1340 1341struct checksum_stream_baton 1342{ 1343 svn_checksum_ctx_t *read_ctx, *write_ctx; 1344 svn_checksum_t **read_checksum; /* Output value. */ 1345 svn_checksum_t **write_checksum; /* Output value. */ 1346 svn_stream_t *proxy; 1347 1348 /* True if more data should be read when closing the stream. */ 1349 svn_boolean_t read_more; 1350 1351 /* Pool to allocate read buffer and output values from. */ 1352 apr_pool_t *pool; 1353}; 1354 1355static svn_error_t * 1356read_handler_checksum(void *baton, char *buffer, apr_size_t *len) 1357{ 1358 struct checksum_stream_baton *btn = baton; 1359 1360 SVN_ERR(svn_stream_read2(btn->proxy, buffer, len)); 1361 1362 if (btn->read_checksum) 1363 SVN_ERR(svn_checksum_update(btn->read_ctx, buffer, *len)); 1364 1365 return SVN_NO_ERROR; 1366} 1367 1368static svn_error_t * 1369read_full_handler_checksum(void *baton, char *buffer, apr_size_t *len) 1370{ 1371 struct checksum_stream_baton *btn = baton; 1372 apr_size_t saved_len = *len; 1373 1374 SVN_ERR(svn_stream_read_full(btn->proxy, buffer, len)); 1375 1376 if (btn->read_checksum) 1377 SVN_ERR(svn_checksum_update(btn->read_ctx, buffer, *len)); 1378 1379 if (saved_len != *len) 1380 btn->read_more = FALSE; 1381 1382 return SVN_NO_ERROR; 1383} 1384 1385 1386static svn_error_t * 1387write_handler_checksum(void *baton, const char *buffer, apr_size_t *len) 1388{ 1389 struct checksum_stream_baton *btn = baton; 1390 1391 if (btn->write_checksum && *len > 0) 1392 SVN_ERR(svn_checksum_update(btn->write_ctx, buffer, *len)); 1393 1394 return svn_error_trace(svn_stream_write(btn->proxy, buffer, len)); 1395} 1396 1397static svn_error_t * 1398data_available_handler_checksum(void *baton, svn_boolean_t *data_available) 1399{ 1400 struct checksum_stream_baton *btn = baton; 1401 1402 return svn_error_trace(svn_stream_data_available(btn->proxy, 1403 data_available)); 1404} 1405 1406static svn_error_t * 1407close_handler_checksum(void *baton) 1408{ 1409 struct checksum_stream_baton *btn = baton; 1410 1411 /* If we're supposed to drain the stream, do so before finalizing the 1412 checksum. */ 1413 if (btn->read_more) 1414 { 1415 char *buf = apr_palloc(btn->pool, SVN__STREAM_CHUNK_SIZE); 1416 apr_size_t len = SVN__STREAM_CHUNK_SIZE; 1417 1418 do 1419 { 1420 SVN_ERR(read_full_handler_checksum(baton, buf, &len)); 1421 } 1422 while (btn->read_more); 1423 } 1424 1425 if (btn->read_ctx) 1426 SVN_ERR(svn_checksum_final(btn->read_checksum, btn->read_ctx, btn->pool)); 1427 1428 if (btn->write_ctx) 1429 SVN_ERR(svn_checksum_final(btn->write_checksum, btn->write_ctx, btn->pool)); 1430 1431 return svn_error_trace(svn_stream_close(btn->proxy)); 1432} 1433 1434 1435svn_stream_t * 1436svn_stream_checksummed2(svn_stream_t *stream, 1437 svn_checksum_t **read_checksum, 1438 svn_checksum_t **write_checksum, 1439 svn_checksum_kind_t checksum_kind, 1440 svn_boolean_t read_all, 1441 apr_pool_t *pool) 1442{ 1443 svn_stream_t *s; 1444 struct checksum_stream_baton *baton; 1445 1446 if (read_checksum == NULL && write_checksum == NULL) 1447 return stream; 1448 1449 baton = apr_palloc(pool, sizeof(*baton)); 1450 if (read_checksum) 1451 baton->read_ctx = svn_checksum_ctx_create(checksum_kind, pool); 1452 else 1453 baton->read_ctx = NULL; 1454 1455 if (write_checksum) 1456 baton->write_ctx = svn_checksum_ctx_create(checksum_kind, pool); 1457 else 1458 baton->write_ctx = NULL; 1459 1460 baton->read_checksum = read_checksum; 1461 baton->write_checksum = write_checksum; 1462 baton->proxy = stream; 1463 baton->read_more = read_all; 1464 baton->pool = pool; 1465 1466 s = svn_stream_create(baton, pool); 1467 svn_stream_set_read2(s, read_handler_checksum, read_full_handler_checksum); 1468 svn_stream_set_write(s, write_handler_checksum); 1469 svn_stream_set_data_available(s, data_available_handler_checksum); 1470 svn_stream_set_close(s, close_handler_checksum); 1471 return s; 1472} 1473 1474/* Miscellaneous stream functions. */ 1475 1476svn_error_t * 1477svn_stringbuf_from_stream(svn_stringbuf_t **str, 1478 svn_stream_t *stream, 1479 apr_size_t len_hint, 1480 apr_pool_t *result_pool) 1481{ 1482#define MIN_READ_SIZE 64 1483 1484 apr_size_t to_read = 0; 1485 svn_stringbuf_t *text 1486 = svn_stringbuf_create_ensure(len_hint ? len_hint : MIN_READ_SIZE, 1487 result_pool); 1488 1489 do 1490 { 1491 to_read = text->blocksize - 1 - text->len; 1492 SVN_ERR(svn_stream_read_full(stream, text->data + text->len, &to_read)); 1493 text->len += to_read; 1494 1495 if (to_read && text->blocksize < text->len + MIN_READ_SIZE) 1496 svn_stringbuf_ensure(text, text->blocksize * 2); 1497 } 1498 while (to_read); 1499 1500 text->data[text->len] = '\0'; 1501 *str = text; 1502 1503 return SVN_NO_ERROR; 1504} 1505 1506struct stringbuf_stream_baton 1507{ 1508 svn_stringbuf_t *str; 1509 apr_size_t amt_read; 1510}; 1511 1512/* svn_stream_mark_t for streams backed by stringbufs. */ 1513struct stringbuf_stream_mark { 1514 apr_size_t pos; 1515}; 1516 1517static svn_error_t * 1518read_handler_stringbuf(void *baton, char *buffer, apr_size_t *len) 1519{ 1520 struct stringbuf_stream_baton *btn = baton; 1521 apr_size_t left_to_read = btn->str->len - btn->amt_read; 1522 1523 *len = (*len > left_to_read) ? left_to_read : *len; 1524 memcpy(buffer, btn->str->data + btn->amt_read, *len); 1525 btn->amt_read += *len; 1526 return SVN_NO_ERROR; 1527} 1528 1529static svn_error_t * 1530skip_handler_stringbuf(void *baton, apr_size_t len) 1531{ 1532 struct stringbuf_stream_baton *btn = baton; 1533 apr_size_t left_to_read = btn->str->len - btn->amt_read; 1534 1535 len = (len > left_to_read) ? left_to_read : len; 1536 btn->amt_read += len; 1537 return SVN_NO_ERROR; 1538} 1539 1540static svn_error_t * 1541write_handler_stringbuf(void *baton, const char *data, apr_size_t *len) 1542{ 1543 struct stringbuf_stream_baton *btn = baton; 1544 1545 svn_stringbuf_appendbytes(btn->str, data, *len); 1546 return SVN_NO_ERROR; 1547} 1548 1549static svn_error_t * 1550mark_handler_stringbuf(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 1551{ 1552 struct stringbuf_stream_baton *btn; 1553 struct stringbuf_stream_mark *stringbuf_stream_mark; 1554 1555 btn = baton; 1556 1557 stringbuf_stream_mark = apr_palloc(pool, sizeof(*stringbuf_stream_mark)); 1558 stringbuf_stream_mark->pos = btn->amt_read; 1559 *mark = (svn_stream_mark_t *)stringbuf_stream_mark; 1560 return SVN_NO_ERROR; 1561} 1562 1563static svn_error_t * 1564seek_handler_stringbuf(void *baton, const svn_stream_mark_t *mark) 1565{ 1566 struct stringbuf_stream_baton *btn = baton; 1567 1568 if (mark != NULL) 1569 { 1570 const struct stringbuf_stream_mark *stringbuf_stream_mark; 1571 1572 stringbuf_stream_mark = (const struct stringbuf_stream_mark *)mark; 1573 btn->amt_read = stringbuf_stream_mark->pos; 1574 } 1575 else 1576 btn->amt_read = 0; 1577 1578 return SVN_NO_ERROR; 1579} 1580 1581static svn_error_t * 1582data_available_handler_stringbuf(void *baton, svn_boolean_t *data_available) 1583{ 1584 struct stringbuf_stream_baton *btn = baton; 1585 1586 *data_available = ((btn->str->len - btn->amt_read) > 0); 1587 return SVN_NO_ERROR; 1588} 1589 1590static svn_boolean_t 1591is_buffered_handler_stringbuf(void *baton) 1592{ 1593 return TRUE; 1594} 1595 1596svn_stream_t * 1597svn_stream_from_stringbuf(svn_stringbuf_t *str, 1598 apr_pool_t *pool) 1599{ 1600 svn_stream_t *stream; 1601 struct stringbuf_stream_baton *baton; 1602 1603 if (! str) 1604 return svn_stream_empty(pool); 1605 1606 baton = apr_palloc(pool, sizeof(*baton)); 1607 baton->str = str; 1608 baton->amt_read = 0; 1609 stream = svn_stream_create(baton, pool); 1610 svn_stream_set_read2(stream, read_handler_stringbuf, read_handler_stringbuf); 1611 svn_stream_set_skip(stream, skip_handler_stringbuf); 1612 svn_stream_set_write(stream, write_handler_stringbuf); 1613 svn_stream_set_mark(stream, mark_handler_stringbuf); 1614 svn_stream_set_seek(stream, seek_handler_stringbuf); 1615 svn_stream_set_data_available(stream, data_available_handler_stringbuf); 1616 svn_stream__set_is_buffered(stream, is_buffered_handler_stringbuf); 1617 return stream; 1618} 1619 1620struct string_stream_baton 1621{ 1622 const svn_string_t *str; 1623 apr_size_t amt_read; 1624}; 1625 1626/* svn_stream_mark_t for streams backed by stringbufs. */ 1627struct string_stream_mark { 1628 apr_size_t pos; 1629}; 1630 1631static svn_error_t * 1632read_handler_string(void *baton, char *buffer, apr_size_t *len) 1633{ 1634 struct string_stream_baton *btn = baton; 1635 apr_size_t left_to_read = btn->str->len - btn->amt_read; 1636 1637 *len = (*len > left_to_read) ? left_to_read : *len; 1638 memcpy(buffer, btn->str->data + btn->amt_read, *len); 1639 btn->amt_read += *len; 1640 return SVN_NO_ERROR; 1641} 1642 1643static svn_error_t * 1644mark_handler_string(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool) 1645{ 1646 struct string_stream_baton *btn; 1647 struct string_stream_mark *marker; 1648 1649 btn = baton; 1650 1651 marker = apr_palloc(pool, sizeof(*marker)); 1652 marker->pos = btn->amt_read; 1653 *mark = (svn_stream_mark_t *)marker; 1654 return SVN_NO_ERROR; 1655} 1656 1657static svn_error_t * 1658seek_handler_string(void *baton, const svn_stream_mark_t *mark) 1659{ 1660 struct string_stream_baton *btn = baton; 1661 1662 if (mark != NULL) 1663 { 1664 const struct string_stream_mark *marker; 1665 1666 marker = (const struct string_stream_mark *)mark; 1667 btn->amt_read = marker->pos; 1668 } 1669 else 1670 btn->amt_read = 0; 1671 1672 return SVN_NO_ERROR; 1673} 1674 1675static svn_error_t * 1676skip_handler_string(void *baton, apr_size_t len) 1677{ 1678 struct string_stream_baton *btn = baton; 1679 apr_size_t left_to_read = btn->str->len - btn->amt_read; 1680 1681 len = (len > left_to_read) ? left_to_read : len; 1682 btn->amt_read += len; 1683 return SVN_NO_ERROR; 1684} 1685 1686static svn_error_t * 1687data_available_handler_string(void *baton, svn_boolean_t *data_available) 1688{ 1689 struct string_stream_baton *btn = baton; 1690 1691 *data_available = ((btn->str->len - btn->amt_read) > 0); 1692 return SVN_NO_ERROR; 1693} 1694 1695static svn_boolean_t 1696is_buffered_handler_string(void *baton) 1697{ 1698 return TRUE; 1699} 1700 1701svn_stream_t * 1702svn_stream_from_string(const svn_string_t *str, 1703 apr_pool_t *pool) 1704{ 1705 svn_stream_t *stream; 1706 struct string_stream_baton *baton; 1707 1708 if (! str) 1709 return svn_stream_empty(pool); 1710 1711 baton = apr_palloc(pool, sizeof(*baton)); 1712 baton->str = str; 1713 baton->amt_read = 0; 1714 stream = svn_stream_create(baton, pool); 1715 svn_stream_set_read2(stream, read_handler_string, read_handler_string); 1716 svn_stream_set_mark(stream, mark_handler_string); 1717 svn_stream_set_seek(stream, seek_handler_string); 1718 svn_stream_set_skip(stream, skip_handler_string); 1719 svn_stream_set_data_available(stream, data_available_handler_string); 1720 svn_stream__set_is_buffered(stream, is_buffered_handler_string); 1721 return stream; 1722} 1723 1724 1725svn_error_t * 1726svn_stream_for_stdin(svn_stream_t **in, apr_pool_t *pool) 1727{ 1728 apr_file_t *stdin_file; 1729 apr_status_t apr_err; 1730 1731 apr_err = apr_file_open_stdin(&stdin_file, pool); 1732 if (apr_err) 1733 return svn_error_wrap_apr(apr_err, "Can't open stdin"); 1734 1735 /* STDIN may or may not support positioning requests, but generally 1736 it does not, or the behavior is implementation-specific. Hence, 1737 we cannot safely advertise mark(), seek() and non-default skip() 1738 support. */ 1739 *in = make_stream_from_apr_file(stdin_file, TRUE, FALSE, pool); 1740 1741 return SVN_NO_ERROR; 1742} 1743 1744 1745svn_error_t * 1746svn_stream_for_stdout(svn_stream_t **out, apr_pool_t *pool) 1747{ 1748 apr_file_t *stdout_file; 1749 apr_status_t apr_err; 1750 1751 apr_err = apr_file_open_stdout(&stdout_file, pool); 1752 if (apr_err) 1753 return svn_error_wrap_apr(apr_err, "Can't open stdout"); 1754 1755 /* STDOUT may or may not support positioning requests, but generally 1756 it does not, or the behavior is implementation-specific. Hence, 1757 we cannot safely advertise mark(), seek() and non-default skip() 1758 support. */ 1759 *out = make_stream_from_apr_file(stdout_file, TRUE, FALSE, pool); 1760 1761 return SVN_NO_ERROR; 1762} 1763 1764 1765svn_error_t * 1766svn_stream_for_stderr(svn_stream_t **err, apr_pool_t *pool) 1767{ 1768 apr_file_t *stderr_file; 1769 apr_status_t apr_err; 1770 1771 apr_err = apr_file_open_stderr(&stderr_file, pool); 1772 if (apr_err) 1773 return svn_error_wrap_apr(apr_err, "Can't open stderr"); 1774 1775 /* STDERR may or may not support positioning requests, but generally 1776 it does not, or the behavior is implementation-specific. Hence, 1777 we cannot safely advertise mark(), seek() and non-default skip() 1778 support. */ 1779 *err = make_stream_from_apr_file(stderr_file, TRUE, FALSE, pool); 1780 1781 return SVN_NO_ERROR; 1782} 1783 1784 1785svn_error_t * 1786svn_string_from_stream(svn_string_t **result, 1787 svn_stream_t *stream, 1788 apr_pool_t *result_pool, 1789 apr_pool_t *scratch_pool) 1790{ 1791 svn_stringbuf_t *work = svn_stringbuf_create_ensure(SVN__STREAM_CHUNK_SIZE, 1792 result_pool); 1793 char *buffer = apr_palloc(scratch_pool, SVN__STREAM_CHUNK_SIZE); 1794 1795 while (1) 1796 { 1797 apr_size_t len = SVN__STREAM_CHUNK_SIZE; 1798 1799 SVN_ERR(svn_stream_read_full(stream, buffer, &len)); 1800 svn_stringbuf_appendbytes(work, buffer, len); 1801 1802 if (len < SVN__STREAM_CHUNK_SIZE) 1803 break; 1804 } 1805 1806 SVN_ERR(svn_stream_close(stream)); 1807 1808 *result = apr_palloc(result_pool, sizeof(**result)); 1809 (*result)->data = work->data; 1810 (*result)->len = work->len; 1811 1812 return SVN_NO_ERROR; 1813} 1814 1815 1816/* These are somewhat arbitrary, if we ever get good empirical data as to 1817 actually valid values, feel free to update them. */ 1818#define BUFFER_BLOCK_SIZE 1024 1819#define BUFFER_MAX_SIZE 100000 1820 1821svn_stream_t * 1822svn_stream_buffered(apr_pool_t *result_pool) 1823{ 1824 return svn_stream__from_spillbuf(svn_spillbuf__create(BUFFER_BLOCK_SIZE, 1825 BUFFER_MAX_SIZE, 1826 result_pool), 1827 result_pool); 1828} 1829 1830 1831 1832/*** Lazyopen Streams ***/ 1833 1834/* Custom baton for lazyopen-style wrapper streams. */ 1835typedef struct lazyopen_baton_t { 1836 1837 /* Callback function and baton for opening the wrapped stream. */ 1838 svn_stream_lazyopen_func_t open_func; 1839 void *open_baton; 1840 1841 /* The wrapped stream, or NULL if the stream hasn't yet been 1842 opened. */ 1843 svn_stream_t *real_stream; 1844 apr_pool_t *pool; 1845 1846 /* Whether to open the wrapped stream on a close call. */ 1847 svn_boolean_t open_on_close; 1848 1849} lazyopen_baton_t; 1850 1851 1852/* Use B->open_func/baton to create and set B->real_stream iff it 1853 isn't already set. */ 1854static svn_error_t * 1855lazyopen_if_unopened(lazyopen_baton_t *b) 1856{ 1857 if (b->real_stream == NULL) 1858 { 1859 svn_stream_t *stream; 1860 apr_pool_t *scratch_pool = svn_pool_create(b->pool); 1861 1862 SVN_ERR(b->open_func(&stream, b->open_baton, 1863 b->pool, scratch_pool)); 1864 1865 svn_pool_destroy(scratch_pool); 1866 1867 b->real_stream = stream; 1868 } 1869 1870 return SVN_NO_ERROR; 1871} 1872 1873/* Implements svn_read_fn_t */ 1874static svn_error_t * 1875read_handler_lazyopen(void *baton, 1876 char *buffer, 1877 apr_size_t *len) 1878{ 1879 lazyopen_baton_t *b = baton; 1880 1881 SVN_ERR(lazyopen_if_unopened(b)); 1882 SVN_ERR(svn_stream_read2(b->real_stream, buffer, len)); 1883 1884 return SVN_NO_ERROR; 1885} 1886 1887/* Implements svn_read_fn_t */ 1888static svn_error_t * 1889read_full_handler_lazyopen(void *baton, 1890 char *buffer, 1891 apr_size_t *len) 1892{ 1893 lazyopen_baton_t *b = baton; 1894 1895 SVN_ERR(lazyopen_if_unopened(b)); 1896 SVN_ERR(svn_stream_read_full(b->real_stream, buffer, len)); 1897 1898 return SVN_NO_ERROR; 1899} 1900 1901/* Implements svn_stream_skip_fn_t */ 1902static svn_error_t * 1903skip_handler_lazyopen(void *baton, 1904 apr_size_t len) 1905{ 1906 lazyopen_baton_t *b = baton; 1907 1908 SVN_ERR(lazyopen_if_unopened(b)); 1909 SVN_ERR(svn_stream_skip(b->real_stream, len)); 1910 1911 return SVN_NO_ERROR; 1912} 1913 1914/* Implements svn_write_fn_t */ 1915static svn_error_t * 1916write_handler_lazyopen(void *baton, 1917 const char *data, 1918 apr_size_t *len) 1919{ 1920 lazyopen_baton_t *b = baton; 1921 1922 SVN_ERR(lazyopen_if_unopened(b)); 1923 SVN_ERR(svn_stream_write(b->real_stream, data, len)); 1924 1925 return SVN_NO_ERROR; 1926} 1927 1928/* Implements svn_close_fn_t */ 1929static svn_error_t * 1930close_handler_lazyopen(void *baton) 1931{ 1932 lazyopen_baton_t *b = baton; 1933 1934 if (b->open_on_close) 1935 SVN_ERR(lazyopen_if_unopened(b)); 1936 if (b->real_stream) 1937 SVN_ERR(svn_stream_close(b->real_stream)); 1938 1939 return SVN_NO_ERROR; 1940} 1941 1942/* Implements svn_stream_mark_fn_t */ 1943static svn_error_t * 1944mark_handler_lazyopen(void *baton, 1945 svn_stream_mark_t **mark, 1946 apr_pool_t *pool) 1947{ 1948 lazyopen_baton_t *b = baton; 1949 1950 SVN_ERR(lazyopen_if_unopened(b)); 1951 SVN_ERR(svn_stream_mark(b->real_stream, mark, pool)); 1952 1953 return SVN_NO_ERROR; 1954} 1955 1956/* Implements svn_stream_seek_fn_t */ 1957static svn_error_t * 1958seek_handler_lazyopen(void *baton, 1959 const svn_stream_mark_t *mark) 1960{ 1961 lazyopen_baton_t *b = baton; 1962 1963 SVN_ERR(lazyopen_if_unopened(b)); 1964 SVN_ERR(svn_stream_seek(b->real_stream, mark)); 1965 1966 return SVN_NO_ERROR; 1967} 1968 1969static svn_error_t * 1970data_available_handler_lazyopen(void *baton, 1971 svn_boolean_t *data_available) 1972{ 1973 lazyopen_baton_t *b = baton; 1974 1975 SVN_ERR(lazyopen_if_unopened(b)); 1976 return svn_error_trace(svn_stream_data_available(b->real_stream, 1977 data_available)); 1978} 1979 1980/* Implements svn_stream__is_buffered_fn_t */ 1981static svn_boolean_t 1982is_buffered_lazyopen(void *baton) 1983{ 1984 lazyopen_baton_t *b = baton; 1985 1986 /* No lazy open as we cannot handle an open error. */ 1987 if (!b->real_stream) 1988 return FALSE; 1989 1990 return svn_stream__is_buffered(b->real_stream); 1991} 1992 1993svn_stream_t * 1994svn_stream_lazyopen_create(svn_stream_lazyopen_func_t open_func, 1995 void *open_baton, 1996 svn_boolean_t open_on_close, 1997 apr_pool_t *result_pool) 1998{ 1999 lazyopen_baton_t *lob = apr_pcalloc(result_pool, sizeof(*lob)); 2000 svn_stream_t *stream; 2001 2002 lob->open_func = open_func; 2003 lob->open_baton = open_baton; 2004 lob->real_stream = NULL; 2005 lob->pool = result_pool; 2006 lob->open_on_close = open_on_close; 2007 2008 stream = svn_stream_create(lob, result_pool); 2009 svn_stream_set_read2(stream, read_handler_lazyopen, 2010 read_full_handler_lazyopen); 2011 svn_stream_set_skip(stream, skip_handler_lazyopen); 2012 svn_stream_set_write(stream, write_handler_lazyopen); 2013 svn_stream_set_close(stream, close_handler_lazyopen); 2014 svn_stream_set_mark(stream, mark_handler_lazyopen); 2015 svn_stream_set_seek(stream, seek_handler_lazyopen); 2016 svn_stream_set_data_available(stream, data_available_handler_lazyopen); 2017 svn_stream__set_is_buffered(stream, is_buffered_lazyopen); 2018 2019 return stream; 2020} 2021 2022/* Baton for install streams */ 2023struct install_baton_t 2024{ 2025 struct baton_apr baton_apr; 2026 const char *tmp_path; 2027}; 2028 2029#ifdef WIN32 2030 2031/* Create and open a tempfile in DIRECTORY. Return its handle and path */ 2032static svn_error_t * 2033create_tempfile(HANDLE *hFile, 2034 const char **file_path, 2035 const char *directory, 2036 apr_pool_t *result_pool, 2037 apr_pool_t *scratch_pool) 2038{ 2039 const char *unique_name; 2040 apr_pool_t *iterpool = svn_pool_create(scratch_pool); 2041 static svn_atomic_t tempname_counter; 2042 int baseNr = (GetTickCount() << 11) + 13 * svn_atomic_inc(&tempname_counter) 2043 + GetCurrentProcessId(); 2044 int i = 0; 2045 HANDLE h; 2046 2047 /* Shares common idea with io.c's temp_file_create */ 2048 2049 do 2050 { 2051 apr_uint32_t unique_nr; 2052 WCHAR *w_name; 2053 2054 /* Generate a number that should be unique for this application and 2055 usually for the entire computer to reduce the number of cycles 2056 through this loop. (A bit of calculation is much cheaper than 2057 disk io) */ 2058 unique_nr = baseNr + 7 * i++; 2059 2060 2061 svn_pool_clear(iterpool); 2062 unique_name = svn_dirent_join(directory, 2063 apr_psprintf(iterpool, "svn-%X", 2064 unique_nr), 2065 iterpool); 2066 2067 SVN_ERR(svn_io__utf8_to_unicode_longpath(&w_name, unique_name, 2068 iterpool)); 2069 2070 /* Create a completely not-sharable file to avoid indexers, and other 2071 filesystem watchers locking the file while we are still writing. 2072 2073 We need DELETE privileges to move the file. */ 2074 h = CreateFileW(w_name, GENERIC_WRITE | DELETE, 0 /* share */, 2075 NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); 2076 2077 if (h == INVALID_HANDLE_VALUE) 2078 { 2079 apr_status_t status = apr_get_os_error(); 2080 if (i > 1000) 2081 return svn_error_createf(SVN_ERR_IO_UNIQUE_NAMES_EXHAUSTED, 2082 svn_error_wrap_apr(status, NULL), 2083 _("Unable to make name in '%s'"), 2084 svn_dirent_local_style(directory, scratch_pool)); 2085 2086 if (!APR_STATUS_IS_EEXIST(status) && !APR_STATUS_IS_EACCES(status)) 2087 return svn_error_wrap_apr(status, NULL); 2088 } 2089 } 2090 while (h == INVALID_HANDLE_VALUE); 2091 2092 *hFile = h; 2093 *file_path = apr_pstrdup(result_pool, unique_name); 2094 svn_pool_destroy(iterpool); 2095 2096 return SVN_NO_ERROR; 2097} 2098 2099/* Implements svn_close_fn_t */ 2100static svn_error_t * 2101install_close(void *baton) 2102{ 2103 struct install_baton_t *ib = baton; 2104 2105 /* Flush the data cached in APR, but don't close the file yet */ 2106 SVN_ERR(svn_io_file_flush(ib->baton_apr.file, ib->baton_apr.pool)); 2107 2108 return SVN_NO_ERROR; 2109} 2110 2111#endif /* WIN32 */ 2112 2113svn_error_t * 2114svn_stream__create_for_install(svn_stream_t **install_stream, 2115 const char *tmp_abspath, 2116 apr_pool_t *result_pool, 2117 apr_pool_t *scratch_pool) 2118{ 2119 apr_file_t *file; 2120 struct install_baton_t *ib; 2121 const char *tmp_path; 2122 2123#ifdef WIN32 2124 HANDLE hInstall; 2125 apr_status_t status; 2126 2127 SVN_ERR_ASSERT(svn_dirent_is_absolute(tmp_abspath)); 2128 2129 SVN_ERR(create_tempfile(&hInstall, &tmp_path, tmp_abspath, 2130 scratch_pool, scratch_pool)); 2131 2132 /* Wrap as a standard APR file to allow sharing implementation. 2133 2134 But do note that some file functions (such as retrieving the name) 2135 don't work on this wrapper. */ 2136 /* ### Buffered, or not? */ 2137 status = apr_os_file_put(&file, &hInstall, 2138 APR_WRITE | APR_BINARY | APR_BUFFERED, 2139 result_pool); 2140 2141 if (status) 2142 { 2143 CloseHandle(hInstall); 2144 return svn_error_wrap_apr(status, NULL); 2145 } 2146 2147 tmp_path = svn_dirent_internal_style(tmp_path, result_pool); 2148#else 2149 2150 SVN_ERR_ASSERT(svn_dirent_is_absolute(tmp_abspath)); 2151 2152 SVN_ERR(svn_io_open_unique_file3(&file, &tmp_path, tmp_abspath, 2153 svn_io_file_del_none, 2154 result_pool, scratch_pool)); 2155#endif 2156 *install_stream = svn_stream_from_aprfile2(file, FALSE, result_pool); 2157 2158 ib = apr_pcalloc(result_pool, sizeof(*ib)); 2159 ib->baton_apr = *(struct baton_apr*)(*install_stream)->baton; 2160 2161 assert((void*)&ib->baton_apr == (void*)ib); /* baton pointer is the same */ 2162 2163 (*install_stream)->baton = ib; 2164 2165 ib->tmp_path = tmp_path; 2166 2167#ifdef WIN32 2168 /* Don't close the file on stream close; flush instead */ 2169 svn_stream_set_close(*install_stream, install_close); 2170#else 2171 /* ### Install pool cleanup handler for tempfile? */ 2172#endif 2173 2174 return SVN_NO_ERROR; 2175} 2176 2177svn_error_t * 2178svn_stream__install_stream(svn_stream_t *install_stream, 2179 const char *final_abspath, 2180 svn_boolean_t make_parents, 2181 apr_pool_t *scratch_pool) 2182{ 2183 struct install_baton_t *ib = install_stream->baton; 2184 svn_error_t *err; 2185 2186 SVN_ERR_ASSERT(svn_dirent_is_absolute(final_abspath)); 2187#ifdef WIN32 2188 err = svn_io__win_rename_open_file(ib->baton_apr.file, ib->tmp_path, 2189 final_abspath, scratch_pool); 2190 if (make_parents && err && APR_STATUS_IS_ENOENT(err->apr_err)) 2191 { 2192 svn_error_t *err2; 2193 2194 err2 = svn_io_make_dir_recursively(svn_dirent_dirname(final_abspath, 2195 scratch_pool), 2196 scratch_pool); 2197 2198 if (err2) 2199 return svn_error_trace(svn_error_compose_create(err, err2)); 2200 else 2201 svn_error_clear(err); 2202 2203 err = svn_io__win_rename_open_file(ib->baton_apr.file, ib->tmp_path, 2204 final_abspath, scratch_pool); 2205 } 2206 2207 /* ### rhuijben: I wouldn't be surprised if we later find out that we 2208 have to fall back to close+rename on some specific 2209 error values here, to support some non standard NAS 2210 and filesystem scenarios. */ 2211 if (err && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE) 2212 { 2213 /* Rename open files is not supported on this platform: fallback to 2214 svn_io_file_rename2(). */ 2215 svn_error_clear(err); 2216 err = SVN_NO_ERROR; 2217 2218 SVN_ERR(svn_io_file_close(ib->baton_apr.file, scratch_pool)); 2219 } 2220 else 2221 { 2222 return svn_error_compose_create(err, 2223 svn_io_file_close(ib->baton_apr.file, 2224 scratch_pool)); 2225 } 2226#endif 2227 2228 err = svn_io_file_rename(ib->tmp_path, final_abspath, scratch_pool); 2229 2230 /* A missing directory is too common to not cover here. */ 2231 if (make_parents && err && APR_STATUS_IS_ENOENT(err->apr_err)) 2232 { 2233 svn_error_t *err2; 2234 2235 err2 = svn_io_make_dir_recursively(svn_dirent_dirname(final_abspath, 2236 scratch_pool), 2237 scratch_pool); 2238 2239 if (err2) 2240 /* Creating directory didn't work: Return all errors */ 2241 return svn_error_trace(svn_error_compose_create(err, err2)); 2242 else 2243 /* We could create a directory: retry install */ 2244 svn_error_clear(err); 2245 2246 SVN_ERR(svn_io_file_rename(ib->tmp_path, final_abspath, scratch_pool)); 2247 } 2248 else 2249 SVN_ERR(err); 2250 2251 return SVN_NO_ERROR; 2252} 2253 2254svn_error_t * 2255svn_stream__install_get_info(apr_finfo_t *finfo, 2256 svn_stream_t *install_stream, 2257 apr_int32_t wanted, 2258 apr_pool_t *scratch_pool) 2259{ 2260 struct install_baton_t *ib = install_stream->baton; 2261 2262#ifdef WIN32 2263 /* On WIN32 the file is still open, so we can obtain the information 2264 from the handle without race conditions */ 2265 apr_status_t status; 2266 2267 status = apr_file_info_get(finfo, wanted, ib->baton_apr.file); 2268 2269 if (status) 2270 return svn_error_wrap_apr(status, NULL); 2271#else 2272 SVN_ERR(svn_io_stat(finfo, ib->tmp_path, wanted, scratch_pool)); 2273#endif 2274 2275 return SVN_NO_ERROR; 2276} 2277 2278svn_error_t * 2279svn_stream__install_delete(svn_stream_t *install_stream, 2280 apr_pool_t *scratch_pool) 2281{ 2282 struct install_baton_t *ib = install_stream->baton; 2283 2284#ifdef WIN32 2285 svn_error_t *err; 2286 2287 /* Mark the file as delete on close to avoid having to reopen 2288 the file as part of the delete handling. */ 2289 err = svn_io__win_delete_file_on_close(ib->baton_apr.file, ib->tmp_path, 2290 scratch_pool); 2291 if (err == SVN_NO_ERROR) 2292 { 2293 SVN_ERR(svn_io_file_close(ib->baton_apr.file, scratch_pool)); 2294 return SVN_NO_ERROR; /* File is already gone */ 2295 } 2296 2297 /* Deleting file on close may be unsupported, so ignore errors and 2298 fallback to svn_io_remove_file2(). */ 2299 svn_error_clear(err); 2300 SVN_ERR(svn_io_file_close(ib->baton_apr.file, scratch_pool)); 2301#endif 2302 2303 return svn_error_trace(svn_io_remove_file2(ib->tmp_path, FALSE, 2304 scratch_pool)); 2305} 2306