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

« back to all changes in this revision

Viewing changes to subversion/libsvn_subr/checksum.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:
21
21
 * ====================================================================
22
22
 */
23
23
 
 
24
#define APR_WANT_BYTEFUNC
24
25
 
25
26
#include <ctype.h>
26
27
 
30
31
#include "svn_checksum.h"
31
32
#include "svn_error.h"
32
33
#include "svn_ctype.h"
 
34
#include "svn_sorts.h"
33
35
 
34
 
#include "sha1.h"
35
 
#include "md5.h"
 
36
#include "checksum.h"
 
37
#include "fnv1a.h"
36
38
 
37
39
#include "private/svn_subr_private.h"
38
40
 
40
42
 
41
43
 
42
44
 
 
45
/* The MD5 digest for the empty string. */
 
46
static const unsigned char md5_empty_string_digest_array[] = {
 
47
  0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
 
48
  0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e
 
49
};
 
50
 
 
51
/* The SHA1 digest for the empty string. */
 
52
static const unsigned char sha1_empty_string_digest_array[] = {
 
53
  0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
 
54
  0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09
 
55
};
 
56
 
 
57
/* The FNV-1a digest for the empty string. */
 
58
static const unsigned char fnv1a_32_empty_string_digest_array[] = {
 
59
  0x81, 0x1c, 0x9d, 0xc5
 
60
};
 
61
 
 
62
/* The FNV-1a digest for the empty string. */
 
63
static const unsigned char fnv1a_32x4_empty_string_digest_array[] = {
 
64
  0xcd, 0x6d, 0x9a, 0x85
 
65
};
 
66
 
 
67
/* Digests for an empty string, indexed by checksum type */
 
68
static const unsigned char * empty_string_digests[] = {
 
69
  md5_empty_string_digest_array,
 
70
  sha1_empty_string_digest_array,
 
71
  fnv1a_32_empty_string_digest_array,
 
72
  fnv1a_32x4_empty_string_digest_array
 
73
};
 
74
 
 
75
/* Digest sizes in bytes, indexed by checksum type */
 
76
static const apr_size_t digest_sizes[] = {
 
77
  APR_MD5_DIGESTSIZE,
 
78
  APR_SHA1_DIGESTSIZE,
 
79
  sizeof(apr_uint32_t),
 
80
  sizeof(apr_uint32_t)
 
81
};
 
82
 
 
83
/* Checksum type prefixes used in serialized checksums. */
 
84
static const char *ckind_str[] = {
 
85
  "$md5 $",
 
86
  "$sha1$",
 
87
  "$fnv1$",
 
88
  "$fnvm$",
 
89
};
 
90
 
43
91
/* Returns the digest size of it's argument. */
44
 
#define DIGESTSIZE(k) ((k) == svn_checksum_md5 ? APR_MD5_DIGESTSIZE : \
45
 
                       (k) == svn_checksum_sha1 ? APR_SHA1_DIGESTSIZE : 0)
46
 
 
 
92
#define DIGESTSIZE(k) \
 
93
  (((k) < svn_checksum_md5 || (k) > svn_checksum_fnv1a_32x4) ? 0 : digest_sizes[k])
 
94
 
 
95
/* Largest supported digest size */
 
96
#define MAX_DIGESTSIZE (MAX(APR_MD5_DIGESTSIZE,APR_SHA1_DIGESTSIZE))
 
97
 
 
98
const unsigned char *
 
99
svn__empty_string_digest(svn_checksum_kind_t kind)
 
100
{
 
101
  return empty_string_digests[kind];
 
102
}
 
103
 
 
104
const char *
 
105
svn__digest_to_cstring_display(const unsigned char digest[],
 
106
                               apr_size_t digest_size,
 
107
                               apr_pool_t *pool)
 
108
{
 
109
  static const char *hex = "0123456789abcdef";
 
110
  char *str = apr_palloc(pool, (digest_size * 2) + 1);
 
111
  apr_size_t i;
 
112
 
 
113
  for (i = 0; i < digest_size; i++)
 
114
    {
 
115
      str[i*2]   = hex[digest[i] >> 4];
 
116
      str[i*2+1] = hex[digest[i] & 0x0f];
 
117
    }
 
118
  str[i*2] = '\0';
 
119
 
 
120
  return str;
 
121
}
 
122
 
 
123
 
 
124
const char *
 
125
svn__digest_to_cstring(const unsigned char digest[],
 
126
                       apr_size_t digest_size,
 
127
                       apr_pool_t *pool)
 
128
{
 
129
  static const unsigned char zeros_digest[MAX_DIGESTSIZE] = { 0 };
 
130
 
 
131
  if (memcmp(digest, zeros_digest, digest_size) != 0)
 
132
    return svn__digest_to_cstring_display(digest, digest_size, pool);
 
133
  else
 
134
    return NULL;
 
135
}
 
136
 
 
137
 
 
138
svn_boolean_t
 
139
svn__digests_match(const unsigned char d1[],
 
140
                   const unsigned char d2[],
 
141
                   apr_size_t digest_size)
 
142
{
 
143
  static const unsigned char zeros[MAX_DIGESTSIZE] = { 0 };
 
144
 
 
145
  return ((memcmp(d1, d2, digest_size) == 0)
 
146
          || (memcmp(d2, zeros, digest_size) == 0)
 
147
          || (memcmp(d1, zeros, digest_size) == 0));
 
148
}
47
149
 
48
150
/* Check to see if KIND is something we recognize.  If not, return
49
151
 * SVN_ERR_BAD_CHECKSUM_KIND */
50
152
static svn_error_t *
51
153
validate_kind(svn_checksum_kind_t kind)
52
154
{
53
 
  if (kind == svn_checksum_md5 || kind == svn_checksum_sha1)
 
155
  if (kind >= svn_checksum_md5 && kind <= svn_checksum_fnv1a_32x4)
54
156
    return SVN_NO_ERROR;
55
157
  else
56
158
    return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
71
173
  return checksum;
72
174
}
73
175
 
 
176
/* Return a checksum object, allocated in POOL.  The checksum will be of
 
177
 * type KIND and contain the given DIGEST.
 
178
 */
74
179
static svn_checksum_t *
75
180
checksum_create(svn_checksum_kind_t kind,
76
 
                apr_size_t digest_size,
77
181
                const unsigned char *digest,
78
182
                apr_pool_t *pool)
79
183
{
 
184
  apr_size_t digest_size = DIGESTSIZE(kind);
80
185
  svn_checksum_t *checksum = checksum_create_without_digest(kind, digest_size,
81
186
                                                            pool);
82
187
  memcpy((unsigned char *)checksum->digest, digest, digest_size);
93
198
  switch (kind)
94
199
    {
95
200
      case svn_checksum_md5:
96
 
        digest_size = APR_MD5_DIGESTSIZE;
97
 
        break;
98
201
      case svn_checksum_sha1:
99
 
        digest_size = APR_SHA1_DIGESTSIZE;
 
202
      case svn_checksum_fnv1a_32:
 
203
      case svn_checksum_fnv1a_32x4:
 
204
        digest_size = digest_sizes[kind];
100
205
        break;
 
206
 
101
207
      default:
102
208
        return NULL;
103
209
    }
111
217
svn_checksum__from_digest_md5(const unsigned char *digest,
112
218
                              apr_pool_t *result_pool)
113
219
{
114
 
  return checksum_create(svn_checksum_md5, APR_MD5_DIGESTSIZE, digest,
115
 
                         result_pool);
 
220
  return checksum_create(svn_checksum_md5, digest, result_pool);
116
221
}
117
222
 
118
223
svn_checksum_t *
119
224
svn_checksum__from_digest_sha1(const unsigned char *digest,
120
225
                               apr_pool_t *result_pool)
121
226
{
122
 
  return checksum_create(svn_checksum_sha1, APR_SHA1_DIGESTSIZE, digest,
123
 
                         result_pool);
 
227
  return checksum_create(svn_checksum_sha1, digest, result_pool);
 
228
}
 
229
 
 
230
svn_checksum_t *
 
231
svn_checksum__from_digest_fnv1a_32(const unsigned char *digest,
 
232
                                   apr_pool_t *result_pool)
 
233
{
 
234
  return checksum_create(svn_checksum_fnv1a_32, digest, result_pool);
 
235
}
 
236
 
 
237
svn_checksum_t *
 
238
svn_checksum__from_digest_fnv1a_32x4(const unsigned char *digest,
 
239
                                     apr_pool_t *result_pool)
 
240
{
 
241
  return checksum_create(svn_checksum_fnv1a_32x4, digest, result_pool);
124
242
}
125
243
 
126
244
svn_error_t *
145
263
  switch (checksum1->kind)
146
264
    {
147
265
      case svn_checksum_md5:
148
 
        return svn_md5__digests_match(checksum1->digest, checksum2->digest);
149
266
      case svn_checksum_sha1:
150
 
        return svn_sha1__digests_match(checksum1->digest, checksum2->digest);
 
267
      case svn_checksum_fnv1a_32:
 
268
      case svn_checksum_fnv1a_32x4:
 
269
        return svn__digests_match(checksum1->digest,
 
270
                                  checksum2->digest,
 
271
                                  digest_sizes[checksum1->kind]);
 
272
 
151
273
      default:
152
274
        /* We really shouldn't get here, but if we do... */
153
275
        return FALSE;
161
283
  switch (checksum->kind)
162
284
    {
163
285
      case svn_checksum_md5:
164
 
        return svn_md5__digest_to_cstring_display(checksum->digest, pool);
165
286
      case svn_checksum_sha1:
166
 
        return svn_sha1__digest_to_cstring_display(checksum->digest, pool);
 
287
      case svn_checksum_fnv1a_32:
 
288
      case svn_checksum_fnv1a_32x4:
 
289
        return svn__digest_to_cstring_display(checksum->digest,
 
290
                                              digest_sizes[checksum->kind],
 
291
                                              pool);
 
292
 
167
293
      default:
168
294
        /* We really shouldn't get here, but if we do... */
169
295
        return NULL;
180
306
  switch (checksum->kind)
181
307
    {
182
308
      case svn_checksum_md5:
183
 
        return svn_md5__digest_to_cstring(checksum->digest, pool);
184
309
      case svn_checksum_sha1:
185
 
        return svn_sha1__digest_to_cstring(checksum->digest, pool);
 
310
      case svn_checksum_fnv1a_32:
 
311
      case svn_checksum_fnv1a_32x4:
 
312
        return svn__digest_to_cstring(checksum->digest,
 
313
                                      digest_sizes[checksum->kind],
 
314
                                      pool);
 
315
 
186
316
      default:
187
317
        /* We really shouldn't get here, but if we do... */
188
318
        return NULL;
195
325
                       apr_pool_t *result_pool,
196
326
                       apr_pool_t *scratch_pool)
197
327
{
198
 
  const char *ckind_str;
199
 
 
200
 
  SVN_ERR_ASSERT_NO_RETURN(checksum->kind == svn_checksum_md5
201
 
                           || checksum->kind == svn_checksum_sha1);
202
 
  ckind_str = (checksum->kind == svn_checksum_md5 ? "$md5 $" : "$sha1$");
 
328
  SVN_ERR_ASSERT_NO_RETURN(checksum->kind >= svn_checksum_md5
 
329
                           || checksum->kind <= svn_checksum_fnv1a_32x4);
203
330
  return apr_pstrcat(result_pool,
204
 
                     ckind_str,
 
331
                     ckind_str[checksum->kind],
205
332
                     svn_checksum_to_cstring(checksum, scratch_pool),
206
 
                     (char *)NULL);
 
333
                     SVN_VA_NULL);
207
334
}
208
335
 
209
336
 
213
340
                         apr_pool_t *result_pool,
214
341
                         apr_pool_t *scratch_pool)
215
342
{
216
 
  svn_checksum_kind_t ckind;
 
343
  svn_checksum_kind_t kind;
217
344
  svn_checksum_t *parsed_checksum;
218
345
 
219
 
  /* "$md5 $..." or "$sha1$..." */
220
 
  SVN_ERR_ASSERT(strlen(data) > 6);
221
 
 
222
 
  ckind = (data[1] == 'm' ? svn_checksum_md5 : svn_checksum_sha1);
223
 
  SVN_ERR(svn_checksum_parse_hex(&parsed_checksum, ckind,
224
 
                                 data + 6, result_pool));
225
 
  *checksum = parsed_checksum;
226
 
 
227
 
  return SVN_NO_ERROR;
 
346
  /* All prefixes have the same length. */
 
347
  apr_size_t prefix_len = strlen(ckind_str[0]);
 
348
 
 
349
  /* "$md5 $...", "$sha1$..." or ... */
 
350
  if (strlen(data) <= prefix_len)
 
351
    return svn_error_createf(SVN_ERR_BAD_CHECKSUM_PARSE, NULL,
 
352
                             _("Invalid prefix in checksum '%s'"),
 
353
                             data);
 
354
 
 
355
  for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind)
 
356
    if (strncmp(ckind_str[kind], data, prefix_len) == 0)
 
357
      {
 
358
        SVN_ERR(svn_checksum_parse_hex(&parsed_checksum, kind,
 
359
                                       data + prefix_len, result_pool));
 
360
        *checksum = parsed_checksum;
 
361
        return SVN_NO_ERROR;
 
362
      }
 
363
 
 
364
  return svn_error_createf(SVN_ERR_BAD_CHECKSUM_KIND, NULL,
 
365
                           "Unknown checksum kind in '%s'", data);
228
366
}
229
367
 
230
368
 
234
372
                       const char *hex,
235
373
                       apr_pool_t *pool)
236
374
{
237
 
  int i, len;
 
375
  apr_size_t i, len;
238
376
  char is_nonzero = '\0';
239
377
  char *digest;
240
378
  static const char xdigitval[256] =
302
440
  switch (checksum->kind)
303
441
    {
304
442
      case svn_checksum_md5:
305
 
        return svn_checksum__from_digest_md5(checksum->digest, pool);
306
 
        break;
307
443
      case svn_checksum_sha1:
308
 
        return svn_checksum__from_digest_sha1(checksum->digest, pool);
309
 
        break;
 
444
      case svn_checksum_fnv1a_32:
 
445
      case svn_checksum_fnv1a_32x4:
 
446
        return checksum_create(checksum->kind, checksum->digest, pool);
 
447
 
310
448
      default:
311
449
        SVN_ERR_MALFUNCTION_NO_RETURN();
312
450
        break;
337
475
        apr_sha1_final((unsigned char *)(*checksum)->digest, &sha1_ctx);
338
476
        break;
339
477
 
 
478
      case svn_checksum_fnv1a_32:
 
479
        *(apr_uint32_t *)(*checksum)->digest
 
480
          = htonl(svn__fnv1a_32(data, len));
 
481
        break;
 
482
 
 
483
      case svn_checksum_fnv1a_32x4:
 
484
        *(apr_uint32_t *)(*checksum)->digest
 
485
          = htonl(svn__fnv1a_32x4(data, len));
 
486
        break;
 
487
 
340
488
      default:
341
489
        /* We really shouldn't get here, but if we do... */
342
490
        return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
353
501
  switch (kind)
354
502
    {
355
503
      case svn_checksum_md5:
356
 
        return svn_checksum__from_digest_md5(svn_md5__empty_string_digest(),
357
 
                                             pool);
358
 
 
359
504
      case svn_checksum_sha1:
360
 
        return svn_checksum__from_digest_sha1(svn_sha1__empty_string_digest(),
361
 
                                              pool);
 
505
      case svn_checksum_fnv1a_32:
 
506
      case svn_checksum_fnv1a_32x4:
 
507
        return checksum_create(kind, empty_string_digests[kind], pool);
362
508
 
363
509
      default:
364
510
        /* We really shouldn't get here, but if we do... */
391
537
        apr_sha1_init(ctx->apr_ctx);
392
538
        break;
393
539
 
 
540
      case svn_checksum_fnv1a_32:
 
541
        ctx->apr_ctx = svn_fnv1a_32__context_create(pool);
 
542
        break;
 
543
 
 
544
      case svn_checksum_fnv1a_32x4:
 
545
        ctx->apr_ctx = svn_fnv1a_32x4__context_create(pool);
 
546
        break;
 
547
 
394
548
      default:
395
549
        SVN_ERR_MALFUNCTION_NO_RETURN();
396
550
    }
413
567
        apr_sha1_update(ctx->apr_ctx, data, (unsigned int)len);
414
568
        break;
415
569
 
 
570
      case svn_checksum_fnv1a_32:
 
571
        svn_fnv1a_32__update(ctx->apr_ctx, data, len);
 
572
        break;
 
573
 
 
574
      case svn_checksum_fnv1a_32x4:
 
575
        svn_fnv1a_32x4__update(ctx->apr_ctx, data, len);
 
576
        break;
 
577
 
416
578
      default:
417
579
        /* We really shouldn't get here, but if we do... */
418
580
        return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
438
600
        apr_sha1_final((unsigned char *)(*checksum)->digest, ctx->apr_ctx);
439
601
        break;
440
602
 
 
603
      case svn_checksum_fnv1a_32:
 
604
        *(apr_uint32_t *)(*checksum)->digest
 
605
          = htonl(svn_fnv1a_32__finalize(ctx->apr_ctx));
 
606
        break;
 
607
 
 
608
      case svn_checksum_fnv1a_32x4:
 
609
        *(apr_uint32_t *)(*checksum)->digest
 
610
          = htonl(svn_fnv1a_32x4__finalize(ctx->apr_ctx));
 
611
        break;
 
612
 
441
613
      default:
442
614
        /* We really shouldn't get here, but if we do... */
443
615
        return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, NULL);
486
658
  switch (checksum->kind)
487
659
    {
488
660
      case svn_checksum_md5:
489
 
        return svn_md5__digests_match(checksum->digest,
490
 
                                      svn_md5__empty_string_digest());
491
 
 
492
661
      case svn_checksum_sha1:
493
 
        return svn_sha1__digests_match(checksum->digest,
494
 
                                       svn_sha1__empty_string_digest());
 
662
      case svn_checksum_fnv1a_32:
 
663
      case svn_checksum_fnv1a_32x4:
 
664
        return svn__digests_match(checksum->digest,
 
665
                                  svn__empty_string_digest(checksum->kind),
 
666
                                  digest_sizes[checksum->kind]);
495
667
 
496
668
      default:
497
669
        /* We really shouldn't get here, but if we do... */
498
670
        SVN_ERR_MALFUNCTION_NO_RETURN();
499
671
    }
500
672
}
 
673
 
 
674
/* Checksum calculating stream wrappers.
 
675
 */
 
676
 
 
677
/* Baton used by write_handler and close_handler to calculate the checksum
 
678
 * and return the result to the stream creator.  It accommodates the data
 
679
 * needed by svn_checksum__wrap_write_stream_fnv1a_32x4 as well as
 
680
 * svn_checksum__wrap_write_stream.
 
681
 */
 
682
typedef struct stream_baton_t
 
683
{
 
684
  /* Stream we are wrapping. Forward write() and close() operations to it. */
 
685
  svn_stream_t *inner_stream;
 
686
 
 
687
  /* Build the checksum data in here. */
 
688
  svn_checksum_ctx_t *context;
 
689
 
 
690
  /* Write the final checksum here. May be NULL. */
 
691
  svn_checksum_t **checksum;
 
692
 
 
693
  /* Copy the digest of the final checksum. May be NULL. */
 
694
  unsigned char *digest;
 
695
 
 
696
  /* Allocate the resulting checksum here. */
 
697
  apr_pool_t *pool;
 
698
} stream_baton_t;
 
699
 
 
700
/* Implement svn_write_fn_t.
 
701
 * Update checksum and pass data on to inner stream.
 
702
 */
 
703
static svn_error_t *
 
704
write_handler(void *baton,
 
705
              const char *data,
 
706
              apr_size_t *len)
 
707
{
 
708
  stream_baton_t *b = baton;
 
709
 
 
710
  SVN_ERR(svn_checksum_update(b->context, data, *len));
 
711
  SVN_ERR(svn_stream_write(b->inner_stream, data, len));
 
712
 
 
713
  return SVN_NO_ERROR;
 
714
}
 
715
 
 
716
/* Implement svn_close_fn_t.
 
717
 * Finalize checksum calculation and write results. Close inner stream.
 
718
 */
 
719
static svn_error_t *
 
720
close_handler(void *baton)
 
721
{
 
722
  stream_baton_t *b = baton;
 
723
  svn_checksum_t *local_checksum;
 
724
 
 
725
  /* Ensure we can always write to *B->CHECKSUM. */
 
726
  if (!b->checksum)
 
727
    b->checksum = &local_checksum;
 
728
 
 
729
  /* Get the final checksum. */
 
730
  SVN_ERR(svn_checksum_final(b->checksum, b->context, b->pool));
 
731
 
 
732
  /* Extract digest, if wanted. */
 
733
  if (b->digest)
 
734
    {
 
735
      apr_size_t digest_size = DIGESTSIZE((*b->checksum)->kind);
 
736
      memcpy(b->digest, (*b->checksum)->digest, digest_size);
 
737
    }
 
738
 
 
739
  /* Done here.  Now, close the underlying stream as well. */
 
740
  return svn_error_trace(svn_stream_close(b->inner_stream));
 
741
}
 
742
 
 
743
/* Common constructor function for svn_checksum__wrap_write_stream and
 
744
 * svn_checksum__wrap_write_stream_fnv1a_32x4, taking the superset of their
 
745
 * respecting parameters.
 
746
 *
 
747
 * In the current usage, either CHECKSUM or DIGEST will be NULL but this
 
748
 * function does not enforce any such restriction.  Also, the caller must
 
749
 * make sure that DIGEST refers to a buffer of sufficient length.
 
750
 */
 
751
static svn_stream_t *
 
752
wrap_write_stream(svn_checksum_t **checksum,
 
753
                  unsigned char *digest,
 
754
                  svn_stream_t *inner_stream,
 
755
                  svn_checksum_kind_t kind,
 
756
                  apr_pool_t *pool)
 
757
{
 
758
  svn_stream_t *outer_stream;
 
759
 
 
760
  stream_baton_t *baton = apr_pcalloc(pool, sizeof(*baton));
 
761
  baton->inner_stream = inner_stream;
 
762
  baton->context = svn_checksum_ctx_create(kind, pool);
 
763
  baton->checksum = checksum;
 
764
  baton->digest = digest;
 
765
  baton->pool = pool;
 
766
 
 
767
  outer_stream = svn_stream_create(baton, pool);
 
768
  svn_stream_set_write(outer_stream, write_handler);
 
769
  svn_stream_set_close(outer_stream, close_handler);
 
770
 
 
771
  return outer_stream;
 
772
}
 
773
 
 
774
svn_stream_t *
 
775
svn_checksum__wrap_write_stream(svn_checksum_t **checksum,
 
776
                                svn_stream_t *inner_stream,
 
777
                                svn_checksum_kind_t kind,
 
778
                                apr_pool_t *pool)
 
779
{
 
780
  return wrap_write_stream(checksum, NULL, inner_stream, kind, pool);
 
781
}
 
782
 
 
783
/* Implement svn_close_fn_t.
 
784
 * For FNV-1a-like checksums, we want the checksum as 32 bit integer instead
 
785
 * of a big endian 4 byte sequence.  This simply wraps close_handler adding
 
786
 * the digest conversion.
 
787
 */
 
788
static svn_error_t *
 
789
close_handler_fnv1a_32x4(void *baton)
 
790
{
 
791
  stream_baton_t *b = baton;
 
792
  SVN_ERR(close_handler(baton));
 
793
 
 
794
  *(apr_uint32_t *)b->digest = ntohl(*(apr_uint32_t *)b->digest);
 
795
  return SVN_NO_ERROR;
 
796
}
 
797
 
 
798
svn_stream_t *
 
799
svn_checksum__wrap_write_stream_fnv1a_32x4(apr_uint32_t *digest,
 
800
                                           svn_stream_t *inner_stream,
 
801
                                           apr_pool_t *pool)
 
802
{
 
803
  svn_stream_t *result
 
804
    = wrap_write_stream(NULL, (unsigned char *)digest, inner_stream,
 
805
                        svn_checksum_fnv1a_32x4, pool);
 
806
  svn_stream_set_close(result, close_handler_fnv1a_32x4);
 
807
 
 
808
  return result;
 
809
}