You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@subversion.apache.org by "Julian Foad (JIRA)" <ji...@apache.org> on 2019/04/24 16:20:00 UTC

[jira] [Deleted] (SVN-4809) GitHub Customer Data Protection

     [ https://issues.apache.org/jira/browse/SVN-4809?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Julian Foad deleted SVN-4809:
-----------------------------


> GitHub Customer Data Protection 
> --------------------------------
>
>                 Key: SVN-4809
>                 URL: https://issues.apache.org/jira/browse/SVN-4809
>             Project: Subversion
>          Issue Type: Test
>         Environment:    A description of GIT's unidiff-compatible patch extensions, which we might use for "svn patch" format. Copied from Augie Fackler's email <[http://subversion.tigris.org/ds/viewMessage.do?dsForumId=462&dsMessageId=2388540]>. Documentation for the format is pretty sparse. Here's an overview (now  that I've written this out, it might be more like "everything you need  to know to support this format other than specifics of how base85  works"): Copies and renames are both handled like this: diff --git a/\{oldname} b/\{newname} copy from \{oldname} copy to \{newname} \{normal unidiff data here if there was a difference, only for how new  is different from old} (naturally, with copy instead of rename if that was the case} New files: diff --git a/alpha b/alpha new file mode 100644 — /dev/null +++ b/alpha @@ -0,0 +1,1 @@ +alpha (the longer file mode is used for representing symlinks, they come in  with mode 120000, and the contents are listed as *just* the path of  the symlink, that is, svn's symlink format without the leading 'link ') Removals: diff --git a/README b/README deleted file mode 100644 — a/README +++ /dev/null @@ -1,77 +0,0 @@ \{pile of unidiff data} File mode changes: diff --git a/README b/README old mode 100644 new mode 100755 (I think it's normal for patch implementations to not care about the  old mode, and just apply the new one blindly - the old mode I believe  is more for human consumption or reverse-patching than anything else.  Also, you don't really ever see any modes other than these two - the  first is just "not executable", the second is executable. I've never  *seen* any other modes for regular files). Binaries (this is for literals, which I believe is the new binary in  its entirety. I think there's a delta format which Mercurial does not  support, per a "TODO: deltas" in the code): index \{old hash}..\{new hash} GIT binary patch literal \{file length} \{base85-encoded zlib-compressed data} The hashes are either the nullid (40 0's) if there was (or is) no  text, and are sha1('blob %d\0%s' % (len(text), text, )) (using python syntax). The base85 encoding seems to use a leading z to indicate this isn't  the last line of data, and a leading e to indicate this is the last  line of data. There's more to base85 than that, and I'd gladly take  some time to write down how it works for those interested in  reimplementing it. It appears at first glance to be the part that  requries the most detailed documentation. Supporting binary deltas is something that can obviously come later,  since Mercurial doesn't appear to implement it at all right now. Note  that with binary literals it does not appear that patch -R is  possible. That's really a minor limitation, since you're never using  this on non-version-controlled files anyway. It should be possible to add your own hunk types to this format (once  the base format is supported) that would allow you to transmit  property modifications inline as well (other than symlink and  executable, which are already handled sanely). For those interested in some source code (GPLv2): [http://mercurial.selenic.com/hg/hg/file/ac02b43bc08a/mercurial/patch.py#l195] [http://mercurial.selenic.com/hg/hg/file/ac02b43bc08a/mercurial/patch.py#l710] [http://mercurial.selenic.com/hg/hg/file/ac02b43bc08a/mercurial/pure/base85.py]
>            Reporter: SpArkx
>            Priority: Minor
>              Labels: SpArkx, eysz7x
>
> {code:java}
> /*
>  * externals.c:  handle the svn:externals property
>  *
>  * ====================================================================
>  *    Licensed to the Apache Software Foundation (ASF) under one
>  *    or more contributor license agreements.  See the NOTICE file
>  *    distributed with this work for additional information
>  *    regarding copyright ownership.  The ASF licenses this file
>  *    to you under the Apache License, Version 2.0 (the
>  *    "License"); you may not use this file except in compliance
>  *    with the License.  You may obtain a copy of the License at
>  *
>  *      http://www.apache.org/licenses/LICENSE-2.0
>  *
>  *    Unless required by applicable law or agreed to in writing,
>  *    software distributed under the License is distributed on an
>  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
>  *    KIND, either express or implied.  See the License for the
>  *    specific language governing permissions and limitations
>  *    under the License.
>  * ====================================================================
>  */
> /* ==================================================================== */
> /*** Includes. ***/
> #include <apr_uri.h>
> #include "svn_hash.h"
> #include "svn_wc.h"
> #include "svn_pools.h"
> #include "svn_client.h"
> #include "svn_types.h"
> #include "svn_error.h"
> #include "svn_dirent_uri.h"
> #include "svn_path.h"
> #include "svn_props.h"
> #include "svn_config.h"
> #include "client.h"
> #include "svn_private_config.h"
> #include "private/svn_wc_private.h"
> /* Remove the directory at LOCAL_ABSPATH from revision control, and do the
>  * same to any revision controlled directories underneath LOCAL_ABSPATH
>  * (including directories not referred to by parent svn administrative areas);
>  * then if LOCAL_ABSPATH is empty afterwards, remove it, else rename it to a
>  * unique name in the same parent directory.
>  *
>  * Pass CANCEL_FUNC, CANCEL_BATON to svn_wc_remove_from_revision_control.
>  *
>  * Use SCRATCH_POOL for all temporary allocation.
>  */
> static svn_error_t *
> relegate_dir_external(svn_wc_context_t *wc_ctx,
>                       const char *wri_abspath,
>                       const char *local_abspath,
>                       svn_cancel_func_t cancel_func,
>                       void *cancel_baton,
>                       svn_wc_notify_func2_t notify_func,
>                       void *notify_baton,
>                       apr_pool_t *scratch_pool)
> {
>   svn_error_t *err = SVN_NO_ERROR;
>   SVN_ERR(svn_wc__acquire_write_lock(NULL, wc_ctx, local_abspath,
>                                      FALSE, scratch_pool, scratch_pool));
>   err = svn_wc__external_remove(wc_ctx, wri_abspath, local_abspath, FALSE,
>                                 cancel_func, cancel_baton, scratch_pool);
>   if (err && (err->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD))
>     {
>       const char *parent_dir;
>       const char *dirname;
>       const char *new_path;
>       svn_error_clear(err);
>       err = SVN_NO_ERROR;
>       svn_dirent_split(&parent_dir, &dirname, local_abspath, scratch_pool);
>       /* Reserve the new dir name. */
>       SVN_ERR(svn_io_open_uniquely_named(NULL, &new_path,
>                                          parent_dir, dirname, ".OLD",
>                                          svn_io_file_del_none,
>                                          scratch_pool, scratch_pool));
>       /* Sigh...  We must fall ever so slightly from grace.
>          Ideally, there would be no window, however brief, when we
>          don't have a reservation on the new name.  Unfortunately,
>          at least in the Unix (Linux?) version of apr_file_rename(),
>          you can't rename a directory over a file, because it's just
>          calling stdio rename(), which says:
>             ENOTDIR
>               A  component used as a directory in oldpath or newpath
>               path is not, in fact, a directory.  Or, oldpath  is
>               a directory, and newpath exists but is not a directory
>          So instead, we get the name, then remove the file (ugh), then
>          rename the directory, hoping that nobody has gotten that name
>          in the meantime -- which would never happen in real life, so
>          no big deal.
>       */
>       /* Do our best, but no biggy if it fails. The rename will fail. */
>       svn_error_clear(svn_io_remove_file2(new_path, TRUE, scratch_pool));
>       /* Rename. If this is still a working copy we should use the working
>          copy rename function (to release open handles) */
>       err = svn_wc__rename_wc(wc_ctx, local_abspath, new_path,
>                               scratch_pool);
>       if (err && err->apr_err == SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
>         {
>           svn_error_clear(err);
>           /* And if it is no longer a working copy, we should just rename
>              it */
>           err = svn_io_file_rename2(local_abspath, new_path, FALSE, scratch_pool);
>         }
>       /* ### TODO: We should notify the user about the rename */
>       if (notify_func)
>         {
>           svn_wc_notify_t *notify;
>           notify = svn_wc_create_notify(err ? local_abspath : new_path,
>                                         svn_wc_notify_left_local_modifications,
>                                         scratch_pool);
>           notify->kind = svn_node_dir;
>           notify->err = err;
>           notify_func(notify_baton, notify, scratch_pool);
>         }
>     }
>   return svn_error_trace(err);
> }
> /* Try to update a directory external at PATH to URL at REVISION.
>    Use POOL for temporary allocations, and use the client context CTX. */
> static svn_error_t *
> switch_dir_external(const char *local_abspath,
>                     const char *url,
>                     const char *url_from_externals_definition,
>                     const svn_opt_revision_t *peg_revision,
>                     const svn_opt_revision_t *revision,
>                     const char *defining_abspath,
>                     svn_boolean_t *timestamp_sleep,
>                     svn_ra_session_t *ra_session,
>                     svn_client_ctx_t *ctx,
>                     apr_pool_t *pool)
> {
>   svn_node_kind_t kind;
>   svn_error_t *err;
>   svn_revnum_t external_peg_rev = SVN_INVALID_REVNUM;
>   svn_revnum_t external_rev = SVN_INVALID_REVNUM;
>   apr_pool_t *subpool = svn_pool_create(pool);
>   const char *repos_root_url;
>   const char *repos_uuid;
>   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
>   if (peg_revision->kind == svn_opt_revision_number)
>     external_peg_rev = peg_revision->value.number;
>   if (revision->kind == svn_opt_revision_number)
>     external_rev = revision->value.number;
>   /*
>    * The code below assumes existing versioned paths are *not* part of
>    * the external's defining working copy.
>    * The working copy library does not support registering externals
>    * on top of existing BASE nodes and will error out if we try.
>    * So if the external target is part of the defining working copy's
>    * BASE tree, don't attempt to create the external. Doing so would
>    * leave behind a switched path instead of an external (since the
>    * switch succeeds but registration of the external in the DB fails).
>    * The working copy then cannot be updated until the path is switched back.
>    * See issue #4085.
>    */
>   SVN_ERR(svn_wc__node_get_base(&kind, NULL, NULL,
>                                 &repos_root_url, &repos_uuid,
>                                 NULL, ctx->wc_ctx, local_abspath,
>                                 TRUE, /* ignore_enoent */
>                                 pool, pool));
>   if (kind != svn_node_unknown)
>     {
>       const char *wcroot_abspath;
>       const char *defining_wcroot_abspath;
>       SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath, ctx->wc_ctx,
>                                  local_abspath, pool, pool));
>       SVN_ERR(svn_wc__get_wcroot(&defining_wcroot_abspath, ctx->wc_ctx,
>                                  defining_abspath, pool, pool));
>       if (strcmp(wcroot_abspath, defining_wcroot_abspath) == 0)
>         return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
>                                  _("The external '%s' defined in %s at '%s' "
>                                    "cannot be checked out because '%s' is "
>                                    "already a versioned path."),
>                                    url_from_externals_definition,
>                                    SVN_PROP_EXTERNALS,
>                                    svn_dirent_local_style(defining_abspath,
>                                                           pool),
>                                    svn_dirent_local_style(local_abspath,
>                                                           pool));
>     }
>   /* If path is a directory, try to update/switch to the correct URL
>      and revision. */
>   SVN_ERR(svn_io_check_path(local_abspath, &kind, pool));
>   if (kind == svn_node_dir)
>     {
>       const char *node_url;
>       /* Doubles as an "is versioned" check. */
>       err = svn_wc__node_get_url(&node_url, ctx->wc_ctx, local_abspath,
>                                  pool, subpool);
>       if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
>         {
>           svn_error_clear(err);
>           err = SVN_NO_ERROR;
>           goto relegate;
>         }
>       else if (err)
>         return svn_error_trace(err);
>       if (node_url)
>         {
>           svn_boolean_t is_wcroot;
>           SVN_ERR(svn_wc__is_wcroot(&is_wcroot, ctx->wc_ctx, local_abspath,
>                                     pool));
>           if (! is_wcroot)
>           {
>             /* This can't be a directory external! */
>             err = svn_wc__external_remove(ctx->wc_ctx, defining_abspath,
>                                           local_abspath,
>                                           TRUE /* declaration_only */,
>                                           ctx->cancel_func, ctx->cancel_baton,
>                                           pool);
>             if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
>               {
>                 /* New external... No problem that we can't remove it */
>                 svn_error_clear(err);
>                 err = NULL;
>               }
>             else if (err)
>               return svn_error_trace(err);
>             return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
>                                      _("The external '%s' defined in %s at '%s' "
>                                        "cannot be checked out because '%s' is "
>                                        "already a versioned path."),
>                                      url_from_externals_definition,
>                                      SVN_PROP_EXTERNALS,
>                                      svn_dirent_local_style(defining_abspath,
>                                                             pool),
>                                      svn_dirent_local_style(local_abspath,
>                                                             pool));
>           }
>           /* If we have what appears to be a version controlled
>              subdir, and its top-level URL matches that of our
>              externals definition, perform an update. */
>           if (strcmp(node_url, url) == 0)
>             {
>               SVN_ERR(svn_client__update_internal(NULL, timestamp_sleep,
>                                                   local_abspath,
>                                                   revision, svn_depth_unknown,
>                                                   FALSE, FALSE, FALSE, TRUE,
>                                                   FALSE, TRUE,
>                                                   ra_session, ctx, subpool));
>               /* We just decided that this existing directory is an external,
>                  so update the external registry with this information, like
>                  when checking out an external */
>               SVN_ERR(svn_wc__external_register(ctx->wc_ctx,
>                                     defining_abspath,
>                                     local_abspath, svn_node_dir,
>                                     repos_root_url, repos_uuid,
>                                     svn_uri_skip_ancestor(repos_root_url,
>                                                           url, pool),
>                                     external_peg_rev,
>                                     external_rev,
>                                     pool));
>               svn_pool_destroy(subpool);
>               goto cleanup;
>             }
>           /* We'd really prefer not to have to do a brute-force
>              relegation -- blowing away the current external working
>              copy and checking it out anew -- so we'll first see if we
>              can get away with a generally cheaper relocation (if
>              required) and switch-style update.
>              To do so, we need to know the repository root URL of the
>              external working copy as it currently sits. */
>           err = svn_wc__node_get_repos_info(NULL, NULL,
>                                             &repos_root_url, &repos_uuid,
>                                             ctx->wc_ctx, local_abspath,
>                                             pool, subpool);
>           if (err)
>             {
>               if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND
>                   && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
>                 return svn_error_trace(err);
>               svn_error_clear(err);
>               repos_root_url = NULL;
>               repos_uuid = NULL;
>             }
>           if (repos_root_url)
>             {
>               /* If the new external target URL is not obviously a
>                  child of the external working copy's current
>                  repository root URL... */
>               if (! svn_uri__is_ancestor(repos_root_url, url))
>                 {
>                   const char *repos_root;
>                   /* ... then figure out precisely which repository
>                       root URL that target URL *is* a child of ... */
>                   SVN_ERR(svn_client_get_repos_root(&repos_root, NULL, url,
>                                                     ctx, subpool, subpool));
>                   /* ... and use that to try to relocate the external
>                      working copy to the target location.  */
>                   err = svn_client_relocate2(local_abspath, repos_root_url,
>                                              repos_root, FALSE, ctx, subpool);
>                   /* If the relocation failed because the new URL
>                      points to a totally different repository, we've
>                      no choice but to relegate and check out a new WC. */
>                   if (err
>                       && (err->apr_err == SVN_ERR_WC_INVALID_RELOCATION
>                           || (err->apr_err
>                               == SVN_ERR_CLIENT_INVALID_RELOCATION)))
>                     {
>                       svn_error_clear(err);
>                       goto relegate;
>                     }
>                   else if (err)
>                     return svn_error_trace(err);
>                   /* If the relocation went without a hitch, we should
>                      have a new repository root URL. */
>                   repos_root_url = repos_root;
>                 }
>               SVN_ERR(svn_client__switch_internal(NULL, local_abspath, url,
>                                                   peg_revision, revision,
>                                                   svn_depth_infinity,
>                                                   TRUE, FALSE, FALSE,
>                                                   TRUE /* ignore_ancestry */,
>                                                   timestamp_sleep,
>                                                   ctx, subpool));
>               SVN_ERR(svn_wc__external_register(ctx->wc_ctx,
>                                                 defining_abspath,
>                                                 local_abspath, svn_node_dir,
>                                                 repos_root_url, repos_uuid,
>                                                 svn_uri_skip_ancestor(
>                                                             repos_root_url,
>                                                             url, subpool),
>                                                 external_peg_rev,
>                                                 external_rev,
>                                                 subpool));
>               svn_pool_destroy(subpool);
>               goto cleanup;
>             }
>         }
>     }
>  relegate:
>   /* Fall back on removing the WC and checking out a new one. */
>   /* Ensure that we don't have any RA sessions or WC locks from failed
>      operations above. */
>   svn_pool_destroy(subpool);
>   if (kind == svn_node_dir)
>     {
>       /* Buh-bye, old and busted ... */
>       SVN_ERR(relegate_dir_external(ctx->wc_ctx, defining_abspath,
>                                     local_abspath,
>                                     ctx->cancel_func, ctx->cancel_baton,
>                                     ctx->notify_func2, ctx->notify_baton2,
>                                     pool));
>     }
>   else
>     {
>       /* The target dir might have multiple components.  Guarantee
>          the path leading down to the last component. */
>       const char *parent = svn_dirent_dirname(local_abspath, pool);
>       SVN_ERR(svn_io_make_dir_recursively(parent, pool));
>     }
>   /* ... Hello, new hotness. */
>   SVN_ERR(svn_client__checkout_internal(NULL, timestamp_sleep,
>                                         url, local_abspath, peg_revision,
>                                         revision, svn_depth_infinity,
>                                         FALSE, FALSE,
>                                         ra_session,
>                                         ctx, pool));
>   SVN_ERR(svn_wc__node_get_repos_info(NULL, NULL,
>                                       &repos_root_url,
>                                       &repos_uuid,
>                                       ctx->wc_ctx, local_abspath,
>                                       pool, pool));
>   SVN_ERR(svn_wc__external_register(ctx->wc_ctx,
>                                     defining_abspath,
>                                     local_abspath, svn_node_dir,
>                                     repos_root_url, repos_uuid,
>                                     svn_uri_skip_ancestor(repos_root_url,
>                                                           url, pool),
>                                     external_peg_rev,
>                                     external_rev,
>                                     pool));
>  cleanup:
>   /* Issues #4123 and #4130: We don't need to keep the newly checked
>      out external's DB open. */
>   SVN_ERR(svn_wc__close_db(local_abspath, ctx->wc_ctx, pool));
>   return SVN_NO_ERROR;
> }
> /* Try to update a file external at LOCAL_ABSPATH to SWITCH_LOC. This function
>    assumes caller has a write lock in CTX.  Use SCRATCH_POOL for temporary
>    allocations, and use the client context CTX. */
> static svn_error_t *
> switch_file_external(const char *local_abspath,
>                      const svn_client__pathrev_t *switch_loc,
>                      const char *record_url,
>                      const svn_opt_revision_t *record_peg_revision,
>                      const svn_opt_revision_t *record_revision,
>                      const char *def_dir_abspath,
>                      svn_ra_session_t *ra_session,
>                      svn_client_ctx_t *ctx,
>                      apr_pool_t *scratch_pool)
> {
>   svn_config_t *cfg = ctx->config
>                       ? svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG)
>                       : NULL;
>   svn_boolean_t use_commit_times;
>   const char *diff3_cmd;
>   const char *preserved_exts_str;
>   const apr_array_header_t *preserved_exts;
>   svn_node_kind_t kind, external_kind;
>   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
>   /* See if the user wants last-commit timestamps instead of current ones. */
>   SVN_ERR(svn_config_get_bool(cfg, &use_commit_times,
>                               SVN_CONFIG_SECTION_MISCELLANY,
>                               SVN_CONFIG_OPTION_USE_COMMIT_TIMES, FALSE));
>   /* Get the external diff3, if any. */
>   svn_config_get(cfg, &diff3_cmd, SVN_CONFIG_SECTION_HELPERS,
>                  SVN_CONFIG_OPTION_DIFF3_CMD, NULL);
>   if (diff3_cmd != NULL)
>     SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, scratch_pool));
>   /* See which files the user wants to preserve the extension of when
>      conflict files are made. */
>   svn_config_get(cfg, &preserved_exts_str, SVN_CONFIG_SECTION_MISCELLANY,
>                  SVN_CONFIG_OPTION_PRESERVED_CF_EXTS, "");
>   preserved_exts = *preserved_exts_str
>     ? svn_cstring_split(preserved_exts_str, "\n\r\t\v ", FALSE, scratch_pool)
>     : NULL;
>   {
>     const char *wcroot_abspath;
>     SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath, ctx->wc_ctx, local_abspath,
>                                scratch_pool, scratch_pool));
>     /* File externals can only be installed inside the current working copy.
>        So verify if the working copy that contains/will contain the target
>        is the defining abspath, or one of its ancestors */
>     if (!svn_dirent_is_ancestor(wcroot_abspath, def_dir_abspath))
>         return svn_error_createf(
>                         SVN_ERR_WC_BAD_PATH, NULL,
>                         _("Cannot insert a file external defined on '%s' "
>                           "into the working copy '%s'."),
>                         svn_dirent_local_style(def_dir_abspath,
>                                                scratch_pool),
>                         svn_dirent_local_style(wcroot_abspath,
>                                                scratch_pool));
>   }
>   SVN_ERR(svn_wc_read_kind2(&kind, ctx->wc_ctx, local_abspath,
>                             TRUE, FALSE, scratch_pool));
>   SVN_ERR(svn_wc__read_external_info(&external_kind, NULL, NULL, NULL, NULL,
>                                      ctx->wc_ctx, local_abspath, local_abspath,
>                                      TRUE, scratch_pool, scratch_pool));
>   /* If there is a versioned item with this name, ensure it's a file
>      external before working with it.  If there is no entry in the
>      working copy, then create an empty file and add it to the working
>      copy. */
>   if (kind != svn_node_none && kind != svn_node_unknown)
>     {
>       if (external_kind != svn_node_file)
>         {
>           return svn_error_createf(
>               SVN_ERR_CLIENT_FILE_EXTERNAL_OVERWRITE_VERSIONED, 0,
>              _("The file external from '%s' cannot overwrite the existing "
>                "versioned item at '%s'"),
>              switch_loc->url,
>              svn_dirent_local_style(local_abspath, scratch_pool));
>         }
>     }
>   else
>     {
>       svn_node_kind_t disk_kind;
>       SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, scratch_pool));
>       if (disk_kind == svn_node_file || disk_kind == svn_node_dir)
>         return svn_error_createf(SVN_ERR_WC_PATH_FOUND, NULL,
>                                  _("The file external '%s' can not be "
>                                    "created because the node exists."),
>                                  svn_dirent_local_style(local_abspath,
>                                                         scratch_pool));
>     }
>   {
>     const svn_ra_reporter3_t *reporter;
>     void *report_baton;
>     const svn_delta_editor_t *switch_editor;
>     void *switch_baton;
>     svn_revnum_t revnum;
>     apr_array_header_t *inherited_props;
>     const char *target = svn_dirent_basename(local_abspath, scratch_pool);
>     /* Get the external file's iprops. */
>     SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props, "",
>                                        switch_loc->rev,
>                                        scratch_pool, scratch_pool));
>     SVN_ERR(svn_ra_reparent(ra_session,
>                             svn_uri_dirname(switch_loc->url, scratch_pool),
>                             scratch_pool));
>     SVN_ERR(svn_wc__get_file_external_editor(&switch_editor, &switch_baton,
>                                              &revnum, ctx->wc_ctx,
>                                              local_abspath,
>                                              def_dir_abspath,
>                                              switch_loc->url,
>                                              switch_loc->repos_root_url,
>                                              switch_loc->repos_uuid,
>                                              inherited_props,
>                                              use_commit_times,
>                                              diff3_cmd, preserved_exts,
>                                              def_dir_abspath,
>                                              record_url,
>                                              record_peg_revision,
>                                              record_revision,
>                                              ctx->conflict_func2,
>                                              ctx->conflict_baton2,
>                                              ctx->cancel_func,
>                                              ctx->cancel_baton,
>                                              ctx->notify_func2,
>                                              ctx->notify_baton2,
>                                              scratch_pool, scratch_pool));
>     /* Tell RA to do an update of URL+TARGET to REVISION; if we pass an
>      invalid revnum, that means RA will use the latest revision. */
>     SVN_ERR(svn_ra_do_switch3(ra_session, &reporter, &report_baton,
>                               switch_loc->rev,
>                               target, svn_depth_unknown, switch_loc->url,
>                               FALSE /* send_copyfrom */,
>                               TRUE /* ignore_ancestry */,
>                               switch_editor, switch_baton,
>                               scratch_pool, scratch_pool));
>     SVN_ERR(svn_wc__crawl_file_external(ctx->wc_ctx, local_abspath,
>                                         reporter, report_baton,
>                                         TRUE,  use_commit_times,
>                                         ctx->cancel_func, ctx->cancel_baton,
>                                         ctx->notify_func2, ctx->notify_baton2,
>                                         scratch_pool));
>     if (ctx->notify_func2)
>       {
>         svn_wc_notify_t *notify
>           = svn_wc_create_notify(local_abspath, svn_wc_notify_update_completed,
>                                  scratch_pool);
>         notify->kind = svn_node_none;
>         notify->content_state = notify->prop_state
>           = svn_wc_notify_state_inapplicable;
>         notify->lock_state = svn_wc_notify_lock_state_inapplicable;
>         notify->revision = revnum;
>         ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
>       }
>   }
>   return SVN_NO_ERROR;
> }
> /* Wrappers around svn_wc__external_remove, obtaining and releasing a lock for
>    directory externals */
> static svn_error_t *
> remove_external2(svn_boolean_t *removed,
>                 svn_wc_context_t *wc_ctx,
>                 const char *wri_abspath,
>                 const char *local_abspath,
>                 svn_node_kind_t external_kind,
>                 svn_cancel_func_t cancel_func,
>                 void *cancel_baton,
>                 apr_pool_t *scratch_pool)
> {
>   SVN_ERR(svn_wc__external_remove(wc_ctx, wri_abspath,
>                                   local_abspath,
>                                   (external_kind == svn_node_none),
>                                   cancel_func, cancel_baton,
>                                   scratch_pool));
>   *removed = TRUE;
>   return SVN_NO_ERROR;
> }
> static svn_error_t *
> remove_external(svn_boolean_t *removed,
>                 svn_wc_context_t *wc_ctx,
>                 const char *wri_abspath,
>                 const char *local_abspath,
>                 svn_node_kind_t external_kind,
>                 svn_cancel_func_t cancel_func,
>                 void *cancel_baton,
>                 apr_pool_t *scratch_pool)
> {
>   *removed = FALSE;
>   switch (external_kind)
>     {
>       case svn_node_dir:
>         SVN_WC__CALL_WITH_WRITE_LOCK(
>             remove_external2(removed,
>                              wc_ctx, wri_abspath,
>                              local_abspath, external_kind,
>                              cancel_func, cancel_baton,
>                              scratch_pool),
>             wc_ctx, local_abspath, FALSE, scratch_pool);
>         break;
>       case svn_node_file:
>       default:
>         SVN_ERR(remove_external2(removed,
>                                  wc_ctx, wri_abspath,
>                                  local_abspath, external_kind,
>                                  cancel_func, cancel_baton,
>                                  scratch_pool));
>         break;
>     }
>   return SVN_NO_ERROR;
> }
> /* Called when an external that is in the EXTERNALS table is no longer
>    referenced from an svn:externals property */
> static svn_error_t *
> handle_external_item_removal(const svn_client_ctx_t *ctx,
>                              const char *defining_abspath,
>                              const char *local_abspath,
>                              apr_pool_t *scratch_pool)
> {
>   svn_error_t *err;
>   svn_node_kind_t external_kind;
>   svn_node_kind_t kind;
>   svn_boolean_t removed = FALSE;
>   /* local_abspath should be a wcroot or a file external */
>   SVN_ERR(svn_wc__read_external_info(&external_kind, NULL, NULL, NULL, NULL,
>                                      ctx->wc_ctx, defining_abspath,
>                                      local_abspath, FALSE,
>                                      scratch_pool, scratch_pool));
>   SVN_ERR(svn_wc_read_kind2(&kind, ctx->wc_ctx, local_abspath, TRUE, FALSE,
>                            scratch_pool));
>   if (external_kind != kind)
>     external_kind = svn_node_none; /* Only remove the registration */
>   err = remove_external(&removed,
>                         ctx->wc_ctx, defining_abspath, local_abspath,
>                         external_kind,
>                         ctx->cancel_func, ctx->cancel_baton,
>                         scratch_pool);
>   if (err && err->apr_err == SVN_ERR_WC_NOT_LOCKED && removed)
>     {
>       svn_error_clear(err);
>       err = NULL; /* We removed the working copy, so we can't release the
>                      lock that was stored inside */
>     }
>   if (ctx->notify_func2)
>     {
>       svn_wc_notify_t *notify =
>           svn_wc_create_notify(local_abspath,
>                                svn_wc_notify_update_external_removed,
>                                scratch_pool);
>       notify->kind = kind;
>       notify->err = err;
>       ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
>       if (err && err->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD)
>         {
>           notify = svn_wc_create_notify(local_abspath,
>                                       svn_wc_notify_left_local_modifications,
>                                       scratch_pool);
>           notify->kind = svn_node_dir;
>           notify->err = err;
>           ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
>         }
>     }
>   if (err && err->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD)
>     {
>       svn_error_clear(err);
>       err = NULL;
>     }
>   return svn_error_trace(err);
> }
> static svn_error_t *
> handle_external_item_change(svn_client_ctx_t *ctx,
>                             const char *repos_root_url,
>                             const char *parent_dir_abspath,
>                             const char *parent_dir_url,
>                             const char *local_abspath,
>                             const char *old_defining_abspath,
>                             const svn_wc_external_item2_t *new_item,
>                             svn_ra_session_t *ra_session,
>                             svn_boolean_t *timestamp_sleep,
>                             apr_pool_t *scratch_pool)
> {
>   svn_client__pathrev_t *new_loc;
>   const char *new_url;
>   svn_node_kind_t ext_kind;
>   SVN_ERR_ASSERT(repos_root_url && parent_dir_url);
>   SVN_ERR_ASSERT(new_item != NULL);
>   /* Don't bother to check status, since we'll get that for free by
>      attempting to retrieve the hash values anyway.  */
>   /* When creating the absolute URL, use the pool and not the
>      iterpool, since the hash table values outlive the iterpool and
>      any pointers they have should also outlive the iterpool.  */
>   SVN_ERR(svn_wc__resolve_relative_external_url(&new_url,
>                                                 new_item, repos_root_url,
>                                                 parent_dir_url,
>                                                 scratch_pool, scratch_pool));
>   /* Determine if the external is a file or directory. */
>   /* Get the RA connection, if needed. */
>   if (ra_session)
>     {
>       svn_error_t *err = svn_ra_reparent(ra_session, new_url, scratch_pool);
>       if (err)
>         {
>           if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
>             {
>               svn_error_clear(err);
>               ra_session = NULL;
>             }
>           else
>             return svn_error_trace(err);
>         }
>       else
>         {
>           SVN_ERR(svn_client__resolve_rev_and_url(&new_loc,
>                                                   ra_session, new_url,
>                                                   &(new_item->peg_revision),
>                                                   &(new_item->revision), ctx,
>                                                   scratch_pool));
>           SVN_ERR(svn_ra_reparent(ra_session, new_loc->url, scratch_pool));
>         }
>     }
>   if (!ra_session)
>     SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &new_loc,
>                                               new_url, NULL,
>                                               &(new_item->peg_revision),
>                                               &(new_item->revision), ctx,
>                                               scratch_pool));
>   SVN_ERR(svn_ra_check_path(ra_session, "", new_loc->rev, &ext_kind,
>                             scratch_pool));
>   if (svn_node_none == ext_kind)
>     return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
>                              _("URL '%s' at revision %ld doesn't exist"),
>                              new_loc->url, new_loc->rev);
>   if (svn_node_dir != ext_kind && svn_node_file != ext_kind)
>     return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
>                              _("URL '%s' at revision %ld is not a file "
>                                "or a directory"),
>                              new_loc->url, new_loc->rev);
>   /* Not protecting against recursive externals.  Detecting them in
>      the global case is hard, and it should be pretty obvious to a
>      user when it happens.  Worst case: your disk fills up :-). */
>   /* First notify that we're about to handle an external. */
>   if (ctx->notify_func2)
>     {
>       ctx->notify_func2(
>          ctx->notify_baton2,
>          svn_wc_create_notify(local_abspath,
>                               svn_wc_notify_update_external,
>                               scratch_pool),
>          scratch_pool);
>     }
>   if (! old_defining_abspath)
>     {
>       /* The target dir might have multiple components.  Guarantee the path
>          leading down to the last component. */
>       SVN_ERR(svn_io_make_dir_recursively(svn_dirent_dirname(local_abspath,
>                                                              scratch_pool),
>                                           scratch_pool));
>     }
>   switch (ext_kind)
>     {
>       case svn_node_dir:
>         SVN_ERR(switch_dir_external(local_abspath, new_loc->url,
>                                     new_item->url,
>                                     &(new_item->peg_revision),
>                                     &(new_item->revision),
>                                     parent_dir_abspath,
>                                     timestamp_sleep, ra_session, ctx,
>                                     scratch_pool));
>         break;
>       case svn_node_file:
>         if (strcmp(repos_root_url, new_loc->repos_root_url))
>           {
>             const char *local_repos_root_url;
>             const char *local_repos_uuid;
>             const char *ext_repos_relpath;
>             svn_error_t *err;
>             /*
>              * The working copy library currently requires that all files
>              * in the working copy have the same repository root URL.
>              * The URL from the file external's definition differs from the
>              * one used by the working copy. As a workaround, replace the
>              * root URL portion of the file external's URL, after making
>              * sure both URLs point to the same repository. See issue #4087.
>              */
>             err = svn_wc__node_get_repos_info(NULL, NULL,
>                                               &local_repos_root_url,
>                                               &local_repos_uuid,
>                                               ctx->wc_ctx, parent_dir_abspath,
>                                               scratch_pool, scratch_pool);
>             if (err)
>               {
>                 if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND
>                     && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
>                   return svn_error_trace(err);
>                 svn_error_clear(err);
>                 local_repos_root_url = NULL;
>                 local_repos_uuid = NULL;
>               }
>             ext_repos_relpath = svn_uri_skip_ancestor(new_loc->repos_root_url,
>                                                       new_url, scratch_pool);
>             if (local_repos_uuid == NULL || local_repos_root_url == NULL ||
>                 ext_repos_relpath == NULL ||
>                 strcmp(local_repos_uuid, new_loc->repos_uuid) != 0)
>               return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
>                         _("Unsupported external: URL of file external '%s' "
>                           "is not in repository '%s'"),
>                         new_url, repos_root_url);
>             new_url = svn_path_url_add_component2(local_repos_root_url,
>                                                   ext_repos_relpath,
>                                                   scratch_pool);
>             SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &new_loc,
>                                                       new_url,
>                                                       NULL,
>                                                       &(new_item->peg_revision),
>                                                       &(new_item->revision),
>                                                       ctx, scratch_pool));
>           }
>         SVN_ERR(switch_file_external(local_abspath,
>                                      new_loc,
>                                      new_url,
>                                      &new_item->peg_revision,
>                                      &new_item->revision,
>                                      parent_dir_abspath,
>                                      ra_session,
>                                      ctx,
>                                      scratch_pool));
>         break;
>       default:
>         SVN_ERR_MALFUNCTION();
>         break;
>     }
>   return SVN_NO_ERROR;
> }
> static svn_error_t *
> wrap_external_error(const svn_client_ctx_t *ctx,
>                     const char *target_abspath,
>                     svn_error_t *err,
>                     apr_pool_t *scratch_pool)
> {
>   if (err && err->apr_err != SVN_ERR_CANCELLED)
>     {
>       if (ctx->notify_func2)
>         {
>           svn_wc_notify_t *notifier = svn_wc_create_notify(
>                                             target_abspath,
>                                             svn_wc_notify_failed_external,
>                                             scratch_pool);
>           notifier->err = err;
>           ctx->notify_func2(ctx->notify_baton2, notifier, scratch_pool);
>         }
>       svn_error_clear(err);
>       return SVN_NO_ERROR;
>     }
>   return err;
> }
> static svn_error_t *
> handle_externals_change(svn_client_ctx_t *ctx,
>                         const char *repos_root_url,
>                         svn_boolean_t *timestamp_sleep,
>                         const char *local_abspath,
>                         const char *new_desc_text,
>                         apr_hash_t *old_externals,
>                         svn_depth_t ambient_depth,
>                         svn_depth_t requested_depth,
>                         svn_ra_session_t *ra_session,
>                         apr_pool_t *scratch_pool)
> {
>   apr_array_header_t *new_desc;
>   int i;
>   apr_pool_t *iterpool;
>   const char *url;
>   iterpool = svn_pool_create(scratch_pool);
>   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
>   /* Bag out if the depth here is too shallow for externals action. */
>   if ((requested_depth < svn_depth_infinity
>        && requested_depth != svn_depth_unknown)
>       || (ambient_depth < svn_depth_infinity
>           && requested_depth < svn_depth_infinity))
>     return SVN_NO_ERROR;
>   if (new_desc_text)
>     SVN_ERR(svn_wc_parse_externals_description3(&new_desc, local_abspath,
>                                                 new_desc_text,
>                                                 FALSE, scratch_pool));
>   else
>     new_desc = NULL;
>   SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, local_abspath,
>                                scratch_pool, iterpool));
>   SVN_ERR_ASSERT(url);
>   for (i = 0; new_desc && (i < new_desc->nelts); i++)
>     {
>       const char *old_defining_abspath;
>       svn_wc_external_item2_t *new_item;
>       const char *target_abspath;
>       svn_boolean_t under_root;
>       new_item = APR_ARRAY_IDX(new_desc, i, svn_wc_external_item2_t *);
>       svn_pool_clear(iterpool);
>       if (ctx->cancel_func)
>         SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
>       SVN_ERR(svn_dirent_is_under_root(&under_root, &target_abspath,
>                                        local_abspath, new_item->target_dir,
>                                        iterpool));
>       if (! under_root)
>         {
>           return svn_error_createf(
>                     SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
>                     _("Path '%s' is not in the working copy"),
>                     svn_dirent_local_style(
>                         svn_dirent_join(local_abspath, new_item->target_dir,
>                                         iterpool),
>                         iterpool));
>         }
>       old_defining_abspath = svn_hash_gets(old_externals, target_abspath);
>       SVN_ERR(wrap_external_error(
>                       ctx, target_abspath,
>                       handle_external_item_change(ctx,
>                                                   repos_root_url,
>                                                   local_abspath, url,
>                                                   target_abspath,
>                                                   old_defining_abspath,
>                                                   new_item, ra_session,
>                                                   timestamp_sleep,
>                                                   iterpool),
>                       iterpool));
>       /* And remove already processed items from the to-remove hash */
>       if (old_defining_abspath)
>         svn_hash_sets(old_externals, target_abspath, NULL);
>     }
>   svn_pool_destroy(iterpool);
>   return SVN_NO_ERROR;
> }
> svn_error_t *
> svn_client__handle_externals(apr_hash_t *externals_new,
>                              apr_hash_t *ambient_depths,
>                              const char *repos_root_url,
>                              const char *target_abspath,
>                              svn_depth_t requested_depth,
>                              svn_boolean_t *timestamp_sleep,
>                              svn_ra_session_t *ra_session,
>                              svn_client_ctx_t *ctx,
>                              apr_pool_t *scratch_pool)
> {
>   apr_hash_t *old_external_defs;
>   apr_hash_index_t *hi;
>   apr_pool_t *iterpool;
>   SVN_ERR_ASSERT(repos_root_url);
>   iterpool = svn_pool_create(scratch_pool);
>   SVN_ERR(svn_wc__externals_defined_below(&old_external_defs,
>                                           ctx->wc_ctx, target_abspath,
>                                           scratch_pool, iterpool));
>   for (hi = apr_hash_first(scratch_pool, externals_new);
>        hi;
>        hi = apr_hash_next(hi))
>     {
>       const char *local_abspath = apr_hash_this_key(hi);
>       const char *desc_text = apr_hash_this_val(hi);
>       svn_depth_t ambient_depth = svn_depth_infinity;
>       svn_pool_clear(iterpool);
>       if (ambient_depths)
>         {
>           const char *ambient_depth_w;
>           ambient_depth_w = apr_hash_get(ambient_depths, local_abspath,
>                                          apr_hash_this_key_len(hi));
>           if (ambient_depth_w == NULL)
>             {
>               return svn_error_createf(
>                         SVN_ERR_WC_CORRUPT, NULL,
>                         _("Traversal of '%s' found no ambient depth"),
>                         svn_dirent_local_style(local_abspath, scratch_pool));
>             }
>           else
>             {
>               ambient_depth = svn_depth_from_word(ambient_depth_w);
>             }
>         }
>       SVN_ERR(handle_externals_change(ctx, repos_root_url, timestamp_sleep,
>                                       local_abspath,
>                                       desc_text, old_external_defs,
>                                       ambient_depth, requested_depth,
>                                       ra_session, iterpool));
>     }
>   /* Remove the remaining externals */
>   for (hi = apr_hash_first(scratch_pool, old_external_defs);
>        hi;
>        hi = apr_hash_next(hi))
>     {
>       const char *item_abspath = apr_hash_this_key(hi);
>       const char *defining_abspath = apr_hash_this_val(hi);
>       const char *parent_abspath;
>       svn_pool_clear(iterpool);
>       SVN_ERR(wrap_external_error(
>                           ctx, item_abspath,
>                           handle_external_item_removal(ctx, defining_abspath,
>                                                        item_abspath, iterpool),
>                           iterpool));
>       /* Are there any unversioned directories between the removed
>        * external and the DEFINING_ABSPATH which we can remove? */
>       parent_abspath = item_abspath;
>       do {
>         svn_node_kind_t kind;
>         parent_abspath = svn_dirent_dirname(parent_abspath, iterpool);
>         SVN_ERR(svn_wc_read_kind2(&kind, ctx->wc_ctx, parent_abspath,
>                                   FALSE /* show_deleted*/,
>                                   FALSE /* show_hidden */,
>                                   iterpool));
>         if (kind == svn_node_none)
>           {
>             svn_error_t *err;
>             err = svn_io_dir_remove_nonrecursive(parent_abspath, iterpool);
>             if (err)
>               {
>                 if (APR_STATUS_IS_ENOTEMPTY(err->apr_err))
>                   {
>                     svn_error_clear(err);
>                     break; /* No parents to delete */
>                   }
>                 else if (APR_STATUS_IS_ENOENT(err->apr_err)
>                          || APR_STATUS_IS_ENOTDIR(err->apr_err))
>                   {
>                     svn_error_clear(err);
>                     /* Fall through; parent dir might be unversioned */
>                   }
>                 else
>                   return svn_error_trace(err);
>               }
>           }
>       } while (strcmp(parent_abspath, defining_abspath) != 0);
>     }
>   svn_pool_destroy(iterpool);
>   return SVN_NO_ERROR;
> }
> svn_error_t *
> svn_client__export_externals(apr_hash_t *externals,
>                              const char *from_url,
>                              const char *to_abspath,
>                              const char *repos_root_url,
>                              svn_depth_t requested_depth,
>                              const char *native_eol,
>                              svn_boolean_t ignore_keywords,
>                              svn_client_ctx_t *ctx,
>                              apr_pool_t *scratch_pool)
> {
>   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
>   apr_pool_t *sub_iterpool = svn_pool_create(scratch_pool);
>   apr_hash_index_t *hi;
>   SVN_ERR_ASSERT(svn_dirent_is_absolute(to_abspath));
>   for (hi = apr_hash_first(scratch_pool, externals);
>        hi;
>        hi = apr_hash_next(hi))
>     {
>       const char *local_abspath = apr_hash_this_key(hi);
>       const char *desc_text = apr_hash_this_val(hi);
>       const char *local_relpath;
>       const char *dir_url;
>       apr_array_header_t *items;
>       int i;
>       svn_pool_clear(iterpool);
>       SVN_ERR(svn_wc_parse_externals_description3(&items, local_abspath,
>                                                   desc_text, FALSE,
>                                                   iterpool));
>       if (! items->nelts)
>         continue;
>       local_relpath = svn_dirent_skip_ancestor(to_abspath, local_abspath);
>       dir_url = svn_path_url_add_component2(from_url, local_relpath,
>                                             scratch_pool);
>       for (i = 0; i < items->nelts; i++)
>         {
>           const char *item_abspath;
>           const char *new_url;
>           svn_boolean_t under_root;
>           svn_wc_external_item2_t *item = APR_ARRAY_IDX(items, i,
>                                                 svn_wc_external_item2_t *);
>           svn_pool_clear(sub_iterpool);
>           SVN_ERR(svn_dirent_is_under_root(&under_root, &item_abspath,
>                                            local_abspath, item->target_dir,
>                                            sub_iterpool));
>           if (! under_root)
>             {
>               return svn_error_createf(
>                         SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
>                         _("Path '%s' is not in the working copy"),
>                         svn_dirent_local_style(
>                             svn_dirent_join(local_abspath, item->target_dir,
>                                             sub_iterpool),
>                             sub_iterpool));
>             }
>           SVN_ERR(svn_wc__resolve_relative_external_url(&new_url, item,
>                                                         repos_root_url,
>                                                         dir_url, sub_iterpool,
>                                                         sub_iterpool));
>           /* The target dir might have multiple components.  Guarantee
>              the path leading down to the last component. */
>           SVN_ERR(svn_io_make_dir_recursively(svn_dirent_dirname(item_abspath,
>                                                                  sub_iterpool),
>                                               sub_iterpool));
>           /* First notify that we're about to handle an external. */
>           if (ctx->notify_func2)
>             {
>               ctx->notify_func2(
>                        ctx->notify_baton2,
>                        svn_wc_create_notify(item_abspath,
>                                             svn_wc_notify_update_external,
>                                             sub_iterpool),
>                        sub_iterpool);
>             }
>           SVN_ERR(wrap_external_error(
>                           ctx, item_abspath,
>                           svn_client_export5(NULL, new_url, item_abspath,
>                                              &item->peg_revision,
>                                              &item->revision,
>                                              TRUE, FALSE, ignore_keywords,
>                                              svn_depth_infinity,
>                                              native_eol,
>                                              ctx, sub_iterpool),
>                           sub_iterpool));
>         }
>     }
>   svn_pool_destroy(sub_iterpool);
>   svn_pool_destroy(iterpool);
>   return SVN_NO_ERROR;
> }
> {code}



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)