~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/libsvn_subr/stream.c

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
#include <apr_strings.h>
30
30
#include <apr_file_io.h>
31
31
#include <apr_errno.h>
32
 
#include <apr_md5.h>
 
32
#include <apr_poll.h>
 
33
#include <apr_portable.h>
33
34
 
34
35
#include <zlib.h>
35
36
 
41
42
#include "svn_checksum.h"
42
43
#include "svn_path.h"
43
44
#include "svn_private_config.h"
 
45
#include "private/svn_atomic.h"
44
46
#include "private/svn_error_private.h"
45
47
#include "private/svn_eol_private.h"
46
48
#include "private/svn_io_private.h"
47
49
#include "private/svn_subr_private.h"
 
50
#include "private/svn_utf_private.h"
48
51
 
49
52
 
50
53
struct svn_stream_t {
51
54
  void *baton;
52
55
  svn_read_fn_t read_fn;
 
56
  svn_read_fn_t read_full_fn;
53
57
  svn_stream_skip_fn_t skip_fn;
54
58
  svn_write_fn_t write_fn;
55
59
  svn_close_fn_t close_fn;
56
60
  svn_stream_mark_fn_t mark_fn;
57
61
  svn_stream_seek_fn_t seek_fn;
 
62
  svn_stream_data_available_fn_t data_available_fn;
58
63
  svn_stream__is_buffered_fn_t is_buffered_fn;
59
64
  apr_file_t *file; /* Maybe NULL */
60
65
};
63
68
/*** Forward declarations. ***/
64
69
 
65
70
static svn_error_t *
66
 
skip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_fn);
 
71
skip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_full_fn);
67
72
 
68
73
 
69
74
/*** Generic streams. ***/
73
78
{
74
79
  svn_stream_t *stream;
75
80
 
76
 
  stream = apr_palloc(pool, sizeof(*stream));
 
81
  stream = apr_pcalloc(pool, sizeof(*stream));
77
82
  stream->baton = baton;
78
 
  stream->read_fn = NULL;
79
 
  stream->skip_fn = NULL;
80
 
  stream->write_fn = NULL;
81
 
  stream->close_fn = NULL;
82
 
  stream->mark_fn = NULL;
83
 
  stream->seek_fn = NULL;
84
 
  stream->is_buffered_fn = NULL;
85
 
  stream->file = NULL;
86
83
  return stream;
87
84
}
88
85
 
95
92
 
96
93
 
97
94
void
98
 
svn_stream_set_read(svn_stream_t *stream, svn_read_fn_t read_fn)
 
95
svn_stream_set_read2(svn_stream_t *stream,
 
96
                     svn_read_fn_t read_fn,
 
97
                     svn_read_fn_t read_full_fn)
99
98
{
100
99
  stream->read_fn = read_fn;
 
100
  stream->read_full_fn = read_full_fn;
101
101
}
102
102
 
103
103
void
131
131
}
132
132
 
133
133
void
 
134
svn_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
 
 
140
void
134
141
svn_stream__set_is_buffered(svn_stream_t *stream,
135
142
                            svn_stream__is_buffered_fn_t is_buffered_fn)
136
143
{
137
144
  stream->is_buffered_fn = is_buffered_fn;
138
145
}
139
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) */
 
150
static svn_error_t *
 
151
full_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
 
 
172
svn_boolean_t
 
173
svn_stream_supports_partial_read(svn_stream_t *stream)
 
174
{
 
175
  return stream->read_fn != NULL;
 
176
}
 
177
 
140
178
svn_error_t *
141
 
svn_stream_read(svn_stream_t *stream, char *buffer, apr_size_t *len)
 
179
svn_stream_read2(svn_stream_t *stream, char *buffer, apr_size_t *len)
142
180
{
143
 
  SVN_ERR_ASSERT(stream->read_fn != NULL);
 
181
  if (stream->read_fn == NULL)
 
182
    return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, NULL, NULL);
 
183
 
144
184
  return svn_error_trace(stream->read_fn(stream->baton, buffer, len));
145
185
}
146
186
 
 
187
svn_error_t *
 
188
svn_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
}
147
195
 
148
196
svn_error_t *
149
197
svn_stream_skip(svn_stream_t *stream, apr_size_t len)
150
198
{
151
199
  if (stream->skip_fn == NULL)
152
200
    return svn_error_trace(
153
 
            skip_default_handler(stream->baton, len, stream->read_fn));
 
201
            skip_default_handler(stream->baton, len, stream->read_full_fn));
154
202
 
155
203
  return svn_error_trace(stream->skip_fn(stream->baton, len));
156
204
}
159
207
svn_error_t *
160
208
svn_stream_write(svn_stream_t *stream, const char *data, apr_size_t *len)
161
209
{
162
 
  SVN_ERR_ASSERT(stream->write_fn != NULL);
 
210
  if (stream->write_fn == NULL)
 
211
    return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED, NULL, NULL);
 
212
 
163
213
  return svn_error_trace(stream->write_fn(stream->baton, data, len));
164
214
}
165
215
 
196
246
  return svn_error_trace(stream->seek_fn(stream->baton, mark));
197
247
}
198
248
 
 
249
svn_error_t *
 
250
svn_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
 
199
260
svn_boolean_t
200
261
svn_stream__is_buffered(svn_stream_t *stream)
201
262
{
259
320
  return svn_error_trace(svn_stream_puts(stream, translated));
260
321
}
261
322
 
262
 
/* Size that 90% of the lines we encounter will be not longer than.
263
 
   used by stream_readline_bytewise() and stream_readline_chunky().
264
 
 */
265
 
#define LINE_CHUNK_SIZE 80
266
 
 
267
323
/* Guts of svn_stream_readline().
268
324
 * Returns the line read from STREAM in *STRINGBUF, and indicates
269
325
 * end-of-file in *EOF.  If DETECT_EOL is TRUE, the end-of-line indicator
286
342
     optimize for the 90% case.  90% of the time, we can avoid the
287
343
     stringbuf ever having to realloc() itself if we start it out at
288
344
     80 chars.  */
289
 
  str = svn_stringbuf_create_ensure(LINE_CHUNK_SIZE, pool);
 
345
  str = svn_stringbuf_create_ensure(SVN__LINE_CHUNK_SIZE, pool);
290
346
 
291
347
  /* Read into STR up to and including the next EOL sequence. */
292
348
  match = eol;
293
349
  while (*match)
294
350
    {
295
351
      numbytes = 1;
296
 
      SVN_ERR(svn_stream_read(stream, &c, &numbytes));
 
352
      SVN_ERR(svn_stream_read_full(stream, &c, &numbytes));
297
353
      if (numbytes != 1)
298
354
        {
299
355
          /* a 'short' read means the stream has run out. */
330
386
   * larger value because filling the buffer from the stream takes
331
387
   * time as well.
332
388
   */
333
 
  char buffer[LINE_CHUNK_SIZE+1];
 
389
  char buffer[SVN__LINE_CHUNK_SIZE+1];
334
390
 
335
391
  /* variables */
336
392
  svn_stream_mark_t *mark;
347
403
  SVN_ERR(svn_stream_mark(stream, &mark, pool));
348
404
 
349
405
  /* Read the first chunk. */
350
 
  numbytes = LINE_CHUNK_SIZE;
351
 
  SVN_ERR(svn_stream_read(stream, buffer, &numbytes));
 
406
  numbytes = SVN__LINE_CHUNK_SIZE;
 
407
  SVN_ERR(svn_stream_read_full(stream, buffer, &numbytes));
352
408
  buffer[numbytes] = '\0';
353
409
 
354
410
  /* Look for the EOL in this first chunk. If we find it, we are done here.
359
415
      *stringbuf = svn_stringbuf_ncreate(buffer, eol_pos - buffer, pool);
360
416
      total_parsed = eol_pos - buffer + eol_len;
361
417
    }
362
 
  else if (numbytes < LINE_CHUNK_SIZE)
 
418
  else if (numbytes < SVN__LINE_CHUNK_SIZE)
363
419
    {
364
420
      /* We hit EOF but not EOL.
365
421
       */
371
427
    {
372
428
      /* A larger buffer for the string is needed. */
373
429
      svn_stringbuf_t *str;
374
 
      str = svn_stringbuf_create_ensure(2*LINE_CHUNK_SIZE, pool);
 
430
      str = svn_stringbuf_create_ensure(2*SVN__LINE_CHUNK_SIZE, pool);
375
431
      svn_stringbuf_appendbytes(str, buffer, numbytes);
376
432
      *stringbuf = str;
377
433
 
381
437
      {
382
438
        /* Append the next chunk to the string read so far.
383
439
         */
384
 
        svn_stringbuf_ensure(str, str->len + LINE_CHUNK_SIZE);
385
 
        numbytes = LINE_CHUNK_SIZE;
386
 
        SVN_ERR(svn_stream_read(stream, str->data + str->len, &numbytes));
 
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));
387
443
        str->len += numbytes;
388
444
        str->data[str->len] = '\0';
389
445
 
393
449
         */
394
450
        eol_pos = strstr(str->data + str->len - numbytes - (eol_len-1), eol);
395
451
 
396
 
        if ((numbytes < LINE_CHUNK_SIZE) && (eol_pos == NULL))
 
452
        if ((numbytes < SVN__LINE_CHUNK_SIZE) && (eol_pos == NULL))
397
453
        {
398
454
          /* We hit EOF instead of EOL. */
399
455
          *eof = TRUE;
495
551
             break;
496
552
        }
497
553
 
498
 
      err = svn_stream_read(from, buf, &len);
 
554
      err = svn_stream_read_full(from, buf, &len);
499
555
      if (err)
500
556
         break;
501
557
 
528
584
  while (bytes_read1 == SVN__STREAM_CHUNK_SIZE
529
585
         && bytes_read2 == SVN__STREAM_CHUNK_SIZE)
530
586
    {
531
 
      err = svn_stream_read(stream1, buf1, &bytes_read1);
 
587
      err = svn_stream_read_full(stream1, buf1, &bytes_read1);
532
588
      if (err)
533
589
        break;
534
 
      err = svn_stream_read(stream2, buf2, &bytes_read2);
 
590
      err = svn_stream_read_full(stream2, buf2, &bytes_read2);
535
591
      if (err)
536
592
        break;
537
593
 
554
610
 
555
611
/* Skip data from any stream by reading and simply discarding it. */
556
612
static svn_error_t *
557
 
skip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_fn)
 
613
skip_default_handler(void *baton, apr_size_t len, svn_read_fn_t read_full_fn)
558
614
{
559
615
  apr_size_t bytes_read = 1;
560
616
  char buffer[4096];
563
619
  while ((to_read > 0) && (bytes_read > 0))
564
620
    {
565
621
      bytes_read = sizeof(buffer) < to_read ? sizeof(buffer) : to_read;
566
 
      SVN_ERR(read_fn(baton, buffer, &bytes_read));
 
622
      SVN_ERR(read_full_fn(baton, buffer, &bytes_read));
567
623
      to_read -= bytes_read;
568
624
    }
569
625
 
613
669
  svn_stream_t *stream;
614
670
 
615
671
  stream = svn_stream_create(NULL, pool);
616
 
  svn_stream_set_read(stream, read_handler_empty);
 
672
  svn_stream_set_read2(stream, read_handler_empty, read_handler_empty);
617
673
  svn_stream_set_write(stream, write_handler_empty);
618
674
  svn_stream_set_mark(stream, mark_handler_empty);
619
675
  svn_stream_set_seek(stream, seek_handler_empty);
685
741
static svn_error_t *
686
742
read_handler_disown(void *baton, char *buffer, apr_size_t *len)
687
743
{
688
 
  return svn_error_trace(svn_stream_read(baton, buffer, len));
 
744
  return svn_error_trace(svn_stream_read2(baton, buffer, len));
 
745
}
 
746
 
 
747
static svn_error_t *
 
748
read_full_handler_disown(void *baton, char *buffer, apr_size_t *len)
 
749
{
 
750
  return svn_error_trace(svn_stream_read_full(baton, buffer, len));
689
751
}
690
752
 
691
753
static svn_error_t *
712
774
  return svn_error_trace(svn_stream_seek(baton, mark));
713
775
}
714
776
 
 
777
static svn_error_t *
 
778
data_available_disown(void *baton, svn_boolean_t *data_available)
 
779
{
 
780
  return svn_error_trace(svn_stream_data_available(baton, data_available));
 
781
}
 
782
 
715
783
static svn_boolean_t
716
784
is_buffered_handler_disown(void *baton)
717
785
{
723
791
{
724
792
  svn_stream_t *s = svn_stream_create(stream, pool);
725
793
 
726
 
  svn_stream_set_read(s, read_handler_disown);
 
794
  svn_stream_set_read2(s, read_handler_disown, read_full_handler_disown);
727
795
  svn_stream_set_skip(s, skip_handler_disown);
728
796
  svn_stream_set_write(s, write_handler_disown);
729
797
  svn_stream_set_mark(s, mark_handler_disown);
730
798
  svn_stream_set_seek(s, seek_handler_disown);
 
799
  svn_stream_set_data_available(s, data_available_disown);
731
800
  svn_stream__set_is_buffered(s, is_buffered_handler_disown);
732
801
 
733
802
  return s;
751
820
{
752
821
  struct baton_apr *btn = baton;
753
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
 
 
850
static svn_error_t *
 
851
read_full_handler_apr(void *baton, char *buffer, apr_size_t *len)
 
852
{
 
853
  struct baton_apr *btn = baton;
 
854
  svn_error_t *err;
754
855
  svn_boolean_t eof;
755
856
 
756
857
  if (*len == 1)
833
934
  return SVN_NO_ERROR;
834
935
}
835
936
 
 
937
static svn_error_t *
 
938
data_available_handler_apr(void *baton, svn_boolean_t *data_available)
 
939
{
 
940
  struct baton_apr *btn = baton;
 
941
  apr_pollfd_t pfd;
 
942
  apr_status_t status;
 
943
  int n;
 
944
 
 
945
  pfd.desc_type = APR_POLL_FILE;
 
946
  pfd.desc.f = btn->file;
 
947
  pfd.p = btn->pool; /* If we had a scratch pool... Luckily apr doesn't
 
948
                        store anything in this pool at this time */
 
949
  pfd.reqevents = APR_POLLIN;
 
950
 
 
951
  status = apr_poll(&pfd, 1, &n, 0);
 
952
 
 
953
  if (status == APR_SUCCESS)
 
954
    {
 
955
      *data_available = (n > 0);
 
956
      return SVN_NO_ERROR;
 
957
    }
 
958
  else if (APR_STATUS_IS_EOF(status) || APR_STATUS_IS_TIMEUP(status))
 
959
    {
 
960
      *data_available = FALSE;
 
961
      return SVN_NO_ERROR;
 
962
    }
 
963
  else
 
964
    {
 
965
      return svn_error_create(SVN_ERR_STREAM_NOT_SUPPORTED,
 
966
                              svn_error_wrap_apr(
 
967
                                  status,
 
968
                                  _("Polling for available data on filestream "
 
969
                                    "failed")),
 
970
                              NULL);
 
971
    }
 
972
}
 
973
 
836
974
static svn_boolean_t
837
975
is_buffered_handler_apr(void *baton)
838
976
{
909
1047
  baton->file = file;
910
1048
  baton->pool = pool;
911
1049
  stream = svn_stream_create(baton, pool);
912
 
  svn_stream_set_read(stream, read_handler_apr);
 
1050
  svn_stream_set_read2(stream, read_handler_apr, read_full_handler_apr);
913
1051
  svn_stream_set_write(stream, write_handler_apr);
914
1052
  svn_stream_set_skip(stream, skip_handler_apr);
915
1053
  svn_stream_set_mark(stream, mark_handler_apr);
916
1054
  svn_stream_set_seek(stream, seek_handler_apr);
 
1055
  svn_stream_set_data_available(stream, data_available_handler_apr);
917
1056
  svn_stream__set_is_buffered(stream, is_buffered_handler_apr);
918
1057
  stream->file = file;
919
1058
 
941
1080
struct zbaton {
942
1081
  z_stream *in;                 /* compressed stream for reading */
943
1082
  z_stream *out;                /* compressed stream for writing */
944
 
  svn_read_fn_t read;           /* substream's read function */
945
 
  svn_write_fn_t write;         /* substream's write function */
946
 
  svn_close_fn_t close;         /* substream's close function */
 
1083
  void *substream;              /* The substream */
947
1084
  void *read_buffer;            /* buffer   used   for  reading   from
948
1085
                                   substream */
949
1086
  int read_flush;               /* what flush mode to use while
950
1087
                                   reading */
951
1088
  apr_pool_t *pool;             /* The pool this baton is allocated
952
1089
                                   on */
953
 
  void *subbaton;               /* The substream's baton */
954
1090
};
955
1091
 
956
1092
/* zlib alloc function. opaque is the pool we need. */
971
1107
 
972
1108
/* Helper function to figure out the sync mode */
973
1109
static svn_error_t *
974
 
read_helper_gz(svn_read_fn_t read_fn,
975
 
               void *baton,
 
1110
read_helper_gz(svn_stream_t *substream,
976
1111
               char *buffer,
977
1112
               uInt *len, int *zflush)
978
1113
{
982
1117
     uInt, but Subversion's API requires apr_size_t. */
983
1118
  apr_size_t apr_len = (apr_size_t) *len;
984
1119
 
985
 
  SVN_ERR((*read_fn)(baton, buffer, &apr_len));
 
1120
  SVN_ERR(svn_stream_read_full(substream, buffer, &apr_len));
986
1121
 
987
1122
  /* Type cast back to uInt type that zlib uses.  On LP64 platforms
988
1123
     apr_size_t will be bigger than uInt. */
1012
1147
      btn->in->next_in = btn->read_buffer;
1013
1148
      btn->in->avail_in = ZBUFFER_SIZE;
1014
1149
 
1015
 
      SVN_ERR(read_helper_gz(btn->read, btn->subbaton, btn->read_buffer,
 
1150
      SVN_ERR(read_helper_gz(btn->substream, btn->read_buffer,
1016
1151
                             &btn->in->avail_in, &btn->read_flush));
1017
1152
 
1018
1153
      zerr = inflateInit(btn->in);
1028
1163
        {
1029
1164
          btn->in->avail_in = ZBUFFER_SIZE;
1030
1165
          btn->in->next_in = btn->read_buffer;
1031
 
          SVN_ERR(read_helper_gz(btn->read, btn->subbaton, btn->read_buffer,
 
1166
          SVN_ERR(read_helper_gz(btn->substream, btn->read_buffer,
1032
1167
                                 &btn->in->avail_in, &btn->read_flush));
1033
1168
        }
1034
1169
 
1090
1225
      SVN_ERR(svn_error__wrap_zlib(zerr, "deflate", btn->out->msg));
1091
1226
      write_len = buf_size - btn->out->avail_out;
1092
1227
      if (write_len > 0)
1093
 
        SVN_ERR(btn->write(btn->subbaton, write_buf, &write_len));
 
1228
        SVN_ERR(svn_stream_write(btn->substream, write_buf, &write_len));
1094
1229
    }
1095
1230
 
1096
1231
  svn_pool_destroy(subpool);
1129
1264
                                                        btn->out->msg));
1130
1265
          write_len = ZBUFFER_SIZE - btn->out->avail_out;
1131
1266
          if (write_len > 0)
1132
 
            SVN_ERR(btn->write(btn->subbaton, buf, &write_len));
 
1267
            SVN_ERR(svn_stream_write(btn->substream, buf, &write_len));
1133
1268
          if (zerr == Z_STREAM_END)
1134
1269
            break;
1135
1270
        }
1138
1273
      SVN_ERR(svn_error__wrap_zlib(zerr, "deflateEnd", btn->out->msg));
1139
1274
    }
1140
1275
 
1141
 
  if (btn->close != NULL)
1142
 
    return svn_error_trace(btn->close(btn->subbaton));
1143
 
  else
1144
 
    return SVN_NO_ERROR;
 
1276
  return svn_error_trace(svn_stream_close(btn->substream));
1145
1277
}
1146
1278
 
1147
1279
 
1155
1287
 
1156
1288
  baton = apr_palloc(pool, sizeof(*baton));
1157
1289
  baton->in = baton->out = NULL;
1158
 
  baton->read = stream->read_fn;
1159
 
  baton->write = stream->write_fn;
1160
 
  baton->close = stream->close_fn;
1161
 
  baton->subbaton = stream->baton;
 
1290
  baton->substream = stream;
1162
1291
  baton->pool = pool;
1163
1292
  baton->read_buffer = NULL;
1164
1293
  baton->read_flush = Z_SYNC_FLUSH;
1165
1294
 
1166
1295
  zstream = svn_stream_create(baton, pool);
1167
 
  svn_stream_set_read(zstream, read_handler_gz);
 
1296
  svn_stream_set_read2(zstream, NULL /* only full read support */,
 
1297
                       read_handler_gz);
1168
1298
  svn_stream_set_write(zstream, write_handler_gz);
1169
1299
  svn_stream_set_close(zstream, close_handler_gz);
1170
1300
 
1192
1322
read_handler_checksum(void *baton, char *buffer, apr_size_t *len)
1193
1323
{
1194
1324
  struct checksum_stream_baton *btn = baton;
 
1325
 
 
1326
  SVN_ERR(svn_stream_read2(btn->proxy, buffer, len));
 
1327
 
 
1328
  if (btn->read_checksum)
 
1329
    SVN_ERR(svn_checksum_update(btn->read_ctx, buffer, *len));
 
1330
 
 
1331
  return SVN_NO_ERROR;
 
1332
}
 
1333
 
 
1334
static svn_error_t *
 
1335
read_full_handler_checksum(void *baton, char *buffer, apr_size_t *len)
 
1336
{
 
1337
  struct checksum_stream_baton *btn = baton;
1195
1338
  apr_size_t saved_len = *len;
1196
1339
 
1197
 
  SVN_ERR(svn_stream_read(btn->proxy, buffer, len));
 
1340
  SVN_ERR(svn_stream_read_full(btn->proxy, buffer, len));
1198
1341
 
1199
1342
  if (btn->read_checksum)
1200
1343
    SVN_ERR(svn_checksum_update(btn->read_ctx, buffer, *len));
1217
1360
  return svn_error_trace(svn_stream_write(btn->proxy, buffer, len));
1218
1361
}
1219
1362
 
 
1363
static svn_error_t *
 
1364
data_available_handler_checksum(void *baton, svn_boolean_t *data_available)
 
1365
{
 
1366
  struct checksum_stream_baton *btn = baton;
 
1367
 
 
1368
  return svn_error_trace(svn_stream_data_available(btn->proxy,
 
1369
                                                   data_available));
 
1370
}
1220
1371
 
1221
1372
static svn_error_t *
1222
1373
close_handler_checksum(void *baton)
1232
1383
 
1233
1384
      do
1234
1385
        {
1235
 
          SVN_ERR(read_handler_checksum(baton, buf, &len));
 
1386
          SVN_ERR(read_full_handler_checksum(baton, buf, &len));
1236
1387
        }
1237
1388
      while (btn->read_more);
1238
1389
    }
1279
1430
  baton->pool = pool;
1280
1431
 
1281
1432
  s = svn_stream_create(baton, pool);
1282
 
  svn_stream_set_read(s, read_handler_checksum);
 
1433
  svn_stream_set_read2(s, read_handler_checksum, read_full_handler_checksum);
1283
1434
  svn_stream_set_write(s, write_handler_checksum);
 
1435
  svn_stream_set_data_available(s, data_available_handler_checksum);
1284
1436
  svn_stream_set_close(s, close_handler_checksum);
1285
1437
  return s;
1286
1438
}
1287
1439
 
1288
 
struct md5_stream_baton
1289
 
{
1290
 
  const unsigned char **read_digest;
1291
 
  const unsigned char **write_digest;
1292
 
  svn_checksum_t *read_checksum;
1293
 
  svn_checksum_t *write_checksum;
1294
 
  svn_stream_t *proxy;
1295
 
  apr_pool_t *pool;
1296
 
};
1297
 
 
1298
 
static svn_error_t *
1299
 
read_handler_md5(void *baton, char *buffer, apr_size_t *len)
1300
 
{
1301
 
  struct md5_stream_baton *btn = baton;
1302
 
  return svn_error_trace(svn_stream_read(btn->proxy, buffer, len));
1303
 
}
1304
 
 
1305
 
static svn_error_t *
1306
 
skip_handler_md5(void *baton, apr_size_t len)
1307
 
{
1308
 
  struct md5_stream_baton *btn = baton;
1309
 
  return svn_error_trace(svn_stream_skip(btn->proxy, len));
1310
 
}
1311
 
 
1312
 
static svn_error_t *
1313
 
write_handler_md5(void *baton, const char *buffer, apr_size_t *len)
1314
 
{
1315
 
  struct md5_stream_baton *btn = baton;
1316
 
  return svn_error_trace(svn_stream_write(btn->proxy, buffer, len));
1317
 
}
1318
 
 
1319
 
static svn_error_t *
1320
 
close_handler_md5(void *baton)
1321
 
{
1322
 
  struct md5_stream_baton *btn = baton;
1323
 
 
1324
 
  SVN_ERR(svn_stream_close(btn->proxy));
1325
 
 
1326
 
  if (btn->read_digest)
1327
 
    *btn->read_digest
1328
 
      = apr_pmemdup(btn->pool, btn->read_checksum->digest,
1329
 
                    APR_MD5_DIGESTSIZE);
1330
 
 
1331
 
  if (btn->write_digest)
1332
 
    *btn->write_digest
1333
 
      = apr_pmemdup(btn->pool, btn->write_checksum->digest,
1334
 
                    APR_MD5_DIGESTSIZE);
1335
 
 
1336
 
  return SVN_NO_ERROR;
1337
 
}
1338
 
 
1339
 
 
1340
 
svn_stream_t *
1341
 
svn_stream_checksummed(svn_stream_t *stream,
1342
 
                       const unsigned char **read_digest,
1343
 
                       const unsigned char **write_digest,
1344
 
                       svn_boolean_t read_all,
1345
 
                       apr_pool_t *pool)
1346
 
{
1347
 
  svn_stream_t *s;
1348
 
  struct md5_stream_baton *baton;
1349
 
 
1350
 
  if (! read_digest && ! write_digest)
1351
 
    return stream;
1352
 
 
1353
 
  baton = apr_palloc(pool, sizeof(*baton));
1354
 
  baton->read_digest = read_digest;
1355
 
  baton->write_digest = write_digest;
1356
 
  baton->pool = pool;
1357
 
 
1358
 
  /* Set BATON->proxy to a stream that will fill in BATON->read_checksum
1359
 
   * and BATON->write_checksum (if we want them) when it is closed. */
1360
 
  baton->proxy
1361
 
    = svn_stream_checksummed2(stream,
1362
 
                              read_digest ? &baton->read_checksum : NULL,
1363
 
                              write_digest ? &baton->write_checksum : NULL,
1364
 
                              svn_checksum_md5,
1365
 
                              read_all, pool);
1366
 
 
1367
 
  /* Create a stream that will forward its read/write/close operations to
1368
 
   * BATON->proxy and will fill in *READ_DIGEST and *WRITE_DIGEST (if we
1369
 
   * want them) after it closes BATON->proxy. */
1370
 
  s = svn_stream_create(baton, pool);
1371
 
  svn_stream_set_read(s, read_handler_md5);
1372
 
  svn_stream_set_skip(s, skip_handler_md5);
1373
 
  svn_stream_set_write(s, write_handler_md5);
1374
 
  svn_stream_set_close(s, close_handler_md5);
1375
 
  return s;
1376
 
}
1377
 
 
1378
 
 
1379
 
 
1380
 
 
1381
1440
/* Miscellaneous stream functions. */
 
1441
 
 
1442
svn_error_t *
 
1443
svn_stringbuf_from_stream(svn_stringbuf_t **str,
 
1444
                          svn_stream_t *stream,
 
1445
                          apr_size_t len_hint,
 
1446
                          apr_pool_t *result_pool)
 
1447
{
 
1448
#define MIN_READ_SIZE 64
 
1449
 
 
1450
  apr_size_t to_read = 0;
 
1451
  svn_stringbuf_t *text
 
1452
    = svn_stringbuf_create_ensure(len_hint ? len_hint : MIN_READ_SIZE,
 
1453
                                  result_pool);
 
1454
 
 
1455
  do
 
1456
    {
 
1457
      to_read = text->blocksize - 1 - text->len;
 
1458
      SVN_ERR(svn_stream_read_full(stream, text->data + text->len, &to_read));
 
1459
      text->len += to_read;
 
1460
 
 
1461
      if (to_read && text->blocksize < text->len + MIN_READ_SIZE)
 
1462
        svn_stringbuf_ensure(text, text->blocksize * 2);
 
1463
    }
 
1464
  while (to_read);
 
1465
 
 
1466
  text->data[text->len] = '\0';
 
1467
  *str = text;
 
1468
 
 
1469
  return SVN_NO_ERROR;
 
1470
}
 
1471
 
1382
1472
struct stringbuf_stream_baton
1383
1473
{
1384
1474
  svn_stringbuf_t *str;
1454
1544
  return SVN_NO_ERROR;
1455
1545
}
1456
1546
 
 
1547
static svn_error_t *
 
1548
data_available_handler_stringbuf(void *baton, svn_boolean_t *data_available)
 
1549
{
 
1550
  struct stringbuf_stream_baton *btn = baton;
 
1551
 
 
1552
  *data_available = ((btn->str->len - btn->amt_read) > 0);
 
1553
  return SVN_NO_ERROR;
 
1554
}
 
1555
 
1457
1556
static svn_boolean_t
1458
1557
is_buffered_handler_stringbuf(void *baton)
1459
1558
{
1474
1573
  baton->str = str;
1475
1574
  baton->amt_read = 0;
1476
1575
  stream = svn_stream_create(baton, pool);
1477
 
  svn_stream_set_read(stream, read_handler_stringbuf);
 
1576
  svn_stream_set_read2(stream, read_handler_stringbuf, read_handler_stringbuf);
1478
1577
  svn_stream_set_skip(stream, skip_handler_stringbuf);
1479
1578
  svn_stream_set_write(stream, write_handler_stringbuf);
1480
1579
  svn_stream_set_mark(stream, mark_handler_stringbuf);
1481
1580
  svn_stream_set_seek(stream, seek_handler_stringbuf);
 
1581
  svn_stream_set_data_available(stream, data_available_handler_stringbuf);
1482
1582
  svn_stream__set_is_buffered(stream, is_buffered_handler_stringbuf);
1483
1583
  return stream;
1484
1584
}
1549
1649
  return SVN_NO_ERROR;
1550
1650
}
1551
1651
 
 
1652
static svn_error_t *
 
1653
data_available_handler_string(void *baton, svn_boolean_t *data_available)
 
1654
{
 
1655
  struct string_stream_baton *btn = baton;
 
1656
 
 
1657
  *data_available = ((btn->str->len - btn->amt_read) > 0);
 
1658
  return SVN_NO_ERROR;
 
1659
}
 
1660
 
1552
1661
static svn_boolean_t
1553
1662
is_buffered_handler_string(void *baton)
1554
1663
{
1569
1678
  baton->str = str;
1570
1679
  baton->amt_read = 0;
1571
1680
  stream = svn_stream_create(baton, pool);
1572
 
  svn_stream_set_read(stream, read_handler_string);
 
1681
  svn_stream_set_read2(stream, read_handler_string, read_handler_string);
1573
1682
  svn_stream_set_mark(stream, mark_handler_string);
1574
1683
  svn_stream_set_seek(stream, seek_handler_string);
1575
1684
  svn_stream_set_skip(stream, skip_handler_string);
 
1685
  svn_stream_set_data_available(stream, data_available_handler_string);
1576
1686
  svn_stream__set_is_buffered(stream, is_buffered_handler_string);
1577
1687
  return stream;
1578
1688
}
1640
1750
    {
1641
1751
      apr_size_t len = SVN__STREAM_CHUNK_SIZE;
1642
1752
 
1643
 
      SVN_ERR(svn_stream_read(stream, buffer, &len));
 
1753
      SVN_ERR(svn_stream_read_full(stream, buffer, &len));
1644
1754
      svn_stringbuf_appendbytes(work, buffer, len);
1645
1755
 
1646
1756
      if (len < SVN__STREAM_CHUNK_SIZE)
1657
1767
}
1658
1768
 
1659
1769
 
1660
 
/* These are somewhat arbirary, if we ever get good empirical data as to
 
1770
/* These are somewhat arbitrary, if we ever get good empirical data as to
1661
1771
   actually valid values, feel free to update them. */
1662
1772
#define BUFFER_BLOCK_SIZE 1024
1663
1773
#define BUFFER_MAX_SIZE 100000
1665
1775
svn_stream_t *
1666
1776
svn_stream_buffered(apr_pool_t *result_pool)
1667
1777
{
1668
 
  return svn_stream__from_spillbuf(BUFFER_BLOCK_SIZE, BUFFER_MAX_SIZE,
 
1778
  return svn_stream__from_spillbuf(svn_spillbuf__create(BUFFER_BLOCK_SIZE,
 
1779
                                                        BUFFER_MAX_SIZE,
 
1780
                                                        result_pool),
1669
1781
                                   result_pool);
1670
1782
}
1671
1783
 
1721
1833
  lazyopen_baton_t *b = baton;
1722
1834
 
1723
1835
  SVN_ERR(lazyopen_if_unopened(b));
1724
 
  SVN_ERR(svn_stream_read(b->real_stream, buffer, len));
 
1836
  SVN_ERR(svn_stream_read2(b->real_stream, buffer, len));
 
1837
 
 
1838
  return SVN_NO_ERROR;
 
1839
}
 
1840
 
 
1841
/* Implements svn_read_fn_t */
 
1842
static svn_error_t *
 
1843
read_full_handler_lazyopen(void *baton,
 
1844
                      char *buffer,
 
1845
                      apr_size_t *len)
 
1846
{
 
1847
  lazyopen_baton_t *b = baton;
 
1848
 
 
1849
  SVN_ERR(lazyopen_if_unopened(b));
 
1850
  SVN_ERR(svn_stream_read_full(b->real_stream, buffer, len));
1725
1851
 
1726
1852
  return SVN_NO_ERROR;
1727
1853
}
1794
1920
  return SVN_NO_ERROR;
1795
1921
}
1796
1922
 
 
1923
static svn_error_t *
 
1924
data_available_handler_lazyopen(void *baton,
 
1925
                                svn_boolean_t *data_available)
 
1926
{
 
1927
  lazyopen_baton_t *b = baton;
 
1928
 
 
1929
  SVN_ERR(lazyopen_if_unopened(b));
 
1930
  return svn_error_trace(svn_stream_data_available(b->real_stream,
 
1931
                                                   data_available));
 
1932
}
 
1933
 
1797
1934
/* Implements svn_stream__is_buffered_fn_t */
1798
1935
static svn_boolean_t
1799
1936
is_buffered_lazyopen(void *baton)
1823
1960
  lob->open_on_close = open_on_close;
1824
1961
 
1825
1962
  stream = svn_stream_create(lob, result_pool);
1826
 
  svn_stream_set_read(stream, read_handler_lazyopen);
 
1963
  svn_stream_set_read2(stream, read_handler_lazyopen,
 
1964
                       read_full_handler_lazyopen);
1827
1965
  svn_stream_set_skip(stream, skip_handler_lazyopen);
1828
1966
  svn_stream_set_write(stream, write_handler_lazyopen);
1829
1967
  svn_stream_set_close(stream, close_handler_lazyopen);
1830
1968
  svn_stream_set_mark(stream, mark_handler_lazyopen);
1831
1969
  svn_stream_set_seek(stream, seek_handler_lazyopen);
 
1970
  svn_stream_set_data_available(stream, data_available_handler_lazyopen);
1832
1971
  svn_stream__set_is_buffered(stream, is_buffered_lazyopen);
1833
1972
 
1834
1973
  return stream;
1835
1974
}
 
1975
 
 
1976
/* Baton for install streams */
 
1977
struct install_baton_t
 
1978
{
 
1979
  struct baton_apr baton_apr;
 
1980
  const char *tmp_path;
 
1981
};
 
1982
 
 
1983
#ifdef WIN32
 
1984
 
 
1985
#if _WIN32_WINNT < 0x600 /* Does the SDK assume Windows Vista+? */
 
1986
typedef struct _FILE_RENAME_INFO {
 
1987
  BOOL   ReplaceIfExists;
 
1988
  HANDLE RootDirectory;
 
1989
  DWORD  FileNameLength;
 
1990
  WCHAR  FileName[1];
 
1991
} FILE_RENAME_INFO, *PFILE_RENAME_INFO;
 
1992
 
 
1993
typedef struct _FILE_DISPOSITION_INFO {
 
1994
  BOOL DeleteFile;
 
1995
} FILE_DISPOSITION_INFO, *PFILE_DISPOSITION_INFO;
 
1996
 
 
1997
#define FileRenameInfo 3
 
1998
#define FileDispositionInfo 4
 
1999
 
 
2000
typedef BOOL (WINAPI *SetFileInformationByHandle_t)(HANDLE hFile,
 
2001
                                                    int FileInformationClass,
 
2002
                                                    LPVOID lpFileInformation,
 
2003
                                                    DWORD dwBufferSize);
 
2004
 
 
2005
static volatile SetFileInformationByHandle_t SetFileInformationByHandle_p = 0;
 
2006
#define SetFileInformationByHandle (*SetFileInformationByHandle_p)
 
2007
 
 
2008
static volatile svn_atomic_t SetFileInformationByHandle_a = 0;
 
2009
 
 
2010
 
 
2011
static svn_error_t *
 
2012
find_SetFileInformationByHandle(void *baton, apr_pool_t *scratch_pool)
 
2013
{
 
2014
  HMODULE kernel32 = GetModuleHandle("Kernel32.dll");
 
2015
 
 
2016
  if (kernel32)
 
2017
    {
 
2018
      SetFileInformationByHandle_p =
 
2019
                    (SetFileInformationByHandle_t)
 
2020
                      GetProcAddress(kernel32, "SetFileInformationByHandle");
 
2021
    }
 
2022
 
 
2023
  return SVN_NO_ERROR;
 
2024
}
 
2025
#endif /* WIN32 < Vista */
 
2026
 
 
2027
/* Create and open a tempfile in DIRECTORY. Return its handle and path */
 
2028
static svn_error_t *
 
2029
create_tempfile(HANDLE *hFile,
 
2030
                const char **file_path,
 
2031
                const char *directory,
 
2032
                apr_pool_t *result_pool,
 
2033
                apr_pool_t *scratch_pool)
 
2034
{
 
2035
  const char *unique_name;
 
2036
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
2037
  static svn_atomic_t tempname_counter;
 
2038
  int baseNr = (GetTickCount() << 11) + 13 * svn_atomic_inc(&tempname_counter)
 
2039
               + GetCurrentProcessId();
 
2040
  int i = 0;
 
2041
  HANDLE h;
 
2042
 
 
2043
  /* Shares common idea with io.c's temp_file_create */
 
2044
 
 
2045
  do
 
2046
    {
 
2047
      apr_uint32_t unique_nr;
 
2048
      WCHAR *w_name;
 
2049
 
 
2050
      /* Generate a number that should be unique for this application and
 
2051
         usually for the entire computer to reduce the number of cycles
 
2052
         through this loop. (A bit of calculation is much cheaper than
 
2053
         disk io) */
 
2054
      unique_nr = baseNr + 7 * i++;
 
2055
 
 
2056
 
 
2057
      svn_pool_clear(iterpool);
 
2058
      unique_name = svn_dirent_join(directory,
 
2059
                                    apr_psprintf(iterpool, "svn-%X",
 
2060
                                                 unique_nr),
 
2061
                                    iterpool);
 
2062
 
 
2063
      SVN_ERR(svn_io__utf8_to_unicode_longpath(&w_name, unique_name,
 
2064
                                               iterpool));
 
2065
 
 
2066
      /* Create a completely not-sharable file to avoid indexers, and other
 
2067
         filesystem watchers locking the file while we are still writing.
 
2068
 
 
2069
         We need DELETE privileges to move the file. */
 
2070
      h = CreateFileW(w_name, GENERIC_WRITE | DELETE, 0 /* share */,
 
2071
                      NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
 
2072
 
 
2073
      if (h == INVALID_HANDLE_VALUE)
 
2074
        {
 
2075
          apr_status_t status = apr_get_os_error();
 
2076
          if (i > 1000)
 
2077
            return svn_error_createf(SVN_ERR_IO_UNIQUE_NAMES_EXHAUSTED,
 
2078
                           svn_error_wrap_apr(status, NULL),
 
2079
                           _("Unable to make name in '%s'"),
 
2080
                           svn_dirent_local_style(directory, scratch_pool));
 
2081
 
 
2082
          if (!APR_STATUS_IS_EEXIST(status) && !APR_STATUS_IS_EACCES(status))
 
2083
            return svn_error_wrap_apr(status, NULL);
 
2084
        }
 
2085
    }
 
2086
  while (h == INVALID_HANDLE_VALUE);
 
2087
 
 
2088
  *hFile = h;
 
2089
  *file_path = apr_pstrdup(result_pool, unique_name);
 
2090
  svn_pool_destroy(iterpool);
 
2091
 
 
2092
  return SVN_NO_ERROR;
 
2093
}
 
2094
 
 
2095
/* Implements svn_close_fn_t */
 
2096
static svn_error_t *
 
2097
install_close(void *baton)
 
2098
{
 
2099
  struct install_baton_t *ib = baton;
 
2100
 
 
2101
  /* Flush the data cached in APR, but don't close the file yet */
 
2102
  SVN_ERR(svn_io_file_flush(ib->baton_apr.file, ib->baton_apr.pool));
 
2103
 
 
2104
  return SVN_NO_ERROR;
 
2105
}
 
2106
 
 
2107
#endif /* WIN32 */
 
2108
 
 
2109
svn_error_t *
 
2110
svn_stream__create_for_install(svn_stream_t **install_stream,
 
2111
                               const char *tmp_abspath,
 
2112
                               apr_pool_t *result_pool,
 
2113
                               apr_pool_t *scratch_pool)
 
2114
{
 
2115
  apr_file_t *file;
 
2116
  struct install_baton_t *ib;
 
2117
  const char *tmp_path;
 
2118
 
 
2119
#ifdef WIN32
 
2120
  HANDLE hInstall;
 
2121
  apr_status_t status;
 
2122
 
 
2123
  SVN_ERR_ASSERT(svn_dirent_is_absolute(tmp_abspath));
 
2124
 
 
2125
  SVN_ERR(create_tempfile(&hInstall, &tmp_path, tmp_abspath,
 
2126
                          scratch_pool, scratch_pool));
 
2127
 
 
2128
  /* Wrap as a standard APR file to allow sharing implementation.
 
2129
 
 
2130
     But do note that some file functions (such as retrieving the name)
 
2131
     don't work on this wrapper. */
 
2132
  /* ### Buffered, or not? */
 
2133
  status = apr_os_file_put(&file, &hInstall,
 
2134
                           APR_WRITE | APR_BINARY | APR_BUFFERED,
 
2135
                           result_pool);
 
2136
 
 
2137
  if (status)
 
2138
    {
 
2139
      CloseHandle(hInstall);
 
2140
      return svn_error_wrap_apr(status, NULL);
 
2141
    }
 
2142
 
 
2143
  tmp_path = svn_dirent_internal_style(tmp_path, result_pool);
 
2144
#else
 
2145
 
 
2146
  SVN_ERR_ASSERT(svn_dirent_is_absolute(tmp_abspath));
 
2147
 
 
2148
  SVN_ERR(svn_io_open_unique_file3(&file, &tmp_path, tmp_abspath,
 
2149
                                   svn_io_file_del_none,
 
2150
                                   result_pool, scratch_pool));
 
2151
#endif
 
2152
  *install_stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
 
2153
 
 
2154
  ib = apr_pcalloc(result_pool, sizeof(*ib));
 
2155
  ib->baton_apr = *(struct baton_apr*)(*install_stream)->baton;
 
2156
 
 
2157
  assert((void*)&ib->baton_apr == (void*)ib); /* baton pointer is the same */
 
2158
 
 
2159
  (*install_stream)->baton = ib;
 
2160
 
 
2161
  ib->tmp_path = tmp_path;
 
2162
 
 
2163
#ifdef WIN32
 
2164
  /* Don't close the file on stream close; flush instead */
 
2165
  svn_stream_set_close(*install_stream, install_close);
 
2166
#else
 
2167
  /* ### Install pool cleanup handler for tempfile? */
 
2168
#endif
 
2169
 
 
2170
  return SVN_NO_ERROR;
 
2171
}
 
2172
 
 
2173
svn_error_t *
 
2174
svn_stream__install_stream(svn_stream_t *install_stream,
 
2175
                           const char *final_abspath,
 
2176
                           svn_boolean_t make_parents,
 
2177
                           apr_pool_t *scratch_pool)
 
2178
{
 
2179
  struct install_baton_t *ib = install_stream->baton;
 
2180
  svn_error_t *err;
 
2181
 
 
2182
  SVN_ERR_ASSERT(svn_dirent_is_absolute(final_abspath));
 
2183
#ifdef WIN32
 
2184
 
 
2185
#if _WIN32_WINNT < 0x600
 
2186
  SVN_ERR(svn_atomic__init_once(&SetFileInformationByHandle_a,
 
2187
                                find_SetFileInformationByHandle,
 
2188
                                NULL, scratch_pool));
 
2189
 
 
2190
  if (!SetFileInformationByHandle_p)
 
2191
    SVN_ERR(svn_io_file_close(ib->baton_apr.file, scratch_pool));
 
2192
  else
 
2193
#endif /* WIN32 < Windows Vista */
 
2194
    {
 
2195
      WCHAR *w_final_abspath;
 
2196
      size_t path_len;
 
2197
      size_t rename_size;
 
2198
      FILE_RENAME_INFO *rename_info;
 
2199
      HANDLE hFile;
 
2200
 
 
2201
      apr_os_file_get(&hFile, ib->baton_apr.file);
 
2202
 
 
2203
      SVN_ERR(svn_io__utf8_to_unicode_longpath(&w_final_abspath,
 
2204
                                               svn_dirent_local_style(
 
2205
                                                          final_abspath,
 
2206
                                                          scratch_pool),
 
2207
                                               scratch_pool));
 
2208
      path_len = wcslen(w_final_abspath);
 
2209
      rename_size = sizeof(*rename_info) + sizeof(WCHAR) * path_len;
 
2210
 
 
2211
      /* The rename info struct doesn't need hacks for long paths,
 
2212
         so no ugly escaping calls here */
 
2213
      rename_info = apr_pcalloc(scratch_pool, rename_size);
 
2214
      rename_info->ReplaceIfExists = TRUE;
 
2215
      rename_info->FileNameLength = path_len;
 
2216
      memcpy(rename_info->FileName, w_final_abspath, path_len * sizeof(WCHAR));
 
2217
 
 
2218
      if (!SetFileInformationByHandle(hFile, FileRenameInfo, rename_info,
 
2219
                                      rename_size))
 
2220
        {
 
2221
          svn_boolean_t retry = FALSE;
 
2222
          err = svn_error_wrap_apr(apr_get_os_error(), NULL);
 
2223
 
 
2224
          /* ### rhuijben: I wouldn't be surprised if we later find out that we
 
2225
                           have to fall back to close+rename on some specific
 
2226
                           error values here, to support some non standard NAS
 
2227
                           and filesystem scenarios. */
 
2228
 
 
2229
          if (make_parents && err && APR_STATUS_IS_ENOENT(err->apr_err))
 
2230
            {
 
2231
              svn_error_t *err2;
 
2232
 
 
2233
              err2 = svn_io_make_dir_recursively(svn_dirent_dirname(final_abspath,
 
2234
                                                            scratch_pool),
 
2235
                                                 scratch_pool);
 
2236
 
 
2237
              if (err2)
 
2238
                return svn_error_trace(svn_error_compose_create(err, err2));
 
2239
              else
 
2240
                svn_error_clear(err);
 
2241
 
 
2242
              retry = TRUE;
 
2243
              err = NULL;
 
2244
            }
 
2245
          else if (err && (APR_STATUS_IS_EACCES(err->apr_err)
 
2246
                           || APR_STATUS_IS_EEXIST(err->apr_err)))
 
2247
            {
 
2248
              svn_error_clear(err);
 
2249
              retry = TRUE;
 
2250
              err = NULL;
 
2251
 
 
2252
              /* Set the destination file writable because Windows will not allow
 
2253
                 us to rename when final_abspath is read-only. */
 
2254
              SVN_ERR(svn_io_set_file_read_write(final_abspath, TRUE,
 
2255
                                                 scratch_pool));
 
2256
            }
 
2257
 
 
2258
          if (retry)
 
2259
            {
 
2260
              if (!SetFileInformationByHandle(hFile, FileRenameInfo,
 
2261
                                              rename_info, rename_size))
 
2262
                {
 
2263
                  err = svn_error_wrap_apr(
 
2264
                                apr_get_os_error(),
 
2265
                                _("Can't move '%s' to '%s'"),
 
2266
                                svn_dirent_local_style(ib->tmp_path,
 
2267
                                                       scratch_pool),
 
2268
                                svn_dirent_local_style(final_abspath,
 
2269
                                                       scratch_pool));
 
2270
                }
 
2271
            }
 
2272
        }
 
2273
      else
 
2274
        err = NULL;
 
2275
 
 
2276
      return svn_error_compose_create(err,
 
2277
                                      svn_io_file_close(ib->baton_apr.file,
 
2278
                                                        scratch_pool));
 
2279
    }
 
2280
#endif
 
2281
 
 
2282
  err = svn_io_file_rename(ib->tmp_path, final_abspath, scratch_pool);
 
2283
 
 
2284
  /* A missing directory is too common to not cover here. */
 
2285
  if (make_parents && err && APR_STATUS_IS_ENOENT(err->apr_err))
 
2286
    {
 
2287
      svn_error_t *err2;
 
2288
 
 
2289
      err2 = svn_io_make_dir_recursively(svn_dirent_dirname(final_abspath,
 
2290
                                                            scratch_pool),
 
2291
                                         scratch_pool);
 
2292
 
 
2293
      if (err2)
 
2294
        /* Creating directory didn't work: Return all errors */
 
2295
        return svn_error_trace(svn_error_compose_create(err, err2));
 
2296
      else
 
2297
        /* We could create a directory: retry install */
 
2298
        svn_error_clear(err);
 
2299
 
 
2300
      SVN_ERR(svn_io_file_rename(ib->tmp_path, final_abspath, scratch_pool));
 
2301
    }
 
2302
  else
 
2303
    SVN_ERR(err);
 
2304
 
 
2305
  return SVN_NO_ERROR;
 
2306
}
 
2307
 
 
2308
svn_error_t *
 
2309
svn_stream__install_get_info(apr_finfo_t *finfo,
 
2310
                             svn_stream_t *install_stream,
 
2311
                             apr_int32_t wanted,
 
2312
                             apr_pool_t *scratch_pool)
 
2313
{
 
2314
  struct install_baton_t *ib = install_stream->baton;
 
2315
 
 
2316
#ifdef WIN32
 
2317
  /* On WIN32 the file is still open, so we can obtain the information
 
2318
     from the handle without race conditions */
 
2319
  apr_status_t status;
 
2320
 
 
2321
  status = apr_file_info_get(finfo, wanted, ib->baton_apr.file);
 
2322
 
 
2323
  if (status)
 
2324
    return svn_error_wrap_apr(status, NULL);
 
2325
#else
 
2326
  SVN_ERR(svn_io_stat(finfo, ib->tmp_path, wanted, scratch_pool));
 
2327
#endif
 
2328
 
 
2329
  return SVN_NO_ERROR;
 
2330
}
 
2331
 
 
2332
svn_error_t *
 
2333
svn_stream__install_delete(svn_stream_t *install_stream,
 
2334
                           apr_pool_t *scratch_pool)
 
2335
{
 
2336
  struct install_baton_t *ib = install_stream->baton;
 
2337
 
 
2338
#ifdef WIN32
 
2339
  BOOL done;
 
2340
 
 
2341
#if _WIN32_WINNT < 0x600
 
2342
 
 
2343
  SVN_ERR(svn_atomic__init_once(&SetFileInformationByHandle_a,
 
2344
                                find_SetFileInformationByHandle,
 
2345
                                NULL, scratch_pool));
 
2346
 
 
2347
  if (!SetFileInformationByHandle_p)
 
2348
    done = FALSE;
 
2349
  else
 
2350
#endif /* WIN32 < Windows Vista */
 
2351
    {
 
2352
      FILE_DISPOSITION_INFO disposition_info;
 
2353
      HANDLE hFile;
 
2354
 
 
2355
      apr_os_file_get(&hFile, ib->baton_apr.file);
 
2356
 
 
2357
      disposition_info.DeleteFile = TRUE;
 
2358
 
 
2359
      /* Mark the file as delete on close to avoid having to reopen
 
2360
         the file as part of the delete handling. */
 
2361
      done = SetFileInformationByHandle(hFile, FileDispositionInfo,
 
2362
                                        &disposition_info,
 
2363
                                        sizeof(disposition_info));
 
2364
    }
 
2365
 
 
2366
   SVN_ERR(svn_io_file_close(ib->baton_apr.file, scratch_pool));
 
2367
 
 
2368
   if (done)
 
2369
     return SVN_NO_ERROR; /* File is already gone */
 
2370
#endif
 
2371
 
 
2372
  return svn_error_trace(svn_io_remove_file2(ib->tmp_path, FALSE,
 
2373
                                             scratch_pool));
 
2374
}