You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ph...@apache.org on 2015/03/12 16:31:17 UTC

svn commit: r1666222 - /subversion/trunk/subversion/tests/cmdline/patch_tests.py

Author: philip
Date: Thu Mar 12 15:31:17 2015
New Revision: 1666222

URL: http://svn.apache.org/r1666222
Log:
Regression tests for patch's symlink traversal behaviour.

* subversion/tests/cmdline/patch_tests.py
  (patch_symlink_traversal, patch_symlink_traversal2): New tests.
  (test_list): Add new tests.

Modified:
    subversion/trunk/subversion/tests/cmdline/patch_tests.py

Modified: subversion/trunk/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/patch_tests.py?rev=1666222&r1=1666221&r2=1666222&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/patch_tests.py Thu Mar 12 15:31:17 2015
@@ -5437,6 +5437,189 @@ def patch_closest(sbox):
                                        expected_output, expected_disk,
                                        expected_status, expected_skip)
 
+@SkipUnless(svntest.main.is_posix_os)
+def patch_symlink_traversal(sbox):
+  """symlink traversal behaviour"""
+
+  sbox.build(read_only=True)
+  wc_dir = sbox.wc_dir
+  alpha_contents = "This is the file 'alpha'.\n"
+
+  # A/B/E/unversioned -> alpha
+  # A/B/E/versioned -> alpha
+  # A/B/unversioned -> E         (so A/B/unversioned/alpha is A/B/E/alpha)
+  # A/B/versioned -> E           (so A/B/versioned/alpha is A/B/E/alpha)
+  os.symlink('alpha', sbox.ospath('A/B/E/unversioned'))
+  os.symlink('alpha', sbox.ospath('A/B/E/versioned'))
+  os.symlink('E', sbox.ospath('A/B/unversioned'))
+  os.symlink('E', sbox.ospath('A/B/versioned'))
+  sbox.simple_add('A/B/E/versioned', 'A/B/versioned')
+
+  prepatch_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  prepatch_status.add({'A/B/E/versioned' : Item(status='A ', wc_rev='-')})
+  prepatch_status.add({'A/B/versioned' : Item(status='A ', wc_rev='-')})
+  svntest.actions.run_and_verify_status(wc_dir, prepatch_status)
+
+  # Patch through unversioned symlink to file
+  unidiff_patch = (
+    "Index: A/B/E/unversioned\n"
+    "===================================================================\n"
+    "--- A/B/E/unversioned\t(revision 2)\n"
+    "+++ A/B/E/unversioned\t(working copy)\n"
+    "@@ -1 +1,2 @@\n"
+    " This is the file 'alpha'.\n"
+    "+xx\n"
+    )
+  patch_file_path = make_patch_path(sbox)
+  svntest.main.file_write(patch_file_path, unidiff_patch)
+
+  expected_output = [
+    'Skipped missing target: \'%s\'\n' % sbox.ospath('A/B/E/unversioned'),
+  ] + svntest.main.summary_of_conflicts(skipped_paths=1)
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({'A/B/E/unversioned' : Item(contents=alpha_contents)})
+  expected_disk.add({'A/B/E/versioned' : Item(contents=alpha_contents)})
+  expected_disk.add({'A/B/unversioned' : Item()})
+  expected_disk.add({'A/B/versioned' : Item()})
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.add({'A/B/E/versioned' : Item(status='A ', wc_rev='-')})
+  expected_status.add({'A/B/versioned' : Item(status='A ', wc_rev='-')})
+  expected_skip = wc.State('', {
+    sbox.ospath('A/B/E/unversioned') : Item(verb='Skipped missing target'),
+  })
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output, expected_disk,
+                                       expected_status, expected_skip)
+  svntest.actions.run_and_verify_status(wc_dir, prepatch_status)
+
+  # Patch through versioned symlink to file
+  unidiff_patch = (
+    "Index: A/B/E/versioned\n"
+    "===================================================================\n"
+    "--- A/B/E/versioned\t(revision 2)\n"
+    "+++ A/B/E/versioned\t(working copy)\n"
+    "@@ -1 +1,2 @@\n"
+    " This is the file 'alpha'.\n"
+    "+xx\n"
+    )
+  patch_file_path = make_patch_path(sbox)
+  svntest.main.file_write(patch_file_path, unidiff_patch)
+  reject_contents = (
+    "--- A/B/E/versioned\n"
+    "+++ A/B/E/versioned\n"
+    "@@ -1,1 +1,2 @@\n"
+    " This is the file 'alpha'.\n"
+    "+xx\n"
+  )
+
+  expected_output = [
+    'C         %s\n' % sbox.ospath('A/B/E/versioned'),
+    '>         rejected hunk @@ -1,1 +1,2 @@\n',
+  ] + svntest.main.summary_of_conflicts(text_conflicts=1)
+  expected_disk.add({'A/B/E/versioned.svnpatch.rej'
+                     : Item(contents=reject_contents)})
+  expected_skip = wc.State('', { })
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output, expected_disk,
+                                       expected_status, expected_skip)
+  os.remove(sbox.ospath('A/B/E/versioned.svnpatch.rej'))
+  expected_disk.remove('A/B/E/versioned.svnpatch.rej')
+  svntest.actions.run_and_verify_status(wc_dir, prepatch_status)
+
+  # Patch through unversioned symlink to parent of file
+  unidiff_patch = (
+    "Index: A/B/unversioned/alpha\n"
+    "===================================================================\n"
+    "--- A/B/unversioned/alpha\t(revision 2)\n"
+    "+++ A/B/unversioned/alpha\t(working copy)\n"
+    "@@ -1 +1,2 @@\n"
+    " This is the file 'alpha'.\n"
+    "+xx\n"
+    )
+  patch_file_path = make_patch_path(sbox)
+  svntest.main.file_write(patch_file_path, unidiff_patch)
+
+  expected_output = [
+    'Skipped missing target: \'%s\'\n' % sbox.ospath('A/B/unversioned/alpha'),
+  ] + svntest.main.summary_of_conflicts(skipped_paths=1)
+  expected_skip = wc.State('', {
+    sbox.ospath('A/B/unversioned/alpha') : Item(verb='Skipped missing target'),
+  })
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output, expected_disk,
+                                       expected_status, expected_skip)
+  svntest.actions.run_and_verify_status(wc_dir, prepatch_status)
+
+  # Patch through versioned symlink to parent of file
+  unidiff_patch = (
+    "Index: A/B/versioned/alpha\n"
+    "===================================================================\n"
+    "--- A/B/versioned/alpha\t(revision 2)\n"
+    "+++ A/B/versioned/alpha\t(working copy)\n"
+    "@@ -1 +1,2 @@\n"
+    " This is the file 'alpha'.\n"
+    "+xx\n"
+    )
+  patch_file_path = make_patch_path(sbox)
+  svntest.main.file_write(patch_file_path, unidiff_patch)
+
+  expected_output = [
+    'Skipped missing target: \'%s\'\n' % sbox.ospath('A/B/versioned/alpha'),
+  ] + svntest.main.summary_of_conflicts(skipped_paths=1)
+  expected_skip = wc.State('', {
+    sbox.ospath('A/B/versioned/alpha') :  Item(verb='Skipped missing target'),
+  })
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output, expected_disk,
+                                       expected_status, expected_skip)
+  svntest.actions.run_and_verify_status(wc_dir, prepatch_status)
+
+@SkipUnless(svntest.main.is_posix_os)
+def patch_obstructing_symlink_traversal(sbox):
+  """obstructing symlink traversal behaviour"""
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  alpha_contents = "This is the file 'alpha'.\n"
+  sbox.simple_append('A/B/F/alpha', alpha_contents)
+  sbox.simple_add('A/B/F/alpha')
+  sbox.simple_commit()
+  sbox.simple_update()
+
+  # Unversioned symlink A/B/E -> F obstructing versioned A/B/E so
+  # versioned A/B/E/alpha is A/B/F/alpha
+  svntest.main.safe_rmtree(sbox.ospath('A/B/E'))
+  os.symlink('F', sbox.ospath('A/B/E'))
+
+  unidiff_patch = (
+    "Index: A/B/E/alpha\n"
+    "===================================================================\n"
+    "--- A/B/E/alpha\t(revision 2)\n"
+    "+++ A/B/E/alpha\t(working copy)\n"
+    "@@ -1 +1,2 @@\n"
+    " This is the file 'alpha'.\n"
+    "+xx\n"
+    )
+  patch_file_path = make_patch_path(sbox)
+  svntest.main.file_write(patch_file_path, unidiff_patch)
+
+  ### Patch applies through the unversioned symlink
+  expected_output = [
+    'U         %s\n' % sbox.ospath('A/B/E/alpha'),
+  ]
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.remove('A/B/E/alpha', 'A/B/E/beta')
+  expected_disk.add({'A/B/F/alpha' : Item(contents=alpha_contents+"xx\n")})
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.add({'A/B/F/alpha' : Item(status='  ', wc_rev=2)})
+  expected_status.tweak('A/B/E', status='~ ')
+  expected_status.tweak('A/B/E/alpha', 'A/B/F/alpha', status='M ')
+  expected_status.tweak('A/B/E/beta', status='! ')
+  expected_skip = wc.State('', { })
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output, expected_disk,
+                                       expected_status, expected_skip)
+
 ########################################################################
 #Run the tests
 
@@ -5496,6 +5679,8 @@ test_list = [ None,
               patch_hunk_overlap,
               patch_delete_modified,
               patch_closest,
+              patch_symlink_traversal,
+              patch_obstructing_symlink_traversal,
             ]
 
 if __name__ == '__main__':