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

« back to all changes in this revision

Viewing changes to subversion/libsvn_subr/string.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:
26
26
 
27
27
 
28
28
#include <apr.h>
 
29
#include <assert.h>
29
30
 
30
31
#include <string.h>      /* for memcpy(), memcmp(), strlen() */
31
32
#include <apr_fnmatch.h>
53
54
  /* apr_palloc will allocate multiples of 8.
54
55
   * Thus, we would waste some of that memory if we stuck to the
55
56
   * smaller size. Note that this is safe even if apr_palloc would
56
 
   * use some other aligment or none at all. */
 
57
   * use some other alignment or none at all. */
57
58
  minimum_size = APR_ALIGN_DEFAULT(minimum_size);
58
 
  *data = (!minimum_size ? NULL : apr_palloc(pool, minimum_size));
 
59
  *data = apr_palloc(pool, minimum_size);
59
60
  *size = minimum_size;
60
61
}
61
62
 
78
79
      apr_size_t new_size = *size;
79
80
 
80
81
      if (new_size == 0)
81
 
        /* APR will increase odd allocation sizes to the next
82
 
         * multiple for 8, for instance. Take advantage of that
83
 
         * knowledge and allow for the extra size to be used. */
84
82
        new_size = minimum_size;
85
83
      else
86
84
        while (new_size < minimum_size)
87
85
          {
88
 
            /* new_size is aligned; doubling it should keep it aligned */
89
86
            const apr_size_t prev_size = new_size;
90
87
            new_size *= 2;
91
88
 
121
118
  const apr_size_t old_size = membuf->size;
122
119
 
123
120
  membuf_ensure(&membuf->data, &membuf->size, size, membuf->pool);
124
 
  if (membuf->data && old_data && old_data != membuf->data)
 
121
 
 
122
  /* If we re-allocated MEMBUF->DATA, it cannot be NULL.
 
123
   * Statically initialized membuffers (OLD_DATA) may be NULL, though. */
 
124
  if (old_data && old_data != membuf->data)
125
125
    memcpy(membuf->data, old_data, old_size);
126
126
}
127
127
 
151
151
  if (len1 != len2)
152
152
    return FALSE;
153
153
 
154
 
  /* now the strings must have identical lenghths */
 
154
  /* now the strings must have identical lengths */
155
155
 
156
156
  if ((memcmp(str1, str2, len1)) == 0)
157
157
    return TRUE;
240
240
  new_string->data = data;
241
241
  new_string->len = size;
242
242
 
243
 
  memcpy(data, bytes, size);
 
243
  /* If SIZE is 0, NULL is valid for BYTES. */
 
244
  if (size)
 
245
    memcpy(data, bytes, size);
244
246
 
245
247
  /* Null termination is the convention -- even if we suspect the data
246
248
     to be binary, it's not up to us to decide, it's the caller's
299
301
svn_string_t *
300
302
svn_string_dup(const svn_string_t *original_string, apr_pool_t *pool)
301
303
{
302
 
  return (svn_string_ncreate(original_string->data,
303
 
                             original_string->len, pool));
 
304
  return (original_string ? svn_string_ncreate(original_string->data,
 
305
                                               original_string->len, pool)
 
306
                          : NULL);
304
307
}
305
308
 
306
309
 
393
396
svn_stringbuf_ncreate(const char *bytes, apr_size_t size, apr_pool_t *pool)
394
397
{
395
398
  svn_stringbuf_t *strbuf = svn_stringbuf_create_ensure(size, pool);
396
 
  memcpy(strbuf->data, bytes, size);
 
399
 
 
400
  /* If SIZE is 0, NULL is valid for BYTES. */
 
401
  if (size)
 
402
    memcpy(strbuf->data, bytes, size);
397
403
 
398
404
  /* Null termination is the convention -- even if we suspect the data
399
405
     to be binary, it's not up to us to decide, it's the caller's
418
424
  return svn_stringbuf_ncreate(str->data, str->len, pool);
419
425
}
420
426
 
 
427
svn_stringbuf_t *
 
428
svn_stringbuf_create_wrap(char *str, apr_pool_t *pool)
 
429
{
 
430
  svn_stringbuf_t *result = apr_palloc(pool, sizeof(*result));
 
431
  result->pool = pool;
 
432
  result->data = str;
 
433
  result->len = strlen(str);
 
434
  result->blocksize = result->len + 1;
 
435
 
 
436
  return result;
 
437
}
421
438
 
422
439
svn_stringbuf_t *
423
440
svn_stringbuf_createv(apr_pool_t *pool, const char *fmt, va_list ap)
579
596
  apr_size_t total_len;
580
597
  void *start_address;
581
598
 
 
599
  if (!count)
 
600
    /* Allow BYTES to be NULL by avoiding passing it to memcpy. */
 
601
    return;
 
602
 
582
603
  total_len = str->len + count;  /* total size needed */
583
604
 
584
605
  /* svn_stringbuf_ensure adds 1 for null terminator. */
595
616
                                  to null-terminate. */
596
617
}
597
618
 
 
619
void
 
620
svn_stringbuf_appendfill(svn_stringbuf_t *str,
 
621
                         char byte,
 
622
                         apr_size_t count)
 
623
{
 
624
  apr_size_t new_len = str->len + count;
 
625
  svn_stringbuf_ensure(str, new_len);
 
626
 
 
627
  memset(str->data + str->len, byte, count);
 
628
 
 
629
  /* update buffer length and always NUL-terminate it */
 
630
  str->len = new_len;
 
631
  str->data[new_len] = '\0';
 
632
}
 
633
 
598
634
 
599
635
void
600
636
svn_stringbuf_appendstr(svn_stringbuf_t *targetstr,
616
652
                     const char *bytes,
617
653
                     apr_size_t count)
618
654
{
 
655
  /* For COUNT==0, we allow BYTES to be NULL. It's a no-op in that case. */
 
656
  if (count == 0)
 
657
    return;
 
658
 
 
659
  /* special case: BYTES overlaps with this string -> copy the source */
619
660
  if (bytes + count > str->data && bytes < str->data + str->blocksize)
620
 
    {
621
 
      /* special case: BYTES overlaps with this string -> copy the source */
622
 
      const char *temp = apr_pmemdup(str->pool, bytes, count);
623
 
      svn_stringbuf_insert(str, pos, temp, count);
624
 
    }
625
 
  else
626
 
    {
627
 
      if (pos > str->len)
628
 
        pos = str->len;
629
 
 
630
 
      svn_stringbuf_ensure(str, str->len + count);
631
 
      memmove(str->data + pos + count, str->data + pos, str->len - pos + 1);
632
 
      memcpy(str->data + pos, bytes, count);
633
 
 
634
 
      str->len += count;
635
 
    }
 
661
    bytes = apr_pmemdup(str->pool, bytes, count);
 
662
 
 
663
  if (pos > str->len)
 
664
    pos = str->len;
 
665
 
 
666
  svn_stringbuf_ensure(str, str->len + count);
 
667
  memmove(str->data + pos + count, str->data + pos, str->len - pos + 1);
 
668
  memcpy(str->data + pos, bytes, count);
 
669
 
 
670
  str->len += count;
636
671
}
637
672
 
638
673
void
656
691
                      const char *bytes,
657
692
                      apr_size_t new_count)
658
693
{
 
694
  /* For COUNT==0, we allow BYTES to be NULL.
 
695
   * In that case, this is just a substring removal. */
 
696
  if (new_count == 0)
 
697
    {
 
698
      svn_stringbuf_remove(str, pos, old_count);
 
699
      return;
 
700
    }
 
701
 
 
702
  /* special case: BYTES overlaps with this string -> copy the source */
659
703
  if (bytes + new_count > str->data && bytes < str->data + str->blocksize)
660
 
    {
661
 
      /* special case: BYTES overlaps with this string -> copy the source */
662
 
      const char *temp = apr_pmemdup(str->pool, bytes, new_count);
663
 
      svn_stringbuf_replace(str, pos, old_count, temp, new_count);
664
 
    }
665
 
  else
666
 
    {
667
 
      if (pos > str->len)
668
 
        pos = str->len;
669
 
      if (pos + old_count > str->len)
670
 
        old_count = str->len - pos;
671
 
 
672
 
      if (old_count < new_count)
673
 
        {
674
 
          apr_size_t delta = new_count - old_count;
675
 
          svn_stringbuf_ensure(str, str->len + delta);
676
 
        }
677
 
 
678
 
      if (old_count != new_count)
679
 
        memmove(str->data + pos + new_count, str->data + pos + old_count,
680
 
                str->len - pos - old_count + 1);
681
 
 
682
 
      memcpy(str->data + pos, bytes, new_count);
683
 
      str->len += new_count - old_count;
684
 
    }
 
704
    bytes = apr_pmemdup(str->pool, bytes, new_count);
 
705
 
 
706
  if (pos > str->len)
 
707
    pos = str->len;
 
708
  if (pos + old_count > str->len)
 
709
    old_count = str->len - pos;
 
710
 
 
711
  if (old_count < new_count)
 
712
    {
 
713
      apr_size_t delta = new_count - old_count;
 
714
      svn_stringbuf_ensure(str, str->len + delta);
 
715
    }
 
716
 
 
717
  if (old_count != new_count)
 
718
    memmove(str->data + pos + new_count, str->data + pos + old_count,
 
719
            str->len - pos - old_count + 1);
 
720
 
 
721
  memcpy(str->data + pos, bytes, new_count);
 
722
  str->len += new_count - old_count;
685
723
}
686
724
 
687
725
 
832
870
svn_cstring_tokenize(const char *sep, char **str)
833
871
{
834
872
    char *token;
835
 
    const char * next;
 
873
    char *next;
836
874
    char csep;
837
875
 
838
876
    /* check parameters */
862
900
      }
863
901
    else
864
902
      {
865
 
        *(char *)next = '\0';
866
 
        *str = (char *)next + 1;
 
903
        *next = '\0';
 
904
        *str = next + 1;
867
905
      }
868
906
 
869
907
    return token;
1014
1052
  return SVN_NO_ERROR;
1015
1053
}
1016
1054
 
1017
 
 
1018
 
apr_status_t
1019
 
svn__strtoff(apr_off_t *offset, const char *buf, char **end, int base)
 
1055
unsigned long
 
1056
svn__strtoul(const char* buffer, const char** end)
1020
1057
{
1021
 
#if !APR_VERSION_AT_LEAST(1,0,0)
1022
 
  errno = 0;
1023
 
  *offset = strtol(buf, end, base);
1024
 
  return APR_FROM_OS_ERROR(errno);
1025
 
#else
1026
 
  return apr_strtoff(offset, buf, end, base);
1027
 
#endif
 
1058
  unsigned long result = 0;
 
1059
 
 
1060
  /* this loop will execute in just 2 CPU cycles, confirmed by measurement:
 
1061
     7 macro-ops (max 4 / cycle => 2 cycles)
 
1062
       1 load (max 1 / cycle)
 
1063
       1 jumps (compare + conditional jump == 1 macro op; max 1 / cycle)
 
1064
       2 arithmetic ops (subtract, increment; max 3 / cycle)
 
1065
       2 scale-and-add AGU ops (max 3 / cycle)
 
1066
       1 compiler-generated move operation
 
1067
     dependency chain: temp = result * 4 + result; result = temp * 2 + c
 
1068
                       (2 ops with latency 1 => 2 cycles)
 
1069
   */
 
1070
  while (1)
 
1071
    {
 
1072
      unsigned long c = (unsigned char)*buffer - (unsigned char)'0';
 
1073
      if (c > 9)
 
1074
        break;
 
1075
 
 
1076
      result = result * 10 + c;
 
1077
      ++buffer;
 
1078
    }
 
1079
 
 
1080
  *end = buffer;
 
1081
  return result;
1028
1082
}
1029
1083
 
1030
1084
/* "Precalculated" itoa values for 2 places (including leading zeros).
1123
1177
    return svn__ui64toa(dest, (apr_uint64_t)number);
1124
1178
 
1125
1179
  *dest = '-';
1126
 
  return svn__ui64toa(dest + 1, (apr_uint64_t)(0-number)) + 1;
 
1180
  return svn__ui64toa(dest + 1, 0 - (apr_uint64_t)number) + 1;
1127
1181
}
1128
1182
 
1129
1183
static void
1130
 
ui64toa_sep(apr_uint64_t number, char seperator, char *buffer)
 
1184
ui64toa_sep(apr_uint64_t number, char separator, char *buffer)
1131
1185
{
1132
1186
  apr_size_t length = svn__ui64toa(buffer, number);
1133
1187
  apr_size_t i;
1135
1189
  for (i = length; i > 3; i -= 3)
1136
1190
    {
1137
1191
      memmove(&buffer[i - 2], &buffer[i - 3], length - i + 3);
1138
 
      buffer[i-3] = seperator;
 
1192
      buffer[i-3] = separator;
1139
1193
      length++;
1140
1194
    }
1141
1195
 
1143
1197
}
1144
1198
 
1145
1199
char *
1146
 
svn__ui64toa_sep(apr_uint64_t number, char seperator, apr_pool_t *pool)
 
1200
svn__ui64toa_sep(apr_uint64_t number, char separator, apr_pool_t *pool)
1147
1201
{
1148
1202
  char buffer[2 * SVN_INT64_BUFFER_SIZE];
1149
 
  ui64toa_sep(number, seperator, buffer);
 
1203
  ui64toa_sep(number, separator, buffer);
1150
1204
 
1151
1205
  return apr_pstrdup(pool, buffer);
1152
1206
}
1153
1207
 
1154
1208
char *
1155
 
svn__i64toa_sep(apr_int64_t number, char seperator, apr_pool_t *pool)
 
1209
svn__i64toa_sep(apr_int64_t number, char separator, apr_pool_t *pool)
1156
1210
{
1157
1211
  char buffer[2 * SVN_INT64_BUFFER_SIZE];
1158
1212
  if (number < 0)
1159
1213
    {
1160
1214
      buffer[0] = '-';
1161
 
      ui64toa_sep((apr_uint64_t)(-number), seperator, &buffer[1]);
 
1215
      ui64toa_sep((apr_uint64_t)(-number), separator, &buffer[1]);
1162
1216
    }
1163
1217
  else
1164
 
    ui64toa_sep((apr_uint64_t)(number), seperator, buffer);
 
1218
    ui64toa_sep((apr_uint64_t)(number), separator, buffer);
1165
1219
 
1166
1220
  return apr_pstrdup(pool, buffer);
1167
1221
}
1168
1222
 
1169
 
unsigned int
 
1223
apr_size_t
 
1224
svn__ui64tobase36(char *dest, apr_uint64_t value)
 
1225
{
 
1226
  char *dest_start = dest;
 
1227
  if (value < 10)
 
1228
    {
 
1229
      /* pretty frequent and trivial case. Make it fast. */
 
1230
      *(dest++) = (char)(value) + '0';
 
1231
    }
 
1232
  else
 
1233
    {
 
1234
      char buffer[SVN_INT64_BUFFER_SIZE];
 
1235
      char *p = buffer;
 
1236
 
 
1237
      /* write result as little-endian to buffer */
 
1238
      while (value > 0)
 
1239
        {
 
1240
          char c = (char)(value % 36);
 
1241
          value /= 36;
 
1242
 
 
1243
          *p = (c <= 9) ? (c + '0') : (c - 10 + 'a');
 
1244
          ++p;
 
1245
        }
 
1246
 
 
1247
      /* copy as big-endian to DEST */
 
1248
      while (p > buffer)
 
1249
        *(dest++) = *(--p);
 
1250
    }
 
1251
 
 
1252
  *dest = '\0';
 
1253
  return dest - dest_start;
 
1254
}
 
1255
 
 
1256
apr_uint64_t
 
1257
svn__base36toui64(const char **next, const char *source)
 
1258
{
 
1259
  apr_uint64_t result = 0;
 
1260
  apr_uint64_t factor = 1;
 
1261
  int i  = 0;
 
1262
  char digits[SVN_INT64_BUFFER_SIZE];
 
1263
 
 
1264
  /* convert digits to numerical values and count the number of places.
 
1265
   * Also, prevent buffer overflow. */
 
1266
  while (i < sizeof(digits))
 
1267
    {
 
1268
      char c = *source;
 
1269
      if (c < 'a')
 
1270
        {
 
1271
          /* includes detection of NUL terminator */
 
1272
          if (c < '0' || c > '9')
 
1273
            break;
 
1274
 
 
1275
          c -= '0';
 
1276
        }
 
1277
      else
 
1278
        {
 
1279
          if (c < 'a' || c > 'z')
 
1280
            break;
 
1281
 
 
1282
          c -= 'a' - 10;
 
1283
        }
 
1284
 
 
1285
      digits[i++] = c;
 
1286
      source++;
 
1287
    }
 
1288
 
 
1289
  /* fold digits into the result */
 
1290
  while (i > 0)
 
1291
    {
 
1292
      result += factor * (apr_uint64_t)digits[--i];
 
1293
      factor *= 36;
 
1294
    }
 
1295
 
 
1296
  if (next)
 
1297
    *next = source;
 
1298
 
 
1299
  return result;
 
1300
}
 
1301
 
 
1302
 
 
1303
apr_size_t
1170
1304
svn_cstring__similarity(const char *stra, const char *strb,
1171
1305
                        svn_membuf_t *buffer, apr_size_t *rlcs)
1172
1306
{
1178
1312
  return svn_string__similarity(&stringa, &stringb, buffer, rlcs);
1179
1313
}
1180
1314
 
1181
 
unsigned int
 
1315
apr_size_t
1182
1316
svn_string__similarity(const svn_string_t *stringa,
1183
1317
                       const svn_string_t *stringb,
1184
1318
                       svn_membuf_t *buffer, apr_size_t *rlcs)
1242
1376
      /* Calculate LCS length of the remainder */
1243
1377
      for (pstr = stra; pstr < enda; ++pstr)
1244
1378
        {
1245
 
          int i;
 
1379
          apr_size_t i;
1246
1380
          for (i = 1; i <= slots; ++i)
1247
1381
            {
1248
1382
              if (*pstr == strb[i-1])
1267
1401
 
1268
1402
  /* Return similarity ratio rounded to 4 significant digits */
1269
1403
  if (total)
1270
 
    return(unsigned int)((2000 * lcs + total/2) / total);
1271
 
  else
1272
 
    return 1000;
 
1404
    return ((2 * SVN_STRING__SIM_RANGE_MAX * lcs + total/2) / total);
 
1405
  else
 
1406
    return SVN_STRING__SIM_RANGE_MAX;
 
1407
}
 
1408
 
 
1409
apr_size_t
 
1410
svn_cstring__match_length(const char *a,
 
1411
                          const char *b,
 
1412
                          apr_size_t max_len)
 
1413
{
 
1414
  apr_size_t pos = 0;
 
1415
 
 
1416
#if SVN_UNALIGNED_ACCESS_IS_OK
 
1417
 
 
1418
  /* Chunky processing is so much faster ...
 
1419
   *
 
1420
   * We can't make this work on architectures that require aligned access
 
1421
   * because A and B will probably have different alignment. So, skipping
 
1422
   * the first few chars until alignment is reached is not an option.
 
1423
   */
 
1424
  for (; pos + sizeof(apr_size_t) <= max_len; pos += sizeof(apr_size_t))
 
1425
    if (*(const apr_size_t*)(a + pos) != *(const apr_size_t*)(b + pos))
 
1426
      break;
 
1427
 
 
1428
#endif
 
1429
 
 
1430
  for (; pos < max_len; ++pos)
 
1431
    if (a[pos] != b[pos])
 
1432
      break;
 
1433
 
 
1434
  return pos;
 
1435
}
 
1436
 
 
1437
apr_size_t
 
1438
svn_cstring__reverse_match_length(const char *a,
 
1439
                                  const char *b,
 
1440
                                  apr_size_t max_len)
 
1441
{
 
1442
  apr_size_t pos = 0;
 
1443
 
 
1444
#if SVN_UNALIGNED_ACCESS_IS_OK
 
1445
 
 
1446
  /* Chunky processing is so much faster ...
 
1447
   *
 
1448
   * We can't make this work on architectures that require aligned access
 
1449
   * because A and B will probably have different alignment. So, skipping
 
1450
   * the first few chars until alignment is reached is not an option.
 
1451
   */
 
1452
  for (pos = sizeof(apr_size_t); pos <= max_len; pos += sizeof(apr_size_t))
 
1453
    if (*(const apr_size_t*)(a - pos) != *(const apr_size_t*)(b - pos))
 
1454
      break;
 
1455
 
 
1456
  pos -= sizeof(apr_size_t);
 
1457
 
 
1458
#endif
 
1459
 
 
1460
  /* If we find a mismatch at -pos, pos-1 characters matched.
 
1461
   */
 
1462
  while (++pos <= max_len)
 
1463
    if (a[0-pos] != b[0-pos])
 
1464
      return pos - 1;
 
1465
 
 
1466
  /* No mismatch found -> at least MAX_LEN matching chars.
 
1467
   */
 
1468
  return max_len;
 
1469
}
 
1470
 
 
1471
const char *
 
1472
svn_cstring_skip_prefix(const char *str, const char *prefix)
 
1473
{
 
1474
  apr_size_t len = strlen(prefix);
 
1475
 
 
1476
  if (strncmp(str, prefix, len) == 0)
 
1477
    {
 
1478
      return str + len;
 
1479
    }
 
1480
  else
 
1481
    {
 
1482
      return NULL;
 
1483
    }
1273
1484
}