Hello!

After some investigation I realized that PATH passed by repos
layer to AUTHZ_FUNC is not guaranted to be canonical.  In fact, when
path is under copied directory (as in #4760) it does not contain
leading slash.  This causes ary_prefix_match() function to ignore
those paths, since it requires canonical path.

I've attached patch with fix.

Log message:
[[[
Follow-up to r1811992: Canonicalize PATH before passing it to the FILTER_FUNC.

In some cases (e.g. for nodes under copied directories) PATH passed by
repos layer to AUTHZ_FUNC may be non-canonical (missing leading '/').  This
causes FILTER_FUNC implemented in svnadmin to wrongly report PATH as "not
included".

This fixes #4760.

* subversion/libsvn_repos/dump.c
  (dump_filter_authz_func): Canonicalize PATH before passing it
   to the FILTER_FUNC.  Add comment.

* subversion/tests/cmdline/svnadmin_tests.py
  (dump_include_copied_directory): New.
  (test_list): Add new test to table.

Patch by: sergey.raevskiy{_AT_}visualsvn.com
]]]

On Fri, Feb 8, 2019 at 6:27 PM Julian Foad <julianf...@apache.org> wrote:
>
> Sergey Raevskiy wrote:
> > > Ping! Sergey or anyone, are you able to investigate this?
> >
> > Hello!
> >
> > Sorry for the late reply. I'm plannig to investigate this in short time.
>
> That's good to hear! Thank you.
>
> If you need any help, please ask here or in the #svn-dev IRC channel. I'm 
> sure we'll be happy to help as much as we can.
>
> --
> - Julian
>
>
> > > Julian Foad wrote on 2018-11-30:
> > > >     https://issues.apache.org/jira/browse/SVN-4729
> [...]
> > > > A user has reported a problem with this feature.
> > > >     https://issues.apache.org/jira/browse/SVN-4760
> > > >
> > > > It looks like when the source of a copied directory is excluded, it is
> > > > only adding the directory itself and not adding the directory's
> > > > contents. That sounds to me like a bug -- it is not the behaviour I
> > > > would expect.
> > > >
> > > > I see that the regression tests only test with an empty source 
> > > > directory.
> > > >     subversion/tests/cmdline/svnadmin_tests.py : 
> > > > dump_exclude_copysource() etc.
Index: subversion/libsvn_repos/dump.c
===================================================================
--- subversion/libsvn_repos/dump.c      (revision 1853440)
+++ subversion/libsvn_repos/dump.c      (working copy)
@@ -44,6 +44,7 @@
 #include "private/svn_sorts_private.h"
 #include "private/svn_utf_private.h"
 #include "private/svn_cache.h"
+#include "private/svn_fspath.h"
 
 #define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
 
@@ -1996,6 +1997,11 @@ dump_filter_authz_func(svn_boolean_t *allowed,
 {
   dump_filter_baton_t *b = baton;
 
+  /* For some nodes (e.g. files under copied directory) PATH may be
+   * non-canonical (missing leading '/').  Canonicalize PATH before
+   * passing it to FILTER_FUNC. */
+  path = svn_fspath__canonicalize(path, pool);
+
   return svn_error_trace(b->filter_func(allowed, root, path, b->filter_baton,
                                         pool));
 }
Index: subversion/tests/cmdline/svnadmin_tests.py
===================================================================
--- subversion/tests/cmdline/svnadmin_tests.py  (revision 1853440)
+++ subversion/tests/cmdline/svnadmin_tests.py  (working copy)
@@ -3920,6 +3920,51 @@ def recover_prunes_rep_cache_when_disabled(sbox):
 
   check_recover_prunes_rep_cache(sbox, enable_rep_sharing=False)
 
+@Issue(4760)
+def dump_include_copied_directory(sbox):
+  "include copied directory with nested nodes"
+
+  sbox.build(create_wc=False)
+
+  svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], "copy",
+                                     sbox.repo_url + '/A/D',
+                                     sbox.repo_url + '/COPY',
+                                     "-m", "Create branch.")
+
+  # Dump repository with only /COPY path included.
+  _, dump, _ = svntest.actions.run_and_verify_svnadmin(None, [],
+                                                       'dump', '-q',
+                                                       '--include', '/COPY',
+                                                       sbox.repo_dir)
+
+  # Load repository from dump.
+  sbox2 = sbox.clone_dependent()
+  sbox2.build(create_wc=False, empty=True)
+  load_and_verify_dumpstream(sbox2, None, [], None, False, dump)
+
+  # Check log.
+  expected_output = svntest.verify.RegexListOutput([
+    '-+\\n',
+    'r2\ .*\n',
+    # Only '/COPY' is added
+    re.escape('Changed paths:\n'),
+    re.escape('   A /COPY'),
+    re.escape('   A /COPY/G'),
+    re.escape('   A /COPY/G/pi'),
+    re.escape('   A /COPY/G/rho'),
+    re.escape('   A /COPY/G/tau'),
+    re.escape('   A /COPY/H'),
+    re.escape('   A /COPY/H/chi'),
+    re.escape('   A /COPY/H/omega'),
+    re.escape('   A /COPY/H/psi'),
+    re.escape('   A /COPY/gamma'),
+    '-+\\n',
+    'r1\ .*\n',
+    '-+\\n'
+  ])
+  svntest.actions.run_and_verify_svn(expected_output, [],
+                                     'log', '-v', '-q', sbox2.repo_url)
+
 ########################################################################
 # Run the tests
 
@@ -3997,6 +4042,7 @@ test_list = [ None,
               dump_no_canonicalize_svndate,
               recover_prunes_rep_cache_when_enabled,
               recover_prunes_rep_cache_when_disabled,
+              dump_include_copied_directory,
              ]
 
 if __name__ == '__main__':

Reply via email to