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