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

« back to all changes in this revision

Viewing changes to subversion/libsvn_diff/parse-diff.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:
35
35
#include "svn_utf.h"
36
36
#include "svn_dirent_uri.h"
37
37
#include "svn_diff.h"
 
38
#include "svn_ctype.h"
 
39
#include "svn_mergeinfo.h"
38
40
 
39
41
#include "private/svn_eol_private.h"
40
42
#include "private/svn_dep_compat.h"
 
43
#include "private/svn_sorts_private.h"
41
44
 
42
45
/* Helper macro for readability */
43
46
#define starts_with(str, start)  \
385
388
                                 apr_pool_t *result_pool,
386
389
                                 apr_pool_t *scratch_pool)
387
390
{
388
 
  svn_diff_hunk_t dummy;
389
391
  svn_stringbuf_t *line;
390
392
  apr_size_t max_len;
391
393
  apr_off_t pos;
415
417
 
416
418
  if (hunk->patch->reverse)
417
419
    {
418
 
      if (parse_hunk_header(line->data, &dummy, "@@", scratch_pool))
419
 
        {
420
 
          /* Line is a hunk header, reverse it. */
421
 
          line = svn_stringbuf_createf(result_pool,
422
 
                                       "@@ -%lu,%lu +%lu,%lu @@",
423
 
                                       hunk->modified_start,
424
 
                                       hunk->modified_length,
425
 
                                       hunk->original_start,
426
 
                                       hunk->original_length);
427
 
        }
428
 
      else if (parse_hunk_header(line->data, &dummy, "##", scratch_pool))
429
 
        {
430
 
          /* Line is a hunk header, reverse it. */
431
 
          line = svn_stringbuf_createf(result_pool,
432
 
                                       "## -%lu,%lu +%lu,%lu ##",
433
 
                                       hunk->modified_start,
434
 
                                       hunk->modified_length,
435
 
                                       hunk->original_start,
436
 
                                       hunk->original_length);
437
 
        }
438
 
      else
439
 
        {
440
 
          if (line->data[0] == '+')
441
 
            line->data[0] = '-';
442
 
          else if (line->data[0] == '-')
443
 
            line->data[0] = '+';
444
 
        }
 
420
      if (line->data[0] == '+')
 
421
        line->data[0] = '-';
 
422
      else if (line->data[0] == '-')
 
423
        line->data[0] = '+';
445
424
    }
446
425
 
447
426
  *stringbuf = line;
471
450
  return SVN_NO_ERROR;
472
451
}
473
452
 
 
453
 
 
454
/* A helper function to parse svn:mergeinfo diffs.
 
455
 *
 
456
 * These diffs use a special pretty-print format, for instance:
 
457
 *
 
458
 * Added: svn:mergeinfo
 
459
 * ## -0,0 +0,1 ##
 
460
 *   Merged /trunk:r2-3
 
461
 *
 
462
 * The hunk header has the following format:
 
463
 * ## -0,NUMBER_OF_REVERSE_MERGES +0,NUMBER_OF_FORWARD_MERGES ##
 
464
 *
 
465
 * At this point, the number of reverse merges has already been
 
466
 * parsed into HUNK->ORIGINAL_LENGTH, and the number of forward
 
467
 * merges has been parsed into HUNK->MODIFIED_LENGTH.
 
468
 *
 
469
 * The header is followed by a list of mergeinfo, one path per line.
 
470
 * This function parses such lines. Lines describing reverse merges
 
471
 * appear first, and then all lines describing forward merges appear.
 
472
 *
 
473
 * Parts of the line are affected by i18n. The words 'Merged'
 
474
 * and 'Reverse-merged' can appear in any language and at any
 
475
 * position within the line. We can only assume that a leading
 
476
 * '/' starts the merge source path, the path is followed by
 
477
 * ":r", which in turn is followed by a mergeinfo revision range,
 
478
 *  which is terminated by whitespace or end-of-string.
 
479
 *
 
480
 * If the current line meets the above criteria and we're able
 
481
 * to parse valid mergeinfo from it, the resulting mergeinfo
 
482
 * is added to patch->mergeinfo or patch->reverse_mergeinfo,
 
483
 * and we proceed to the next line.
 
484
 */
 
485
static svn_error_t *
 
486
parse_mergeinfo(svn_boolean_t *found_mergeinfo,
 
487
                svn_stringbuf_t *line,
 
488
                svn_diff_hunk_t *hunk,
 
489
                svn_patch_t *patch,
 
490
                apr_pool_t *result_pool,
 
491
                apr_pool_t *scratch_pool)
 
492
{
 
493
  char *slash = strchr(line->data, '/');
 
494
  char *colon = strrchr(line->data, ':');
 
495
 
 
496
  *found_mergeinfo = FALSE;
 
497
 
 
498
  if (slash && colon && colon[1] == 'r' && slash < colon)
 
499
    {
 
500
      svn_stringbuf_t *input;
 
501
      svn_mergeinfo_t mergeinfo = NULL;
 
502
      char *s;
 
503
      svn_error_t *err;
 
504
 
 
505
      input = svn_stringbuf_create_ensure(line->len, scratch_pool);
 
506
 
 
507
      /* Copy the merge source path + colon */
 
508
      s = slash;
 
509
      while (s <= colon)
 
510
        {
 
511
          svn_stringbuf_appendbyte(input, *s);
 
512
          s++;
 
513
        }
 
514
 
 
515
      /* skip 'r' after colon */
 
516
      s++;
 
517
 
 
518
      /* Copy the revision range. */
 
519
      while (s < line->data + line->len)
 
520
        {
 
521
          if (svn_ctype_isspace(*s))
 
522
            break;
 
523
          svn_stringbuf_appendbyte(input, *s);
 
524
          s++;
 
525
        }
 
526
 
 
527
      err = svn_mergeinfo_parse(&mergeinfo, input->data, result_pool);
 
528
      if (err && err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
 
529
        {
 
530
          svn_error_clear(err);
 
531
          mergeinfo = NULL;
 
532
        }
 
533
      else
 
534
        SVN_ERR(err);
 
535
 
 
536
      if (mergeinfo)
 
537
        {
 
538
          if (hunk->original_length > 0) /* reverse merges */
 
539
            {
 
540
              if (patch->reverse)
 
541
                {
 
542
                  if (patch->mergeinfo == NULL)
 
543
                    patch->mergeinfo = mergeinfo;
 
544
                  else
 
545
                    SVN_ERR(svn_mergeinfo_merge2(patch->mergeinfo,
 
546
                                                 mergeinfo,
 
547
                                                 result_pool,
 
548
                                                 scratch_pool));
 
549
                }
 
550
              else
 
551
                {
 
552
                  if (patch->reverse_mergeinfo == NULL)
 
553
                    patch->reverse_mergeinfo = mergeinfo;
 
554
                  else
 
555
                    SVN_ERR(svn_mergeinfo_merge2(patch->reverse_mergeinfo,
 
556
                                                 mergeinfo,
 
557
                                                 result_pool,
 
558
                                                 scratch_pool));
 
559
                }
 
560
              hunk->original_length--;
 
561
            }
 
562
          else if (hunk->modified_length > 0) /* forward merges */
 
563
            {
 
564
              if (patch->reverse)
 
565
                {
 
566
                  if (patch->reverse_mergeinfo == NULL)
 
567
                    patch->reverse_mergeinfo = mergeinfo;
 
568
                  else
 
569
                    SVN_ERR(svn_mergeinfo_merge2(patch->reverse_mergeinfo,
 
570
                                                 mergeinfo,
 
571
                                                 result_pool,
 
572
                                                 scratch_pool));
 
573
                }
 
574
              else
 
575
                {
 
576
                  if (patch->mergeinfo == NULL)
 
577
                    patch->mergeinfo = mergeinfo;
 
578
                  else
 
579
                    SVN_ERR(svn_mergeinfo_merge2(patch->mergeinfo,
 
580
                                                 mergeinfo,
 
581
                                                 result_pool,
 
582
                                                 scratch_pool));
 
583
                }
 
584
              hunk->modified_length--;
 
585
            }
 
586
 
 
587
          *found_mergeinfo = TRUE;
 
588
        }
 
589
    }
 
590
 
 
591
  return SVN_NO_ERROR;
 
592
}
 
593
 
474
594
/* Return the next *HUNK from a PATCH in APR_FILE.
475
595
 * If no hunk can be found, set *HUNK to NULL.
476
596
 * Set IS_PROPERTY to TRUE if we have a property hunk. If the returned HUNK
600
720
          continue;
601
721
        }
602
722
 
 
723
      if (in_hunk && *is_property && *prop_name &&
 
724
          strcmp(*prop_name, SVN_PROP_MERGEINFO) == 0)
 
725
        {
 
726
          svn_boolean_t found_mergeinfo;
 
727
 
 
728
          SVN_ERR(parse_mergeinfo(&found_mergeinfo, line, *hunk, patch,
 
729
                                  result_pool, iterpool));
 
730
          if (found_mergeinfo)
 
731
            continue; /* Proceed to the next line in the patch. */
 
732
        }
 
733
 
603
734
      if (in_hunk)
604
735
        {
605
736
          char c;
1192
1323
            prop_name = last_prop_name;
1193
1324
          else
1194
1325
            last_prop_name = prop_name;
 
1326
 
 
1327
          /* Skip svn:mergeinfo properties.
 
1328
           * Mergeinfo data cannot be represented as a hunk and
 
1329
           * is therefore stored in PATCH itself. */
 
1330
          if (strcmp(prop_name, SVN_PROP_MERGEINFO) == 0)
 
1331
            continue;
 
1332
 
1195
1333
          SVN_ERR(add_property_hunk(patch, prop_name, hunk, prop_operation,
1196
1334
                                    result_pool));
1197
1335
        }
1229
1367
};
1230
1368
 
1231
1369
svn_error_t *
1232
 
svn_diff_parse_next_patch(svn_patch_t **patch,
 
1370
svn_diff_parse_next_patch(svn_patch_t **patch_p,
1233
1371
                          svn_patch_file_t *patch_file,
1234
1372
                          svn_boolean_t reverse,
1235
1373
                          svn_boolean_t ignore_whitespace,
1240
1378
  svn_boolean_t eof;
1241
1379
  svn_boolean_t line_after_tree_header_read = FALSE;
1242
1380
  apr_pool_t *iterpool;
 
1381
  svn_patch_t *patch;
1243
1382
  enum parse_state state = state_start;
1244
1383
 
1245
1384
  if (apr_file_eof(patch_file->apr_file) == APR_EOF)
1246
1385
    {
1247
1386
      /* No more patches here. */
1248
 
      *patch = NULL;
 
1387
      *patch_p = NULL;
1249
1388
      return SVN_NO_ERROR;
1250
1389
    }
1251
1390
 
1252
 
  *patch = apr_pcalloc(result_pool, sizeof(**patch));
 
1391
  patch = apr_pcalloc(result_pool, sizeof(*patch));
1253
1392
 
1254
1393
  pos = patch_file->next_patch_offset;
1255
1394
  SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_SET, &pos, scratch_pool));
1282
1421
          if (starts_with(line->data, transitions[i].expected_input)
1283
1422
              && state == transitions[i].required_state)
1284
1423
            {
1285
 
              SVN_ERR(transitions[i].fn(&state, line->data, *patch,
 
1424
              SVN_ERR(transitions[i].fn(&state, line->data, patch,
1286
1425
                                        result_pool, iterpool));
1287
1426
              valid_header_line = TRUE;
1288
1427
              break;
1328
1467
    }
1329
1468
  while (! eof);
1330
1469
 
1331
 
  (*patch)->reverse = reverse;
 
1470
  patch->reverse = reverse;
1332
1471
  if (reverse)
1333
1472
    {
1334
1473
      const char *temp;
1335
 
      temp = (*patch)->old_filename;
1336
 
      (*patch)->old_filename = (*patch)->new_filename;
1337
 
      (*patch)->new_filename = temp;
 
1474
      temp = patch->old_filename;
 
1475
      patch->old_filename = patch->new_filename;
 
1476
      patch->new_filename = temp;
1338
1477
    }
1339
1478
 
1340
 
  if ((*patch)->old_filename == NULL || (*patch)->new_filename == NULL)
 
1479
  if (patch->old_filename == NULL || patch->new_filename == NULL)
1341
1480
    {
1342
1481
      /* Something went wrong, just discard the result. */
1343
 
      *patch = NULL;
 
1482
      patch = NULL;
1344
1483
    }
1345
1484
  else
1346
 
    SVN_ERR(parse_hunks(*patch, patch_file->apr_file, ignore_whitespace,
 
1485
    SVN_ERR(parse_hunks(patch, patch_file->apr_file, ignore_whitespace,
1347
1486
                        result_pool, iterpool));
1348
1487
 
1349
1488
  svn_pool_destroy(iterpool);
1352
1491
  SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_CUR,
1353
1492
                           &patch_file->next_patch_offset, scratch_pool));
1354
1493
 
1355
 
  if (*patch)
 
1494
  if (patch)
1356
1495
    {
1357
1496
      /* Usually, hunks appear in the patch sorted by their original line
1358
1497
       * offset. But just in case they weren't parsed in this order for
1359
1498
       * some reason, we sort them so that our caller can assume that hunks
1360
1499
       * are sorted as if parsed from a usual patch. */
1361
 
      qsort((*patch)->hunks->elts, (*patch)->hunks->nelts,
1362
 
            (*patch)->hunks->elt_size, compare_hunks);
 
1500
      svn_sort__array(patch->hunks, compare_hunks);
1363
1501
    }
1364
1502
 
 
1503
  *patch_p = patch;
1365
1504
  return SVN_NO_ERROR;
1366
1505
}
1367
1506