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

« back to all changes in this revision

Viewing changes to subversion/libsvn_wc/copy.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:
42
42
#include "svn_private_config.h"
43
43
#include "private/svn_wc_private.h"
44
44
 
 
45
/* #define RECORD_MIXED_MOVE */
45
46
 
46
47
/*** Code. ***/
47
48
 
50
51
   TMPDIR_ABSPATH and return the absolute path of the copy in
51
52
   *DST_ABSPATH.  Return the node kind of SRC_ABSPATH in *KIND.  If
52
53
   SRC_ABSPATH doesn't exist then set *DST_ABSPATH to NULL to indicate
53
 
   that no copy was made. */
 
54
   that no copy was made.
 
55
 
 
56
   If DIRENT is not NULL, it contains the on-disk information of SRC_ABSPATH.
 
57
   RECORDED_SIZE (if not SVN_INVALID_FILESIZE) contains the recorded size of
 
58
   SRC_ABSPATH, and RECORDED_TIME the recorded size or 0.
 
59
 
 
60
   These values will be used to avoid unneeded work.
 
61
 */
54
62
static svn_error_t *
55
63
copy_to_tmpdir(svn_skel_t **work_item,
56
64
               svn_node_kind_t *kind,
60
68
               const char *tmpdir_abspath,
61
69
               svn_boolean_t file_copy,
62
70
               svn_boolean_t unversioned,
 
71
               const svn_io_dirent2_t *dirent,
 
72
               svn_filesize_t recorded_size,
 
73
               apr_time_t recorded_time,
63
74
               svn_cancel_func_t cancel_func,
64
75
               void *cancel_baton,
65
76
               apr_pool_t *result_pool,
74
85
 
75
86
  *work_item = NULL;
76
87
 
77
 
  SVN_ERR(svn_io_check_special_path(src_abspath, kind, &is_special,
78
 
                                    scratch_pool));
 
88
  if (dirent)
 
89
    {
 
90
      *kind = dirent->kind;
 
91
      is_special = dirent->special;
 
92
    }
 
93
  else
 
94
    SVN_ERR(svn_io_check_special_path(src_abspath, kind, &is_special,
 
95
                                      scratch_pool));
79
96
  if (*kind == svn_node_none)
80
97
    {
81
98
      return SVN_NO_ERROR;
104
121
         the timestamp might match, than to examine the
105
122
         destination later as the destination timestamp will
106
123
         never match. */
107
 
      SVN_ERR(svn_wc__internal_file_modified_p(&modified,
108
 
                                               db, src_abspath,
109
 
                                               FALSE, scratch_pool));
 
124
 
 
125
      if (dirent
 
126
          && dirent->kind == svn_node_file
 
127
          && recorded_size != SVN_INVALID_FILESIZE
 
128
          && recorded_size == dirent->filesize
 
129
          && recorded_time == dirent->mtime)
 
130
        {
 
131
          modified = FALSE; /* Recorded matches on-disk. Easy out */
 
132
        }
 
133
      else
 
134
        {
 
135
          SVN_ERR(svn_wc__internal_file_modified_p(&modified, db, src_abspath,
 
136
                                                   FALSE, scratch_pool));
 
137
        }
 
138
 
110
139
      if (!modified)
111
140
        {
112
141
          /* Why create a temp copy if we can just reinstall from pristine? */
117
146
          return SVN_NO_ERROR;
118
147
        }
119
148
    }
 
149
  else if (*kind == svn_node_dir && !file_copy)
 
150
    {
 
151
      /* Just build a new direcory from the workqueue */
 
152
      SVN_ERR(svn_wc__wq_build_dir_install(work_item,
 
153
                                           db, dst_abspath,
 
154
                                           result_pool, scratch_pool));
 
155
 
 
156
      return SVN_NO_ERROR;
 
157
    }
120
158
 
121
159
  /* Set DST_TMP_ABSPATH to a temporary unique path.  If *KIND is file, leave
122
160
     a file there and then overwrite it; otherwise leave no node on disk at
172
210
   versioned file itself.
173
211
 
174
212
   This also works for versioned symlinks that are stored in the db as
175
 
   svn_node_file with svn:special set. */
 
213
   svn_node_file with svn:special set.
 
214
 
 
215
   If DIRENT is not NULL, it contains the on-disk information of SRC_ABSPATH.
 
216
   RECORDED_SIZE (if not SVN_INVALID_FILESIZE) contains the recorded size of
 
217
   SRC_ABSPATH, and RECORDED_TIME the recorded size or 0.
 
218
 
 
219
   These values will be used to avoid unneeded work.
 
220
*/
176
221
static svn_error_t *
177
222
copy_versioned_file(svn_wc__db_t *db,
178
223
                    const char *src_abspath,
182
227
                    svn_boolean_t metadata_only,
183
228
                    svn_boolean_t conflicted,
184
229
                    svn_boolean_t is_move,
 
230
                    const svn_io_dirent2_t *dirent,
 
231
                    svn_filesize_t recorded_size,
 
232
                    apr_time_t recorded_time,
185
233
                    svn_cancel_func_t cancel_func,
186
234
                    void *cancel_baton,
187
235
                    svn_wc_notify_func2_t notify_func,
210
258
          svn_error_t *err;
211
259
 
212
260
          /* Is there a text conflict at the source path? */
213
 
          SVN_ERR(svn_wc__db_read_conflict(&conflict, db, src_abspath,
214
 
                                         scratch_pool, scratch_pool));
 
261
          SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL,
 
262
                                           db, src_abspath,
 
263
                                           scratch_pool, scratch_pool));
215
264
 
216
265
          err = svn_wc__conflict_read_text_conflict(&conflict_working, NULL, NULL,
217
266
                                                    db, src_abspath, conflict,
248
297
                             dst_abspath, tmpdir_abspath,
249
298
                             TRUE /* file_copy */,
250
299
                             handle_as_unversioned /* unversioned */,
 
300
                             dirent, recorded_size, recorded_time,
251
301
                             cancel_func, cancel_baton,
252
302
                             scratch_pool, scratch_pool));
253
303
    }
265
315
                               scratch_pool);
266
316
      notify->kind = svn_node_file;
267
317
 
268
 
      /* When we notify that we performed a copy, make sure we already did */
269
 
      if (work_items != NULL)
270
 
        SVN_ERR(svn_wc__wq_run(db, dst_abspath,
271
 
                               cancel_func, cancel_baton, scratch_pool));
272
318
      (*notify_func)(notify_baton, notify, scratch_pool);
273
319
    }
274
320
  return SVN_NO_ERROR;
282
328
   data in addition to copying the directory.
283
329
 
284
330
   WITHIN_ONE_WC is TRUE if the copy/move is within a single working copy (root)
 
331
 
 
332
   If DIRENT is not NULL, it contains the on-disk information of SRC_ABSPATH.
285
333
 */
286
334
static svn_error_t *
287
335
copy_versioned_dir(svn_wc__db_t *db,
291
339
                   const char *tmpdir_abspath,
292
340
                   svn_boolean_t metadata_only,
293
341
                   svn_boolean_t is_move,
 
342
                   const svn_io_dirent2_t *dirent,
294
343
                   svn_cancel_func_t cancel_func,
295
344
                   void *cancel_baton,
296
345
                   svn_wc_notify_func2_t notify_func,
314
363
                             tmpdir_abspath,
315
364
                             FALSE /* file_copy */,
316
365
                             FALSE /* unversioned */,
 
366
                             dirent, SVN_INVALID_FILESIZE, 0,
317
367
                             cancel_func, cancel_baton,
318
368
                             scratch_pool, scratch_pool));
319
369
    }
353
403
  SVN_ERR(svn_wc__db_read_children_info(&versioned_children,
354
404
                                        &conflicted_children,
355
405
                                        db, src_abspath,
 
406
                                        FALSE /* base_tree_only */,
356
407
                                        scratch_pool, iterpool));
357
408
  for (hi = apr_hash_first(scratch_pool, versioned_children);
358
409
       hi;
366
417
      if (cancel_func)
367
418
        SVN_ERR(cancel_func(cancel_baton));
368
419
 
369
 
      child_name = svn__apr_hash_index_key(hi);
370
 
      info = svn__apr_hash_index_val(hi);
 
420
      child_name = apr_hash_this_key(hi);
 
421
      info = apr_hash_this_val(hi);
371
422
      child_src_abspath = svn_dirent_join(src_abspath, child_name, iterpool);
372
423
      child_dst_abspath = svn_dirent_join(dst_abspath, child_name, iterpool);
373
424
 
394
445
                                            tmpdir_abspath,
395
446
                                            metadata_only, info->conflicted,
396
447
                                            is_move,
 
448
                                            disk_children
 
449
                                              ? svn_hash_gets(disk_children,
 
450
                                                              child_name)
 
451
                                              : NULL,
 
452
                                            info->recorded_size,
 
453
                                            info->recorded_time,
397
454
                                            cancel_func, cancel_baton,
398
455
                                            NULL, NULL,
399
456
                                            iterpool));
403
460
                                       child_src_abspath, child_dst_abspath,
404
461
                                       dst_op_root_abspath, tmpdir_abspath,
405
462
                                       metadata_only, is_move,
 
463
                                       disk_children
 
464
                                              ? svn_hash_gets(disk_children,
 
465
                                                              child_name)
 
466
                                              : NULL,
406
467
                                       cancel_func, cancel_baton, NULL, NULL,
407
468
                                       iterpool));
408
469
          else
421
482
                                     child_dst_abspath, dst_op_root_abspath,
422
483
                                     is_move, NULL, iterpool));
423
484
 
424
 
          /* Don't recurse on children while all we do is creating not-present
 
485
          /* Don't recurse on children when all we do is creating not-present
425
486
             children */
426
487
        }
427
488
      else if (info->status == svn_wc__db_status_incomplete)
467
528
      for (hi = apr_hash_first(scratch_pool, disk_children); hi;
468
529
           hi = apr_hash_next(hi))
469
530
        {
470
 
          const char *name = svn__apr_hash_index_key(hi);
 
531
          const char *name = apr_hash_this_key(hi);
471
532
          const char *unver_src_abspath, *unver_dst_abspath;
472
533
          svn_skel_t *work_item;
473
534
 
488
549
          SVN_ERR(copy_to_tmpdir(&work_item, NULL, db, unver_src_abspath,
489
550
                                 unver_dst_abspath, tmpdir_abspath,
490
551
                                 TRUE /* recursive */, TRUE /* unversioned */,
 
552
                                 NULL, SVN_INVALID_FILESIZE, 0,
491
553
                                 cancel_func, cancel_baton,
492
554
                                 scratch_pool, iterpool));
493
555
 
507
569
 * The additional parameter IS_MOVE indicates whether this is a copy or
508
570
 * a move operation.
509
571
 *
510
 
 * If MOVE_DEGRADED_TO_COPY is not NULL and a move had to be degraded
511
 
 * to a copy, then set *MOVE_DEGRADED_TO_COPY. */
 
572
 * If RECORD_MOVE_ON_DELETE is not NULL and a move had to be degraded
 
573
 * to a copy, then set *RECORD_MOVE_ON_DELETE to FALSE. */
512
574
static svn_error_t *
513
 
copy_or_move(svn_boolean_t *move_degraded_to_copy,
 
575
copy_or_move(svn_boolean_t *record_move_on_delete,
514
576
             svn_wc_context_t *wc_ctx,
515
577
             const char *src_abspath,
516
578
             const char *dst_abspath,
533
595
  svn_boolean_t within_one_wc;
534
596
  svn_wc__db_status_t src_status;
535
597
  svn_error_t *err;
 
598
  svn_filesize_t recorded_size;
 
599
  apr_time_t recorded_time;
536
600
 
537
601
  SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath));
538
602
  SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
550
614
    err = svn_wc__db_read_info(&src_status, &src_db_kind, NULL,
551
615
                               &src_repos_relpath, &src_repos_root_url,
552
616
                               &src_repos_uuid, NULL, NULL, NULL, NULL, NULL,
553
 
                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 
617
                               NULL, NULL, NULL, NULL, NULL, NULL,
 
618
                               &recorded_size, &recorded_time,
554
619
                               NULL, &conflicted, NULL, NULL, NULL, NULL,
555
620
                               NULL, NULL,
556
621
                               db, src_abspath, scratch_pool, scratch_pool);
643
708
                                           scratch_pool, scratch_pool));
644
709
        else
645
710
          /* If not added, the node must have a base or we can't copy */
646
 
          SVN_ERR(svn_wc__db_scan_base_repos(NULL, &src_repos_root_url,
647
 
                                             &src_repos_uuid,
648
 
                                             db, src_abspath,
649
 
                                             scratch_pool, scratch_pool));
 
711
          SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL,
 
712
                                           &src_repos_root_url,
 
713
                                           &src_repos_uuid, NULL, NULL, NULL,
 
714
                                           NULL, NULL, NULL, NULL, NULL, NULL,
 
715
                                           NULL,
 
716
                                           db, src_abspath,
 
717
                                           scratch_pool, scratch_pool));
650
718
      }
651
719
 
652
720
    if (!dst_repos_root_url)
660
728
                                           scratch_pool, scratch_pool));
661
729
        else
662
730
          /* If not added, the node must have a base or we can't copy */
663
 
          SVN_ERR(svn_wc__db_scan_base_repos(NULL, &dst_repos_root_url,
664
 
                                             &dst_repos_uuid,
665
 
                                             db, dstdir_abspath,
666
 
                                             scratch_pool, scratch_pool));
 
731
          SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL,
 
732
                                           &dst_repos_root_url,
 
733
                                           &dst_repos_uuid, NULL, NULL, NULL,
 
734
                                           NULL, NULL, NULL, NULL, NULL, NULL,
 
735
                                           NULL,
 
736
                                           db, dstdir_abspath,
 
737
                                           scratch_pool, scratch_pool));
667
738
      }
668
739
 
669
740
    if (strcmp(src_repos_root_url, dst_repos_root_url) != 0
751
822
  if (is_move
752
823
      && !within_one_wc)
753
824
    {
754
 
      if (move_degraded_to_copy)
755
 
        *move_degraded_to_copy = TRUE;
 
825
      if (record_move_on_delete)
 
826
        *record_move_on_delete = FALSE;
756
827
 
757
828
      is_move = FALSE;
758
829
    }
768
839
      err = copy_versioned_file(db, src_abspath, dst_abspath, dst_abspath,
769
840
                                tmpdir_abspath,
770
841
                                metadata_only, conflicted, is_move,
 
842
                                NULL, recorded_size, recorded_time,
771
843
                                cancel_func, cancel_baton,
772
844
                                notify_func, notify_baton,
773
845
                                scratch_pool);
795
867
                                                                scratch_pool),
796
868
                                         min_rev, max_rev);
797
869
 
 
870
#ifndef RECORD_MIXED_MOVE
798
871
              is_move = FALSE;
799
 
              if (move_degraded_to_copy)
800
 
                *move_degraded_to_copy = TRUE;
 
872
              if (record_move_on_delete)
 
873
                *record_move_on_delete = FALSE;
 
874
#endif
801
875
            }
802
876
        }
803
877
 
804
878
      err = copy_versioned_dir(db, src_abspath, dst_abspath, dst_abspath,
805
879
                               tmpdir_abspath, metadata_only, is_move,
 
880
                               NULL /* dirent */,
806
881
                               cancel_func, cancel_baton,
807
882
                               notify_func, notify_baton,
808
883
                               scratch_pool);
871
946
{
872
947
  svn_skel_t *conflict;
873
948
 
874
 
  SVN_ERR(svn_wc__db_read_conflict(&conflict, db, src_abspath,
 
949
  SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL,
 
950
                                   db, src_abspath,
875
951
                                   scratch_pool, scratch_pool));
876
952
 
877
953
  /* Do we have conflict markers that should be removed? */
923
999
remove_all_conflict_markers(svn_wc__db_t *db,
924
1000
                            const char *src_dir_abspath,
925
1001
                            const char *dst_dir_abspath,
 
1002
                            svn_cancel_func_t cancel_func,
 
1003
                            void *cancel_baton,
926
1004
                            apr_pool_t *scratch_pool)
927
1005
{
928
1006
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
936
1014
          artillery. */
937
1015
  SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts, db,
938
1016
                                        src_dir_abspath,
 
1017
                                        FALSE /* base_tree_only */,
939
1018
                                        scratch_pool, iterpool));
940
1019
 
941
1020
  for (hi = apr_hash_first(scratch_pool, nodes);
942
1021
       hi;
943
1022
       hi = apr_hash_next(hi))
944
1023
    {
945
 
      const char *name = svn__apr_hash_index_key(hi);
946
 
      struct svn_wc__db_info_t *info = svn__apr_hash_index_val(hi);
 
1024
      const char *name = apr_hash_this_key(hi);
 
1025
      struct svn_wc__db_info_t *info = apr_hash_this_val(hi);
 
1026
 
 
1027
      if (cancel_func)
 
1028
        SVN_ERR(cancel_func(cancel_baton));
947
1029
 
948
1030
      if (info->conflicted)
949
1031
        {
961
1043
                            db,
962
1044
                            svn_dirent_join(src_dir_abspath, name, iterpool),
963
1045
                            svn_dirent_join(dst_dir_abspath, name, iterpool),
 
1046
                            cancel_func, cancel_baton,
964
1047
                            iterpool));
965
1048
        }
966
1049
    }
982
1065
              apr_pool_t *scratch_pool)
983
1066
{
984
1067
  svn_wc__db_t *db = wc_ctx->db;
985
 
  svn_boolean_t move_degraded_to_copy = FALSE;
 
1068
  svn_boolean_t record_on_delete = TRUE;
986
1069
  svn_node_kind_t kind;
987
1070
  svn_boolean_t conflicted;
988
1071
 
994
1077
                              svn_dirent_dirname(dst_abspath, scratch_pool),
995
1078
                              scratch_pool));
996
1079
 
997
 
  SVN_ERR(copy_or_move(&move_degraded_to_copy,
 
1080
  SVN_ERR(copy_or_move(&record_on_delete,
998
1081
                       wc_ctx, src_abspath, dst_abspath,
999
1082
                       TRUE /* metadata_only */,
1000
1083
                       TRUE /* is_move */,
1018
1101
     is still in a valid state. So be careful when switching this over
1019
1102
     to the workqueue. */
1020
1103
  if (!metadata_only)
1021
 
    SVN_ERR(svn_io_file_rename(src_abspath, dst_abspath, scratch_pool));
 
1104
    {
 
1105
      svn_error_t *err;
 
1106
 
 
1107
      err = svn_error_trace(svn_io_file_rename(src_abspath, dst_abspath,
 
1108
                                               scratch_pool));
 
1109
 
 
1110
      /* Let's try if we can keep wc.db consistent even when the move
 
1111
         fails. Deleting the target is a wc.db only operation, while
 
1112
         going forward (delaying the error) would try to change
 
1113
         conflict markers, which might also fail. */
 
1114
      if (err)
 
1115
        return svn_error_trace(
 
1116
          svn_error_compose_create(
 
1117
              err,
 
1118
              svn_wc__db_op_delete(wc_ctx->db, dst_abspath, NULL, TRUE,
 
1119
                                   NULL, NULL, cancel_func, cancel_baton,
 
1120
                                   NULL, NULL,
 
1121
                                   scratch_pool)));
 
1122
    }
1022
1123
 
1023
1124
  SVN_ERR(svn_wc__db_read_info(NULL, &kind, NULL, NULL, NULL, NULL, NULL,
1024
1125
                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1030
1131
 
1031
1132
  if (kind == svn_node_dir)
1032
1133
    SVN_ERR(remove_all_conflict_markers(db, src_abspath, dst_abspath,
 
1134
                                        cancel_func, cancel_baton,
1033
1135
                                        scratch_pool));
1034
1136
 
1035
1137
  if (conflicted)
1045
1147
    }
1046
1148
 
1047
1149
  SVN_ERR(svn_wc__db_op_delete(db, src_abspath,
1048
 
                               move_degraded_to_copy ? NULL : dst_abspath,
 
1150
                               record_on_delete ? dst_abspath : NULL,
1049
1151
                               TRUE /* delete_dir_externals */,
1050
1152
                               NULL /* conflict */, NULL /* work_items */,
1051
1153
                               cancel_func, cancel_baton,