/*
 * deprecated.c:  holding file for all deprecated APIs.
 *                "we can't lose 'em, but we can shun 'em!"
 *
 * ====================================================================
 *    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.
 * ====================================================================
 */

/* We define this here to remove any further warnings about the usage of
   deprecated functions in this file. */
#define SVN_DEPRECATED

#include <apr_md5.h>

#include "svn_wc.h"
#include "svn_subst.h"
#include "svn_pools.h"
#include "svn_props.h"
#include "svn_time.h"
#include "svn_dirent_uri.h"
#include "svn_path.h"

#include "private/svn_wc_private.h"

#include "wc.h"
#include "entries.h"
#include "lock.h"
#include "props.h"
#include "translate.h"
#include "workqueue.h"

#include "svn_private_config.h"

/* baton for traversal_info_update */
struct traversal_info_update_baton
{
  struct svn_wc_traversal_info_t *traversal;
  svn_wc__db_t *db;
};

/* Helper for updating svn_wc_traversal_info_t structures
 * Implements svn_wc_external_update_t */
static svn_error_t *
traversal_info_update(void *baton,
                      const char *local_abspath,
                      const svn_string_t *old_val,
                      const svn_string_t *new_val,
                      svn_depth_t depth,
                      apr_pool_t *scratch_pool)
{
  const char *dup_path;
  svn_wc_adm_access_t *adm_access;
  struct traversal_info_update_baton *ub = baton;
  apr_pool_t *dup_pool = ub->traversal->pool;
  const char *dup_val = NULL;

  /* We make the abspath relative by retrieving the access baton
     for the specific directory */
  adm_access = svn_wc__adm_retrieve_internal2(ub->db, local_abspath,
                                              scratch_pool);

  if (adm_access)
    dup_path = apr_pstrdup(dup_pool, svn_wc_adm_access_path(adm_access));
  else
    dup_path = apr_pstrdup(dup_pool, local_abspath);

  if (old_val)
    {
      dup_val = apr_pstrmemdup(dup_pool, old_val->data, old_val->len);

      apr_hash_set(ub->traversal->externals_old, dup_path, APR_HASH_KEY_STRING,
                   dup_val);
    }

  if (new_val)
    {
      /* In most cases the value is identical */
      if (old_val != new_val)
        dup_val = apr_pstrmemdup(dup_pool, new_val->data, new_val->len);

      apr_hash_set(ub->traversal->externals_new, dup_path, APR_HASH_KEY_STRING,
                   dup_val);
    }

  apr_hash_set(ub->traversal->depths, dup_path, APR_HASH_KEY_STRING,
               svn_depth_to_word(depth));

  return SVN_NO_ERROR;
}

/* Helper for functions that used to gather traversal_info */
static svn_error_t *
gather_traversal_info(svn_wc_context_t *wc_ctx,
                      const char *local_abspath,
                      const char *path,
                      svn_depth_t depth,
                      struct svn_wc_traversal_info_t *traversal_info,
                      svn_boolean_t gather_as_old,
                      svn_boolean_t gather_as_new,
                      apr_pool_t *scratch_pool)
{
  apr_hash_t *externals;
  apr_hash_t *ambient_depths;
  apr_hash_index_t *hi;

  SVN_ERR(svn_wc__externals_gather_definitions(&externals, &ambient_depths,
                                               wc_ctx, local_abspath,
                                               depth,
                                               scratch_pool, scratch_pool));

  for (hi = apr_hash_first(scratch_pool, externals);
       hi;
       hi = apr_hash_next(hi))
    {
      const char *node_abspath = svn__apr_hash_index_key(hi);
      const char *relpath;

      relpath = svn_dirent_join(path,
                                svn_dirent_skip_ancestor(local_abspath,
                                                         node_abspath),
                                traversal_info->pool);

      if (gather_as_old)
        apr_hash_set(traversal_info->externals_old,
                     relpath, APR_HASH_KEY_STRING,
                     svn__apr_hash_index_val(hi));

      if (gather_as_new)
        apr_hash_set(traversal_info->externals_new,
                     relpath, APR_HASH_KEY_STRING,
                     svn__apr_hash_index_val(hi));

      apr_hash_set(traversal_info->depths,
                   relpath, APR_HASH_KEY_STRING,
                   apr_hash_get(ambient_depths, node_abspath,
                                APR_HASH_KEY_STRING));
    }

  return SVN_NO_ERROR;
}


/*** From adm_crawler.c ***/

svn_error_t *
svn_wc_crawl_revisions4(const char *path,
                        svn_wc_adm_access_t *adm_access,
                        const svn_ra_reporter3_t *reporter,
                        void *report_baton,
                        svn_boolean_t restore_files,
                        svn_depth_t depth,
                        svn_boolean_t honor_depth_exclude,
                        svn_boolean_t depth_compatibility_trick,
                        svn_boolean_t use_commit_times,
                        svn_wc_notify_func2_t notify_func,
                        void *notify_baton,
                        svn_wc_traversal_info_t *traversal_info,
                        apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *wc_db = svn_wc__adm_get_db(adm_access);
  const char *local_abspath;

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, wc_db, pool));
  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));

  SVN_ERR(svn_wc_crawl_revisions5(wc_ctx,
                                  local_abspath,
                                  reporter,
                                  report_baton,
                                  restore_files,
                                  depth,
                                  honor_depth_exclude,
                                  depth_compatibility_trick,
                                  use_commit_times,
                                  NULL /* cancel_func */,
                                  NULL /* cancel_baton */,
                                  notify_func,
                                  notify_baton,
                                  pool));

  if (traversal_info)
    SVN_ERR(gather_traversal_info(wc_ctx, local_abspath, path, depth,
                                  traversal_info, TRUE, FALSE, pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

/*** Compatibility wrapper: turns an svn_ra_reporter2_t into an
     svn_ra_reporter3_t.

     This code looks like it duplicates code in libsvn_ra/ra_loader.c,
     but it does not.  That code makes an new thing look like an old
     thing; this code makes an old thing look like a new thing. ***/

struct wrap_3to2_report_baton {
  const svn_ra_reporter2_t *reporter;
  void *baton;
};

/* */
static svn_error_t *wrap_3to2_set_path(void *report_baton,
                                       const char *path,
                                       svn_revnum_t revision,
                                       svn_depth_t depth,
                                       svn_boolean_t start_empty,
                                       const char *lock_token,
                                       apr_pool_t *pool)
{
  struct wrap_3to2_report_baton *wrb = report_baton;

  return wrb->reporter->set_path(wrb->baton, path, revision, start_empty,
                                 lock_token, pool);
}

/* */
static svn_error_t *wrap_3to2_delete_path(void *report_baton,
                                          const char *path,
                                          apr_pool_t *pool)
{
  struct wrap_3to2_report_baton *wrb = report_baton;

  return wrb->reporter->delete_path(wrb->baton, path, pool);
}

/* */
static svn_error_t *wrap_3to2_link_path(void *report_baton,
                                        const char *path,
                                        const char *url,
                                        svn_revnum_t revision,
                                        svn_depth_t depth,
                                        svn_boolean_t start_empty,
                                        const char *lock_token,
                                        apr_pool_t *pool)
{
  struct wrap_3to2_report_baton *wrb = report_baton;

  return wrb->reporter->link_path(wrb->baton, path, url, revision,
                                  start_empty, lock_token, pool);
}

/* */
static svn_error_t *wrap_3to2_finish_report(void *report_baton,
                                            apr_pool_t *pool)
{
  struct wrap_3to2_report_baton *wrb = report_baton;

  return wrb->reporter->finish_report(wrb->baton, pool);
}

/* */
static svn_error_t *wrap_3to2_abort_report(void *report_baton,
                                           apr_pool_t *pool)
{
  struct wrap_3to2_report_baton *wrb = report_baton;

  return wrb->reporter->abort_report(wrb->baton, pool);
}

static const svn_ra_reporter3_t wrap_3to2_reporter = {
  wrap_3to2_set_path,
  wrap_3to2_delete_path,
  wrap_3to2_link_path,
  wrap_3to2_finish_report,
  wrap_3to2_abort_report
};

svn_error_t *
svn_wc_crawl_revisions3(const char *path,
                        svn_wc_adm_access_t *adm_access,
                        const svn_ra_reporter3_t *reporter,
                        void *report_baton,
                        svn_boolean_t restore_files,
                        svn_depth_t depth,
                        svn_boolean_t depth_compatibility_trick,
                        svn_boolean_t use_commit_times,
                        svn_wc_notify_func2_t notify_func,
                        void *notify_baton,
                        svn_wc_traversal_info_t *traversal_info,
                        apr_pool_t *pool)
{
  return svn_wc_crawl_revisions4(path,
                                 adm_access,
                                 reporter, report_baton,
                                 restore_files,
                                 depth,
                                 FALSE,
                                 depth_compatibility_trick,
                                 use_commit_times,
                                 notify_func,
                                 notify_baton,
                                 traversal_info,
                                 pool);
}

svn_error_t *
svn_wc_crawl_revisions2(const char *path,
                        svn_wc_adm_access_t *adm_access,
                        const svn_ra_reporter2_t *reporter,
                        void *report_baton,
                        svn_boolean_t restore_files,
                        svn_boolean_t recurse,
                        svn_boolean_t use_commit_times,
                        svn_wc_notify_func2_t notify_func,
                        void *notify_baton,
                        svn_wc_traversal_info_t *traversal_info,
                        apr_pool_t *pool)
{
  struct wrap_3to2_report_baton wrb;
  wrb.reporter = reporter;
  wrb.baton = report_baton;

  return svn_wc_crawl_revisions3(path,
                                 adm_access,
                                 &wrap_3to2_reporter, &wrb,
                                 restore_files,
                                 SVN_DEPTH_INFINITY_OR_FILES(recurse),
                                 FALSE,
                                 use_commit_times,
                                 notify_func,
                                 notify_baton,
                                 traversal_info,
                                 pool);
}


/* Baton for compat_call_notify_func below.  */
struct compat_notify_baton_t {
  /* Wrapped func/baton. */
  svn_wc_notify_func_t func;
  void *baton;
};


/* Implements svn_wc_notify_func2_t.  Call BATON->func (BATON is of type
   svn_wc__compat_notify_baton_t), passing BATON->baton and the appropriate
   arguments from NOTIFY.  */
static void
compat_call_notify_func(void *baton,
                        const svn_wc_notify_t *n,
                        apr_pool_t *pool)
{
  struct compat_notify_baton_t *nb = baton;

  if (nb->func)
    (*nb->func)(nb->baton, n->path, n->action, n->kind, n->mime_type,
                n->content_state, n->prop_state, n->revision);
}


/*** Compatibility wrapper: turns an svn_ra_reporter_t into an
     svn_ra_reporter2_t.

     This code looks like it duplicates code in libsvn_ra/ra_loader.c,
     but it does not.  That code makes an new thing look like an old
     thing; this code makes an old thing look like a new thing. ***/

struct wrap_2to1_report_baton {
  const svn_ra_reporter_t *reporter;
  void *baton;
};

/* */
static svn_error_t *wrap_2to1_set_path(void *report_baton,
                                       const char *path,
                                       svn_revnum_t revision,
                                       svn_boolean_t start_empty,
                                       const char *lock_token,
                                       apr_pool_t *pool)
{
  struct wrap_2to1_report_baton *wrb = report_baton;

  return wrb->reporter->set_path(wrb->baton, path, revision, start_empty,
                                 pool);
}

/* */
static svn_error_t *wrap_2to1_delete_path(void *report_baton,
                                          const char *path,
                                          apr_pool_t *pool)
{
  struct wrap_2to1_report_baton *wrb = report_baton;

  return wrb->reporter->delete_path(wrb->baton, path, pool);
}

/* */
static svn_error_t *wrap_2to1_link_path(void *report_baton,
                                        const char *path,
                                        const char *url,
                                        svn_revnum_t revision,
                                        svn_boolean_t start_empty,
                                        const char *lock_token,
                                        apr_pool_t *pool)
{
  struct wrap_2to1_report_baton *wrb = report_baton;

  return wrb->reporter->link_path(wrb->baton, path, url, revision,
                                  start_empty, pool);
}

/* */
static svn_error_t *wrap_2to1_finish_report(void *report_baton,
                                            apr_pool_t *pool)
{
  struct wrap_2to1_report_baton *wrb = report_baton;

  return wrb->reporter->finish_report(wrb->baton, pool);
}

/* */
static svn_error_t *wrap_2to1_abort_report(void *report_baton,
                                           apr_pool_t *pool)
{
  struct wrap_2to1_report_baton *wrb = report_baton;

  return wrb->reporter->abort_report(wrb->baton, pool);
}

static const svn_ra_reporter2_t wrap_2to1_reporter = {
  wrap_2to1_set_path,
  wrap_2to1_delete_path,
  wrap_2to1_link_path,
  wrap_2to1_finish_report,
  wrap_2to1_abort_report
};

svn_error_t *
svn_wc_crawl_revisions(const char *path,
                       svn_wc_adm_access_t *adm_access,
                       const svn_ra_reporter_t *reporter,
                       void *report_baton,
                       svn_boolean_t restore_files,
                       svn_boolean_t recurse,
                       svn_boolean_t use_commit_times,
                       svn_wc_notify_func_t notify_func,
                       void *notify_baton,
                       svn_wc_traversal_info_t *traversal_info,
                       apr_pool_t *pool)
{
  struct wrap_2to1_report_baton wrb;
  struct compat_notify_baton_t nb;

  wrb.reporter = reporter;
  wrb.baton = report_baton;

  nb.func = notify_func;
  nb.baton = notify_baton;

  return svn_wc_crawl_revisions2(path, adm_access, &wrap_2to1_reporter, &wrb,
                                 restore_files, recurse, use_commit_times,
                                 compat_call_notify_func, &nb,
                                 traversal_info,
                                 pool);
}

svn_error_t *
svn_wc_transmit_text_deltas2(const char **tempfile,
                             unsigned char digest[],
                             const char *path,
                             svn_wc_adm_access_t *adm_access,
                             svn_boolean_t fulltext,
                             const svn_delta_editor_t *editor,
                             void *file_baton,
                             apr_pool_t *pool)
{
  const char *local_abspath;
  svn_wc_context_t *wc_ctx;
  const svn_checksum_t *new_text_base_md5_checksum;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access),
                                         pool));

  SVN_ERR(svn_wc__internal_transmit_text_deltas(tempfile,
                                                (digest
                                                 ? &new_text_base_md5_checksum
                                                 : NULL),
                                                NULL, wc_ctx->db,
                                                local_abspath, fulltext,
                                                editor, file_baton,
                                                pool, pool));

  if (digest)
    memcpy(digest, new_text_base_md5_checksum->digest, APR_MD5_DIGESTSIZE);

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_transmit_text_deltas(const char *path,
                            svn_wc_adm_access_t *adm_access,
                            svn_boolean_t fulltext,
                            const svn_delta_editor_t *editor,
                            void *file_baton,
                            const char **tempfile,
                            apr_pool_t *pool)
{
  return svn_wc_transmit_text_deltas2(tempfile, NULL, path, adm_access,
                                      fulltext, editor, file_baton, pool);
}

svn_error_t *
svn_wc_transmit_prop_deltas(const char *path,
                            svn_wc_adm_access_t *adm_access,
                            const svn_wc_entry_t *entry,
                            const svn_delta_editor_t *editor,
                            void *baton,
                            const char **tempfile,
                            apr_pool_t *pool)
{
  const char *local_abspath;
  svn_wc_context_t *wc_ctx;

  if (tempfile)
    *tempfile = NULL;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access),
                                         pool));

  SVN_ERR(svn_wc_transmit_prop_deltas2(wc_ctx, local_abspath, editor, baton,
                                       pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

/*** From adm_files.c ***/
svn_error_t *
svn_wc_ensure_adm3(const char *path,
                   const char *uuid,
                   const char *url,
                   const char *repos,
                   svn_revnum_t revision,
                   svn_depth_t depth,
                   apr_pool_t *pool)
{
  const char *local_abspath;
  svn_wc_context_t *wc_ctx;

  if (uuid == NULL)
    return svn_error_create(SVN_ERR_BAD_UUID, NULL, NULL);
  if (repos == NULL)
    return svn_error_create(SVN_ERR_BAD_URL, NULL, NULL);

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc_context_create(&wc_ctx, NULL /* config */, pool, pool));

  SVN_ERR(svn_wc_ensure_adm4(wc_ctx, local_abspath, url, repos, uuid, revision,
                             depth, pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_ensure_adm2(const char *path,
                   const char *uuid,
                   const char *url,
                   const char *repos,
                   svn_revnum_t revision,
                   apr_pool_t *pool)
{
  return svn_wc_ensure_adm3(path, uuid, url, repos, revision,
                            svn_depth_infinity, pool);
}


svn_error_t *
svn_wc_ensure_adm(const char *path,
                  const char *uuid,
                  const char *url,
                  svn_revnum_t revision,
                  apr_pool_t *pool)
{
  return svn_wc_ensure_adm2(path, uuid, url, NULL, revision, pool);
}

svn_error_t *
svn_wc_create_tmp_file(apr_file_t **fp,
                       const char *path,
                       svn_boolean_t delete_on_close,
                       apr_pool_t *pool)
{
  return svn_wc_create_tmp_file2(fp, NULL, path,
                                 delete_on_close
                                 ? svn_io_file_del_on_close
                                 : svn_io_file_del_none,
                                 pool);
}


/*** From adm_ops.c ***/
svn_error_t *
svn_wc_get_pristine_contents(svn_stream_t **contents,
                             const char *path,
                             apr_pool_t *result_pool,
                             apr_pool_t *scratch_pool)
{
  svn_wc_context_t *wc_ctx;
  const char *local_abspath;

  SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, scratch_pool, scratch_pool));
  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));

  SVN_ERR(svn_wc_get_pristine_contents2(contents,
                                        wc_ctx,
                                        local_abspath,
                                        result_pool,
                                        scratch_pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}


svn_error_t *
svn_wc_queue_committed2(svn_wc_committed_queue_t *queue,
                        const char *path,
                        svn_wc_adm_access_t *adm_access,
                        svn_boolean_t recurse,
                        const apr_array_header_t *wcprop_changes,
                        svn_boolean_t remove_lock,
                        svn_boolean_t remove_changelist,
                        const svn_checksum_t *md5_checksum,
                        apr_pool_t *scratch_pool)
{
  svn_wc_context_t *wc_ctx;
  const char *local_abspath;
  const svn_checksum_t *sha1_checksum = NULL;

  SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, scratch_pool, scratch_pool));
  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));

  if (md5_checksum != NULL)
    {
      svn_error_t *err;
      err = svn_wc__db_pristine_get_sha1(&sha1_checksum, wc_ctx->db,
                                         local_abspath, md5_checksum,
                                         svn_wc__get_committed_queue_pool(queue),
                                         scratch_pool);

      /* Don't fail on SHA1 not found */
      if (err && err->apr_err == SVN_ERR_WC_DB_ERROR)
        {
          svn_error_clear(err);
          sha1_checksum = NULL;
        }
      else
        SVN_ERR(err);
    }

  SVN_ERR(svn_wc_queue_committed3(queue, wc_ctx, local_abspath, recurse,
                                  wcprop_changes,
                                  remove_lock, remove_changelist,
                                  sha1_checksum, scratch_pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_queue_committed(svn_wc_committed_queue_t **queue,
                       const char *path,
                       svn_wc_adm_access_t *adm_access,
                       svn_boolean_t recurse,
                       const apr_array_header_t *wcprop_changes,
                       svn_boolean_t remove_lock,
                       svn_boolean_t remove_changelist,
                       const unsigned char *digest,
                       apr_pool_t *pool)
{
  const svn_checksum_t *md5_checksum;

  if (digest)
    md5_checksum = svn_checksum__from_digest(
                   digest, svn_checksum_md5,
                   svn_wc__get_committed_queue_pool(*queue));
  else
    md5_checksum = NULL;

  return svn_wc_queue_committed2(*queue, path, adm_access, recurse,
                                 wcprop_changes, remove_lock,
                                 remove_changelist, md5_checksum, pool);
}

svn_error_t *
svn_wc_process_committed_queue(svn_wc_committed_queue_t *queue,
                               svn_wc_adm_access_t *adm_access,
                               svn_revnum_t new_revnum,
                               const char *rev_date,
                               const char *rev_author,
                               apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL,
                                         svn_wc__adm_get_db(adm_access),
                                         pool));
  SVN_ERR(svn_wc_process_committed_queue2(queue, wc_ctx, new_revnum,
                                          rev_date, rev_author,
                                          NULL, NULL, pool));
  SVN_ERR(svn_wc_context_destroy(wc_ctx));

  return SVN_NO_ERROR;
}

svn_error_t *
svn_wc_process_committed4(const char *path,
                          svn_wc_adm_access_t *adm_access,
                          svn_boolean_t recurse,
                          svn_revnum_t new_revnum,
                          const char *rev_date,
                          const char *rev_author,
                          const apr_array_header_t *wcprop_changes,
                          svn_boolean_t remove_lock,
                          svn_boolean_t remove_changelist,
                          const unsigned char *digest,
                          apr_pool_t *pool)
{
  svn_wc__db_t *db = svn_wc__adm_get_db(adm_access);
  const char *local_abspath;
  const svn_checksum_t *md5_checksum;
  const svn_checksum_t *sha1_checksum = NULL;
  apr_time_t new_date;
  apr_hash_t *wcprop_changes_hash;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));

  if (rev_date)
    SVN_ERR(svn_time_from_cstring(&new_date, rev_date, pool));
  else
    new_date = 0;

  if (digest)
    md5_checksum = svn_checksum__from_digest(digest, svn_checksum_md5, pool);
  else
    md5_checksum = NULL;

  if (md5_checksum != NULL)
    {
      svn_error_t *err;
      err = svn_wc__db_pristine_get_sha1(&sha1_checksum, db,
                                         local_abspath, md5_checksum,
                                         pool, pool);

      if (err && err->apr_err == SVN_ERR_WC_DB_ERROR)
        {
          svn_error_clear(err);
          sha1_checksum = NULL;
        }
      else
        SVN_ERR(err);
    }

  wcprop_changes_hash = svn_wc__prop_array_to_hash(wcprop_changes, pool);
  SVN_ERR(svn_wc__process_committed_internal(db, local_abspath, recurse, TRUE,
                                             new_revnum, new_date, rev_author,
                                             wcprop_changes_hash,
                                             !remove_lock, !remove_changelist,
                                             sha1_checksum, NULL, pool));

  /* Run the log file(s) we just created. */
  return svn_error_trace(svn_wc__wq_run(db, local_abspath, NULL, NULL, pool));
}


svn_error_t *
svn_wc_process_committed3(const char *path,
                          svn_wc_adm_access_t *adm_access,
                          svn_boolean_t recurse,
                          svn_revnum_t new_revnum,
                          const char *rev_date,
                          const char *rev_author,
                          const apr_array_header_t *wcprop_changes,
                          svn_boolean_t remove_lock,
                          const unsigned char *digest,
                          apr_pool_t *pool)
{
  return svn_wc_process_committed4(path, adm_access, recurse, new_revnum,
                                   rev_date, rev_author, wcprop_changes,
                                   remove_lock, FALSE, digest, pool);
}

svn_error_t *
svn_wc_process_committed2(const char *path,
                          svn_wc_adm_access_t *adm_access,
                          svn_boolean_t recurse,
                          svn_revnum_t new_revnum,
                          const char *rev_date,
                          const char *rev_author,
                          const apr_array_header_t *wcprop_changes,
                          svn_boolean_t remove_lock,
                          apr_pool_t *pool)
{
  return svn_wc_process_committed3(path, adm_access, recurse, new_revnum,
                                   rev_date, rev_author, wcprop_changes,
                                   remove_lock, NULL, pool);
}

svn_error_t *
svn_wc_process_committed(const char *path,
                         svn_wc_adm_access_t *adm_access,
                         svn_boolean_t recurse,
                         svn_revnum_t new_revnum,
                         const char *rev_date,
                         const char *rev_author,
                         const apr_array_header_t *wcprop_changes,
                         apr_pool_t *pool)
{
  return svn_wc_process_committed2(path, adm_access, recurse, new_revnum,
                                   rev_date, rev_author, wcprop_changes,
                                   FALSE, pool);
}

svn_error_t *
svn_wc_maybe_set_repos_root(svn_wc_adm_access_t *adm_access,
                            const char *path,
                            const char *repos,
                            apr_pool_t *pool)
{
  return SVN_NO_ERROR;
}

svn_error_t *
svn_wc_delete3(const char *path,
               svn_wc_adm_access_t *adm_access,
               svn_cancel_func_t cancel_func,
               void *cancel_baton,
               svn_wc_notify_func2_t notify_func,
               void *notify_baton,
               svn_boolean_t keep_local,
               apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *wc_db = svn_wc__adm_get_db(adm_access);
  svn_wc_adm_access_t *dir_access;
  const char *local_abspath;

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, wc_db, pool));
  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));

  /* Open access batons for everything below path, because we used to open
     these before. */
  SVN_ERR(svn_wc_adm_probe_try3(&dir_access, adm_access, path,
                                TRUE, -1, cancel_func, cancel_baton, pool));

  SVN_ERR(svn_wc_delete4(wc_ctx,
                         local_abspath,
                         keep_local,
                         TRUE,
                         cancel_func, cancel_baton,
                         notify_func, notify_baton,
                         pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_delete2(const char *path,
               svn_wc_adm_access_t *adm_access,
               svn_cancel_func_t cancel_func,
               void *cancel_baton,
               svn_wc_notify_func2_t notify_func,
               void *notify_baton,
               apr_pool_t *pool)
{
  return svn_wc_delete3(path, adm_access, cancel_func, cancel_baton,
                        notify_func, notify_baton, FALSE, pool);
}

svn_error_t *
svn_wc_delete(const char *path,
              svn_wc_adm_access_t *adm_access,
              svn_cancel_func_t cancel_func,
              void *cancel_baton,
              svn_wc_notify_func_t notify_func,
              void *notify_baton,
              apr_pool_t *pool)
{
  struct compat_notify_baton_t nb;

  nb.func = notify_func;
  nb.baton = notify_baton;

  return svn_wc_delete2(path, adm_access, cancel_func, cancel_baton,
                        compat_call_notify_func, &nb, pool);
}

svn_error_t *
svn_wc_add3(const char *path,
            svn_wc_adm_access_t *parent_access,
            svn_depth_t depth,
            const char *copyfrom_url,
            svn_revnum_t copyfrom_rev,
            svn_cancel_func_t cancel_func,
            void *cancel_baton,
            svn_wc_notify_func2_t notify_func,
            void *notify_baton,
            apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *wc_db = svn_wc__adm_get_db(parent_access);
  const char *local_abspath;

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, wc_db, pool));
  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));

  SVN_ERR(svn_wc_add4(wc_ctx, local_abspath,
                      depth, copyfrom_url,
                      copyfrom_rev,
                      cancel_func, cancel_baton,
                      notify_func, notify_baton, pool));

  /* Make sure the caller gets the new access baton in the set. */
  if (svn_wc__adm_retrieve_internal2(wc_db, local_abspath, pool) == NULL)
    {
      svn_wc__db_kind_t kind;

      SVN_ERR(svn_wc__db_read_kind(&kind, wc_db, local_abspath, FALSE, pool));
      if (kind == svn_wc__db_kind_dir)
        {
          svn_wc_adm_access_t *adm_access;

          /* Open the access baton in adm_access' pool to give it the same
             lifetime */
          SVN_ERR(svn_wc_adm_open3(&adm_access, parent_access, path, TRUE,
                                   copyfrom_url ? -1 : 0,
                                   cancel_func, cancel_baton,
                                   svn_wc_adm_access_pool(parent_access)));
        }
    }

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}


svn_error_t *
svn_wc_add2(const char *path,
            svn_wc_adm_access_t *parent_access,
            const char *copyfrom_url,
            svn_revnum_t copyfrom_rev,
            svn_cancel_func_t cancel_func,
            void *cancel_baton,
            svn_wc_notify_func2_t notify_func,
            void *notify_baton,
            apr_pool_t *pool)
{
  return svn_wc_add3(path, parent_access, svn_depth_infinity,
                     copyfrom_url, copyfrom_rev,
                     cancel_func, cancel_baton,
                     notify_func, notify_baton, pool);
}

svn_error_t *
svn_wc_add(const char *path,
           svn_wc_adm_access_t *parent_access,
           const char *copyfrom_url,
           svn_revnum_t copyfrom_rev,
           svn_cancel_func_t cancel_func,
           void *cancel_baton,
           svn_wc_notify_func_t notify_func,
           void *notify_baton,
           apr_pool_t *pool)
{
  struct compat_notify_baton_t nb;

  nb.func = notify_func;
  nb.baton = notify_baton;

  return svn_wc_add2(path, parent_access, copyfrom_url, copyfrom_rev,
                     cancel_func, cancel_baton,
                     compat_call_notify_func, &nb, pool);
}

svn_error_t *
svn_wc_revert3(const char *path,
               svn_wc_adm_access_t *parent_access,
               svn_depth_t depth,
               svn_boolean_t use_commit_times,
               const apr_array_header_t *changelist_filter,
               svn_cancel_func_t cancel_func,
               void *cancel_baton,
               svn_wc_notify_func2_t notify_func,
               void *notify_baton,
               apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *wc_db = svn_wc__adm_get_db(parent_access);
  const char *local_abspath;

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, wc_db, pool));
  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));

  SVN_ERR(svn_wc_revert4(wc_ctx,
                         local_abspath,
                         depth,
                         use_commit_times,
                         changelist_filter,
                         cancel_func, cancel_baton,
                         notify_func, notify_baton,
                         pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_revert2(const char *path,
               svn_wc_adm_access_t *parent_access,
               svn_boolean_t recursive,
               svn_boolean_t use_commit_times,
               svn_cancel_func_t cancel_func,
               void *cancel_baton,
               svn_wc_notify_func2_t notify_func,
               void *notify_baton,
               apr_pool_t *pool)
{
  return svn_wc_revert3(path, parent_access,
                        SVN_DEPTH_INFINITY_OR_EMPTY(recursive),
                        use_commit_times, NULL, cancel_func, cancel_baton,
                        notify_func, notify_baton, pool);
}

svn_error_t *
svn_wc_revert(const char *path,
              svn_wc_adm_access_t *parent_access,
              svn_boolean_t recursive,
              svn_boolean_t use_commit_times,
              svn_cancel_func_t cancel_func,
              void *cancel_baton,
              svn_wc_notify_func_t notify_func,
              void *notify_baton,
              apr_pool_t *pool)
{
  struct compat_notify_baton_t nb;

  nb.func = notify_func;
  nb.baton = notify_baton;

  return svn_wc_revert2(path, parent_access, recursive, use_commit_times,
                        cancel_func, cancel_baton,
                        compat_call_notify_func, &nb, pool);
}

svn_error_t *
svn_wc_remove_from_revision_control(svn_wc_adm_access_t *adm_access,
                                    const char *name,
                                    svn_boolean_t destroy_wf,
                                    svn_boolean_t instant_error,
                                    svn_cancel_func_t cancel_func,
                                    void *cancel_baton,
                                    apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *wc_db = svn_wc__adm_get_db(adm_access);
  const char *local_abspath = svn_dirent_join(
                                    svn_wc__adm_access_abspath(adm_access),
                                    name,
                                    pool);

  /* name must be an entry in adm_access, fail if not */
  SVN_ERR_ASSERT(strcmp(svn_dirent_basename(name, NULL), name) == 0);
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, wc_db, pool));

  SVN_ERR(svn_wc_remove_from_revision_control2(wc_ctx,
                                               local_abspath,
                                               destroy_wf,
                                               instant_error,
                                               cancel_func, cancel_baton,
                                               pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_resolved_conflict4(const char *path,
                          svn_wc_adm_access_t *adm_access,
                          svn_boolean_t resolve_text,
                          svn_boolean_t resolve_props,
                          svn_boolean_t resolve_tree,
                          svn_depth_t depth,
                          svn_wc_conflict_choice_t conflict_choice,
                          svn_wc_notify_func2_t notify_func,
                          void *notify_baton,
                          svn_cancel_func_t cancel_func,
                          void *cancel_baton,
                          apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *wc_db = svn_wc__adm_get_db(adm_access);
  const char *local_abspath;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, wc_db, pool));

  SVN_ERR(svn_wc_resolved_conflict5(wc_ctx,
                                    local_abspath,
                                    depth,
                                    resolve_text,
                                    resolve_props ? "" : NULL,
                                    resolve_tree,
                                    conflict_choice,
                                    cancel_func,
                                    cancel_baton,
                                    notify_func,
                                    notify_baton,
                                    pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));

}

svn_error_t *
svn_wc_resolved_conflict(const char *path,
                         svn_wc_adm_access_t *adm_access,
                         svn_boolean_t resolve_text,
                         svn_boolean_t resolve_props,
                         svn_boolean_t recurse,
                         svn_wc_notify_func_t notify_func,
                         void *notify_baton,
                         apr_pool_t *pool)
{
  struct compat_notify_baton_t nb;

  nb.func = notify_func;
  nb.baton = notify_baton;

  return svn_wc_resolved_conflict2(path, adm_access,
                                   resolve_text, resolve_props, recurse,
                                   compat_call_notify_func, &nb,
                                   NULL, NULL, pool);

}

svn_error_t *
svn_wc_resolved_conflict2(const char *path,
                          svn_wc_adm_access_t *adm_access,
                          svn_boolean_t resolve_text,
                          svn_boolean_t resolve_props,
                          svn_boolean_t recurse,
                          svn_wc_notify_func2_t notify_func,
                          void *notify_baton,
                          svn_cancel_func_t cancel_func,
                          void *cancel_baton,
                          apr_pool_t *pool)
{
  return svn_wc_resolved_conflict3(path, adm_access, resolve_text,
                                   resolve_props,
                                   SVN_DEPTH_INFINITY_OR_EMPTY(recurse),
                                   svn_wc_conflict_choose_merged,
                                   notify_func, notify_baton, cancel_func,
                                   cancel_baton, pool);
}

svn_error_t *
svn_wc_resolved_conflict3(const char *path,
                          svn_wc_adm_access_t *adm_access,
                          svn_boolean_t resolve_text,
                          svn_boolean_t resolve_props,
                          svn_depth_t depth,
                          svn_wc_conflict_choice_t conflict_choice,
                          svn_wc_notify_func2_t notify_func,
                          void *notify_baton,
                          svn_cancel_func_t cancel_func,
                          void *cancel_baton,
                          apr_pool_t *pool)
{
  return svn_wc_resolved_conflict4(path, adm_access, resolve_text,
                                   resolve_props, FALSE, depth,
                                   svn_wc_conflict_choose_merged,
                                   notify_func, notify_baton, cancel_func,
                                   cancel_baton, pool);
}

svn_error_t *
svn_wc_add_lock(const char *path,
                const svn_lock_t *lock,
                svn_wc_adm_access_t *adm_access,
                apr_pool_t *pool)
{
  const char *local_abspath;
  svn_wc_context_t *wc_ctx;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access),
                                         pool));

  SVN_ERR(svn_wc_add_lock2(wc_ctx, local_abspath, lock, pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_remove_lock(const char *path,
                   svn_wc_adm_access_t *adm_access,
                   apr_pool_t *pool)
{
  const char *local_abspath;
  svn_wc_context_t *wc_ctx;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access),
                                         pool));

  SVN_ERR(svn_wc_remove_lock2(wc_ctx, local_abspath, pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));

}

svn_error_t *
svn_wc_get_ancestry(char **url,
                    svn_revnum_t *rev,
                    const char *path,
                    svn_wc_adm_access_t *adm_access,
                    apr_pool_t *pool)
{
  const char *local_abspath;
  const svn_wc_entry_t *entry;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));

  SVN_ERR(svn_wc__get_entry(&entry, svn_wc__adm_get_db(adm_access),
                            local_abspath, FALSE,
                            svn_node_unknown,
                            pool, pool));

  if (url)
    *url = apr_pstrdup(pool, entry->url);

  if (rev)
    *rev = entry->revision;

  return SVN_NO_ERROR;
}

svn_error_t *
svn_wc_set_changelist(const char *path,
                      const char *changelist,
                      svn_wc_adm_access_t *adm_access,
                      svn_cancel_func_t cancel_func,
                      void *cancel_baton,
                      svn_wc_notify_func2_t notify_func,
                      void *notify_baton,
                      apr_pool_t *pool)
{
  const char *local_abspath;
  svn_wc_context_t *wc_ctx;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access),
                                         pool));

  SVN_ERR(svn_wc_set_changelist2(wc_ctx, local_abspath, changelist,
                                 svn_depth_empty, NULL,
                                 cancel_func, cancel_baton, notify_func,
                                 notify_baton, pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}


/*** From diff.c ***/
/* Used to wrap svn_wc_diff_callbacks_t. */
struct diff_callbacks_wrapper_baton {
  const svn_wc_diff_callbacks_t *callbacks;
  void *baton;
};

/* An svn_wc_diff_callbacks3_t function for wrapping svn_wc_diff_callbacks_t. */
static svn_error_t *
wrap_3to1_file_changed(svn_wc_adm_access_t *adm_access,
                       svn_wc_notify_state_t *contentstate,
                       svn_wc_notify_state_t *propstate,
                       svn_boolean_t *tree_conflicted,
                       const char *path,
                       const char *tmpfile1,
                       const char *tmpfile2,
                       svn_revnum_t rev1,
                       svn_revnum_t rev2,
                       const char *mimetype1,
                       const char *mimetype2,
                       const apr_array_header_t *propchanges,
                       apr_hash_t *originalprops,
                       void *diff_baton)
{
  struct diff_callbacks_wrapper_baton *b = diff_baton;

  if (tree_conflicted)
    *tree_conflicted = FALSE;

  if (tmpfile2 != NULL)
    SVN_ERR(b->callbacks->file_changed(adm_access, contentstate, path,
                                       tmpfile1, tmpfile2,
                                       rev1, rev2, mimetype1, mimetype2,
                                       b->baton));
  if (propchanges->nelts > 0)
    SVN_ERR(b->callbacks->props_changed(adm_access, propstate, path,
                                        propchanges, originalprops,
                                        b->baton));

  return SVN_NO_ERROR;
}

/* An svn_wc_diff_callbacks3_t function for wrapping svn_wc_diff_callbacks_t. */
static svn_error_t *
wrap_3to1_file_added(svn_wc_adm_access_t *adm_access,
                     svn_wc_notify_state_t *contentstate,
                     svn_wc_notify_state_t *propstate,
                     svn_boolean_t *tree_conflicted,
                     const char *path,
                     const char *tmpfile1,
                     const char *tmpfile2,
                     svn_revnum_t rev1,
                     svn_revnum_t rev2,
                     const char *mimetype1,
                     const char *mimetype2,
                     const apr_array_header_t *propchanges,
                     apr_hash_t *originalprops,
                     void *diff_baton)
{
  struct diff_callbacks_wrapper_baton *b = diff_baton;

  if (tree_conflicted)
    *tree_conflicted = FALSE;

  SVN_ERR(b->callbacks->file_added(adm_access, contentstate, path,
                                   tmpfile1, tmpfile2, rev1, rev2,
                                   mimetype1, mimetype2, b->baton));
  if (propchanges->nelts > 0)
    SVN_ERR(b->callbacks->props_changed(adm_access, propstate, path,
                                        propchanges, originalprops,
                                        b->baton));

  return SVN_NO_ERROR;
}

/* An svn_wc_diff_callbacks3_t function for wrapping svn_wc_diff_callbacks_t. */
static svn_error_t *
wrap_3to1_file_deleted(svn_wc_adm_access_t *adm_access,
                       svn_wc_notify_state_t *state,
                       svn_boolean_t *tree_conflicted,
                       const char *path,
                       const char *tmpfile1,
                       const char *tmpfile2,
                       const char *mimetype1,
                       const char *mimetype2,
                       apr_hash_t *originalprops,
                       void *diff_baton)
{
  struct diff_callbacks_wrapper_baton *b = diff_baton;

  if (tree_conflicted)
    *tree_conflicted = FALSE;

  SVN_ERR_ASSERT(originalprops);

  return b->callbacks->file_deleted(adm_access, state, path,
                                    tmpfile1, tmpfile2, mimetype1, mimetype2,
                                    b->baton);
}

/* An svn_wc_diff_callbacks3_t function for wrapping svn_wc_diff_callbacks_t. */
static svn_error_t *
wrap_3to1_dir_added(svn_wc_adm_access_t *adm_access,
                    svn_wc_notify_state_t *state,
                    svn_boolean_t *tree_conflicted,
                    const char *path,
                    svn_revnum_t rev,
                    void *diff_baton)
{
  struct diff_callbacks_wrapper_baton *b = diff_baton;

  if (tree_conflicted)
    *tree_conflicted = FALSE;

  return b->callbacks->dir_added(adm_access, state, path, rev, b->baton);
}

/* An svn_wc_diff_callbacks3_t function for wrapping svn_wc_diff_callbacks_t. */
static svn_error_t *
wrap_3to1_dir_deleted(svn_wc_adm_access_t *adm_access,
                      svn_wc_notify_state_t *state,
                      svn_boolean_t *tree_conflicted,
                      const char *path,
                      void *diff_baton)
{
  struct diff_callbacks_wrapper_baton *b = diff_baton;

  if (tree_conflicted)
    *tree_conflicted = FALSE;

  return b->callbacks->dir_deleted(adm_access, state, path, b->baton);
}

/* An svn_wc_diff_callbacks3_t function for wrapping svn_wc_diff_callbacks_t. */
static svn_error_t *
wrap_3to1_dir_props_changed(svn_wc_adm_access_t *adm_access,
                            svn_wc_notify_state_t *state,
                            svn_boolean_t *tree_conflicted,
                            const char *path,
                            const apr_array_header_t *propchanges,
                            apr_hash_t *originalprops,
                            void *diff_baton)
{
  struct diff_callbacks_wrapper_baton *b = diff_baton;

  if (tree_conflicted)
    *tree_conflicted = FALSE;

  return b->callbacks->props_changed(adm_access, state, path, propchanges,
                                     originalprops, b->baton);
}

/* An svn_wc_diff_callbacks3_t function for wrapping svn_wc_diff_callbacks_t
   and svn_wc_diff_callbacks2_t. */
static svn_error_t *
wrap_3to1or2_dir_opened(svn_wc_adm_access_t *adm_access,
                        svn_boolean_t *tree_conflicted,
                        const char *path,
                        svn_revnum_t rev,
                        void *diff_baton)
{
  if (tree_conflicted)
    *tree_conflicted = FALSE;
  /* Do nothing. */
  return SVN_NO_ERROR;
}

/* An svn_wc_diff_callbacks3_t function for wrapping svn_wc_diff_callbacks_t
   and svn_wc_diff_callbacks2_t. */
static svn_error_t *
wrap_3to1or2_dir_closed(svn_wc_adm_access_t *adm_access,
                        svn_wc_notify_state_t *propstate,
                        svn_wc_notify_state_t *contentstate,
                        svn_boolean_t *tree_conflicted,
                        const char *path,
                        void *diff_baton)
{
  if (contentstate)
    *contentstate = svn_wc_notify_state_unknown;
  if (propstate)
    *propstate = svn_wc_notify_state_unknown;
  if (tree_conflicted)
    *tree_conflicted = FALSE;
  /* Do nothing. */
  return SVN_NO_ERROR;
}

/* Used to wrap svn_diff_callbacks_t as an svn_wc_diff_callbacks3_t. */
static struct svn_wc_diff_callbacks3_t diff_callbacks_wrapper = {
  wrap_3to1_file_changed,
  wrap_3to1_file_added,
  wrap_3to1_file_deleted,
  wrap_3to1_dir_added,
  wrap_3to1_dir_deleted,
  wrap_3to1_dir_props_changed,
  wrap_3to1or2_dir_opened,
  wrap_3to1or2_dir_closed
};



/* Used to wrap svn_wc_diff_callbacks2_t. */
struct diff_callbacks2_wrapper_baton {
  const svn_wc_diff_callbacks2_t *callbacks2;
  void *baton;
};

/* An svn_wc_diff_callbacks3_t function for wrapping
 * svn_wc_diff_callbacks2_t. */
static svn_error_t *
wrap_3to2_file_changed(svn_wc_adm_access_t *adm_access,
                       svn_wc_notify_state_t *contentstate,
                       svn_wc_notify_state_t *propstate,
                       svn_boolean_t *tree_conflicted,
                       const char *path,
                       const char *tmpfile1,
                       const char *tmpfile2,
                       svn_revnum_t rev1,
                       svn_revnum_t rev2,
                       const char *mimetype1,
                       const char *mimetype2,
                       const apr_array_header_t *propchanges,
                       apr_hash_t *originalprops,
                       void *diff_baton)
{
  struct diff_callbacks2_wrapper_baton *b = diff_baton;

  if (tree_conflicted)
    *tree_conflicted = FALSE;

  return b->callbacks2->file_changed(adm_access, contentstate, propstate,
                                     path, tmpfile1, tmpfile2,
                                     rev1, rev2, mimetype1, mimetype2,
                                     propchanges, originalprops, b->baton);
}

/* An svn_wc_diff_callbacks3_t function for wrapping
 * svn_wc_diff_callbacks2_t. */
static svn_error_t *
wrap_3to2_file_added(svn_wc_adm_access_t *adm_access,
                     svn_wc_notify_state_t *contentstate,
                     svn_wc_notify_state_t *propstate,
                     svn_boolean_t *tree_conflicted,
                     const char *path,
                     const char *tmpfile1,
                     const char *tmpfile2,
                     svn_revnum_t rev1,
                     svn_revnum_t rev2,
                     const char *mimetype1,
                     const char *mimetype2,
                     const apr_array_header_t *propchanges,
                     apr_hash_t *originalprops,
                     void *diff_baton)
{
  struct diff_callbacks2_wrapper_baton *b = diff_baton;

  if (tree_conflicted)
    *tree_conflicted = FALSE;

  return b->callbacks2->file_added(adm_access, contentstate, propstate, path,
                                   tmpfile1, tmpfile2, rev1, rev2,
                                   mimetype1, mimetype2, propchanges,
                                   originalprops, b->baton);
}

/* An svn_wc_diff_callbacks3_t function for wrapping
 * svn_wc_diff_callbacks2_t. */
static svn_error_t *
wrap_3to2_file_deleted(svn_wc_adm_access_t *adm_access,
                       svn_wc_notify_state_t *state,
                       svn_boolean_t *tree_conflicted,
                       const char *path,
                       const char *tmpfile1,
                       const char *tmpfile2,
                       const char *mimetype1,
                       const char *mimetype2,
                       apr_hash_t *originalprops,
                       void *diff_baton)
{
  struct diff_callbacks2_wrapper_baton *b = diff_baton;

  if (tree_conflicted)
    *tree_conflicted = FALSE;

  return b->callbacks2->file_deleted(adm_access, state, path,
                                     tmpfile1, tmpfile2, mimetype1, mimetype2,
                                     originalprops, b->baton);
}

/* An svn_wc_diff_callbacks3_t function for wrapping
 * svn_wc_diff_callbacks2_t. */
static svn_error_t *
wrap_3to2_dir_added(svn_wc_adm_access_t *adm_access,
                    svn_wc_notify_state_t *state,
                    svn_boolean_t *tree_conflicted,
                    const char *path,
                    svn_revnum_t rev,
                    void *diff_baton)
{
  struct diff_callbacks2_wrapper_baton *b = diff_baton;

  if (tree_conflicted)
    *tree_conflicted = FALSE;

  return b->callbacks2->dir_added(adm_access, state, path, rev, b->baton);
}

/* An svn_wc_diff_callbacks3_t function for wrapping
 * svn_wc_diff_callbacks2_t. */
static svn_error_t *
wrap_3to2_dir_deleted(svn_wc_adm_access_t *adm_access,
                      svn_wc_notify_state_t *state,
                      svn_boolean_t *tree_conflicted,
                      const char *path,
                      void *diff_baton)
{
  struct diff_callbacks2_wrapper_baton *b = diff_baton;

  if (tree_conflicted)
    *tree_conflicted = FALSE;

  return b->callbacks2->dir_deleted(adm_access, state, path, b->baton);
}

/* An svn_wc_diff_callbacks3_t function for wrapping
 * svn_wc_diff_callbacks2_t. */
static svn_error_t *
wrap_3to2_dir_props_changed(svn_wc_adm_access_t *adm_access,
                            svn_wc_notify_state_t *state,
                            svn_boolean_t *tree_conflicted,
                            const char *path,
                            const apr_array_header_t *propchanges,
                            apr_hash_t *originalprops,
                            void *diff_baton)
{
  struct diff_callbacks2_wrapper_baton *b = diff_baton;

  if (tree_conflicted)
    *tree_conflicted = FALSE;

  return b->callbacks2->dir_props_changed(adm_access, state, path, propchanges,
                                          originalprops, b->baton);
}

/* Used to wrap svn_diff_callbacks2_t as an svn_wc_diff_callbacks3_t. */
static struct svn_wc_diff_callbacks3_t diff_callbacks2_wrapper = {
  wrap_3to2_file_changed,
  wrap_3to2_file_added,
  wrap_3to2_file_deleted,
  wrap_3to2_dir_added,
  wrap_3to2_dir_deleted,
  wrap_3to2_dir_props_changed,
  wrap_3to1or2_dir_opened,
  wrap_3to1or2_dir_closed
};



/* Used to wrap svn_wc_diff_callbacks3_t. */
struct diff_callbacks3_wrapper_baton {
  const svn_wc_diff_callbacks3_t *callbacks3;
  svn_wc__db_t *db;
  void *baton;
  const char *anchor;
  const char *anchor_abspath;
};

static svn_error_t *
wrap_4to3_file_opened(svn_boolean_t *tree_conflicted,
                      svn_boolean_t *skip,
                      const char *path,
                      svn_revnum_t rev,
                      void *diff_baton,
                      apr_pool_t *scratch_pool)
{
  return SVN_NO_ERROR;
}

/* An svn_wc_diff_callbacks4_t function for wrapping
 * svn_wc_diff_callbacks3_t. */
static svn_error_t *
wrap_4to3_file_changed(svn_wc_notify_state_t *contentstate,
                       svn_wc_notify_state_t *propstate,
                       svn_boolean_t *tree_conflicted,
                       const char *path,
                       const char *tmpfile1,
                       const char *tmpfile2,
                       svn_revnum_t rev1,
                       svn_revnum_t rev2,
                       const char *mimetype1,
                       const char *mimetype2,
                       const apr_array_header_t *propchanges,
                       apr_hash_t *originalprops,
                       void *diff_baton,
                       apr_pool_t *scratch_pool)
{
  struct diff_callbacks3_wrapper_baton *b = diff_baton;
  svn_wc_adm_access_t *adm_access;
  const char *dir = svn_relpath_dirname(path, scratch_pool);

  adm_access = svn_wc__adm_retrieve_internal2(
                        b->db,
                        svn_dirent_join(b->anchor_abspath, dir, scratch_pool),
                        scratch_pool);

  return b->callbacks3->file_changed(adm_access, contentstate, propstate,
                                     tree_conflicted,
                                     svn_dirent_join(b->anchor, path,
                                                     scratch_pool),
                                     tmpfile1, tmpfile2,
                                     rev1, rev2, mimetype1, mimetype2,
                                     propchanges, originalprops, b->baton);
}

/* An svn_wc_diff_callbacks4_t function for wrapping
 * svn_wc_diff_callbacks3_t. */
static svn_error_t *
wrap_4to3_file_added(svn_wc_notify_state_t *contentstate,
                     svn_wc_notify_state_t *propstate,
                     svn_boolean_t *tree_conflicted,
                     const char *path,
                     const char *tmpfile1,
                     const char *tmpfile2,
                     svn_revnum_t rev1,
                     svn_revnum_t rev2,
                     const char *mimetype1,
                     const char *mimetype2,
                     const char *copyfrom_path,
                     svn_revnum_t copyfrom_revision,
                     const apr_array_header_t *propchanges,
                     apr_hash_t *originalprops,
                     void *diff_baton,
                     apr_pool_t *scratch_pool)
{
  struct diff_callbacks3_wrapper_baton *b = diff_baton;
  svn_wc_adm_access_t *adm_access;
  const char *dir = svn_relpath_dirname(path, scratch_pool);

  adm_access = svn_wc__adm_retrieve_internal2(
                        b->db,
                        svn_dirent_join(b->anchor_abspath, dir, scratch_pool),
                        scratch_pool);

  return b->callbacks3->file_added(adm_access, contentstate, propstate,
                                   tree_conflicted,
                                   svn_dirent_join(b->anchor, path,
                                                   scratch_pool),
                                   tmpfile1, tmpfile2,
                                   rev1, rev2, mimetype1, mimetype2,
                                   propchanges, originalprops, b->baton);
}

/* An svn_wc_diff_callbacks4_t function for wrapping
 * svn_wc_diff_callbacks3_t. */
static svn_error_t *
wrap_4to3_file_deleted(svn_wc_notify_state_t *state,
                       svn_boolean_t *tree_conflicted,
                       const char *path,
                       const char *tmpfile1,
                       const char *tmpfile2,
                       const char *mimetype1,
                       const char *mimetype2,
                       apr_hash_t *originalprops,
                       void *diff_baton,
                       apr_pool_t *scratch_pool)
{
  struct diff_callbacks3_wrapper_baton *b = diff_baton;
  svn_wc_adm_access_t *adm_access;
  const char *dir = svn_relpath_dirname(path, scratch_pool);

  adm_access = svn_wc__adm_retrieve_internal2(
                        b->db,
                        svn_dirent_join(b->anchor_abspath, dir, scratch_pool),
                        scratch_pool);

  return b->callbacks3->file_deleted(adm_access, state, tree_conflicted,
                                     svn_dirent_join(b->anchor, path,
                                                     scratch_pool),
                                     tmpfile1, tmpfile2,
                                     mimetype1, mimetype2, originalprops,
                                     b->baton);
}

/* An svn_wc_diff_callbacks4_t function for wrapping
 * svn_wc_diff_callbacks3_t. */
static svn_error_t *
wrap_4to3_dir_added(svn_wc_notify_state_t *state,
                    svn_boolean_t *tree_conflicted,
                    svn_boolean_t *skip,
                    svn_boolean_t *skip_children,
                    const char *path,
                    svn_revnum_t rev,
                    const char *copyfrom_path,
                    svn_revnum_t copyfrom_revision,
                    void *diff_baton,
                    apr_pool_t *scratch_pool)
{
  struct diff_callbacks3_wrapper_baton *b = diff_baton;
  svn_wc_adm_access_t *adm_access;

  adm_access = svn_wc__adm_retrieve_internal2(
                        b->db,
                        svn_dirent_join(b->anchor_abspath, path, scratch_pool),
                        scratch_pool);

  return b->callbacks3->dir_added(adm_access, state, tree_conflicted,
                                  svn_dirent_join(b->anchor, path,
                                                     scratch_pool),
                                  rev, b->baton);
}

/* An svn_wc_diff_callbacks4_t function for wrapping
 * svn_wc_diff_callbacks3_t. */
static svn_error_t *
wrap_4to3_dir_deleted(svn_wc_notify_state_t *state,
                      svn_boolean_t *tree_conflicted,
                      const char *path,
                      void *diff_baton,
                      apr_pool_t *scratch_pool)
{
  struct diff_callbacks3_wrapper_baton *b = diff_baton;
  svn_wc_adm_access_t *adm_access;

  adm_access = svn_wc__adm_retrieve_internal2(
                        b->db,
                        svn_dirent_join(b->anchor_abspath, path, scratch_pool),
                        scratch_pool);

  return b->callbacks3->dir_deleted(adm_access, state, tree_conflicted,
                                    svn_dirent_join(b->anchor, path,
                                                     scratch_pool),
                                    b->baton);
}

/* An svn_wc_diff_callbacks4_t function for wrapping
 * svn_wc_diff_callbacks3_t. */
static svn_error_t *
wrap_4to3_dir_props_changed(svn_wc_notify_state_t *propstate,
                            svn_boolean_t *tree_conflicted,
                            const char *path,
                            svn_boolean_t dir_was_added,
                            const apr_array_header_t *propchanges,
                            apr_hash_t *original_props,
                            void *diff_baton,
                            apr_pool_t *scratch_pool)
{
  struct diff_callbacks3_wrapper_baton *b = diff_baton;
  svn_wc_adm_access_t *adm_access;

  adm_access = svn_wc__adm_retrieve_internal2(
                        b->db,
                        svn_dirent_join(b->anchor_abspath, path, scratch_pool),
                        scratch_pool);

  return b->callbacks3->dir_props_changed(adm_access, propstate,
                                          tree_conflicted,
                                          svn_dirent_join(b->anchor, path,
                                                     scratch_pool),
                                          propchanges, original_props,
                                          b->baton);
}

/* An svn_wc_diff_callbacks4_t function for wrapping
 * svn_wc_diff_callbacks3_t. */
static svn_error_t *
wrap_4to3_dir_opened(svn_boolean_t *tree_conflicted,
                     svn_boolean_t *skip,
                     svn_boolean_t *skip_children,
                     const char *path,
                     svn_revnum_t rev,
                     void *diff_baton,
                     apr_pool_t *scratch_pool)
{
  struct diff_callbacks3_wrapper_baton *b = diff_baton;
  svn_wc_adm_access_t *adm_access;

  adm_access = svn_wc__adm_retrieve_internal2(
                        b->db,
                        svn_dirent_join(b->anchor_abspath, path, scratch_pool),
                        scratch_pool);
  if (skip_children)
    *skip_children = FALSE;

  return b->callbacks3->dir_opened(adm_access, tree_conflicted,
                                   svn_dirent_join(b->anchor, path,
                                                     scratch_pool),
                                   rev, b->baton);
}

/* An svn_wc_diff_callbacks4_t function for wrapping
 * svn_wc_diff_callbacks3_t. */
static svn_error_t *
wrap_4to3_dir_closed(svn_wc_notify_state_t *contentstate,
                     svn_wc_notify_state_t *propstate,
                     svn_boolean_t *tree_conflicted,
                     const char *path,
                     svn_boolean_t dir_was_added,
                     void *diff_baton,
                     apr_pool_t *scratch_pool)
{
  struct diff_callbacks3_wrapper_baton *b = diff_baton;
  svn_wc_adm_access_t *adm_access;

  adm_access = svn_wc__adm_retrieve_internal2(
                        b->db,
                        svn_dirent_join(b->anchor_abspath, path, scratch_pool),
                        scratch_pool);

  return b->callbacks3->dir_closed(adm_access, contentstate, propstate,
                                   tree_conflicted,
                                   svn_dirent_join(b->anchor, path,
                                                     scratch_pool),
                                   b->baton);
}


/* Used to wrap svn_diff_callbacks3_t as an svn_wc_diff_callbacks4_t. */
static struct svn_wc_diff_callbacks4_t diff_callbacks3_wrapper = {
  wrap_4to3_file_opened,
  wrap_4to3_file_changed,
  wrap_4to3_file_added,
  wrap_4to3_file_deleted,
  wrap_4to3_dir_deleted,
  wrap_4to3_dir_opened,
  wrap_4to3_dir_added,
  wrap_4to3_dir_props_changed,
  wrap_4to3_dir_closed
};

svn_error_t *
svn_wc_get_diff_editor5(svn_wc_adm_access_t *anchor,
                        const char *target,
                        const svn_wc_diff_callbacks3_t *callbacks,
                        void *callback_baton,
                        svn_depth_t depth,
                        svn_boolean_t ignore_ancestry,
                        svn_boolean_t use_text_base,
                        svn_boolean_t reverse_order,
                        svn_cancel_func_t cancel_func,
                        void *cancel_baton,
                        const apr_array_header_t *changelist_filter,
                        const svn_delta_editor_t **editor,
                        void **edit_baton,
                        apr_pool_t *pool)
{
  struct diff_callbacks3_wrapper_baton *b = apr_palloc(pool, sizeof(*b));
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *db = svn_wc__adm_get_db(anchor);

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, db, pool));

  b->callbacks3 = callbacks;
  b->baton = callback_baton;
  b->db = db;
  b->anchor = svn_wc_adm_access_path(anchor);
  b->anchor_abspath = svn_wc__adm_access_abspath(anchor);

  SVN_ERR(svn_wc_get_diff_editor6(editor,
                                   edit_baton,
                                   wc_ctx,
                                   b->anchor_abspath,
                                   target,
                                   depth,
                                   ignore_ancestry,
                                   FALSE,
                                   FALSE,
                                   use_text_base,
                                   reverse_order,
                                   FALSE,
                                   changelist_filter,
                                   &diff_callbacks3_wrapper,
                                   b,
                                   cancel_func,
                                   cancel_baton,
                                   pool,
                                   pool));

  /* Can't destroy wc_ctx. It is used by the diff editor */

   return SVN_NO_ERROR;
}

svn_error_t *
svn_wc_get_diff_editor4(svn_wc_adm_access_t *anchor,
                        const char *target,
                        const svn_wc_diff_callbacks2_t *callbacks,
                        void *callback_baton,
                        svn_depth_t depth,
                        svn_boolean_t ignore_ancestry,
                        svn_boolean_t use_text_base,
                        svn_boolean_t reverse_order,
                        svn_cancel_func_t cancel_func,
                        void *cancel_baton,
                        const apr_array_header_t *changelist_filter,
                        const svn_delta_editor_t **editor,
                        void **edit_baton,
                        apr_pool_t *pool)
{
  struct diff_callbacks2_wrapper_baton *b = apr_palloc(pool, sizeof(*b));
  b->callbacks2 = callbacks;
  b->baton = callback_baton;
  return svn_wc_get_diff_editor5(anchor,
                                 target,
                                 &diff_callbacks2_wrapper,
                                 b,
                                 depth,
                                 ignore_ancestry,
                                 use_text_base,
                                 reverse_order,
                                 cancel_func,
                                 cancel_baton,
                                 changelist_filter,
                                 editor,
                                 edit_baton,
                                 pool);
}

svn_error_t *
svn_wc_get_diff_editor3(svn_wc_adm_access_t *anchor,
                        const char *target,
                        const svn_wc_diff_callbacks2_t *callbacks,
                        void *callback_baton,
                        svn_boolean_t recurse,
                        svn_boolean_t ignore_ancestry,
                        svn_boolean_t use_text_base,
                        svn_boolean_t reverse_order,
                        svn_cancel_func_t cancel_func,
                        void *cancel_baton,
                        const svn_delta_editor_t **editor,
                        void **edit_baton,
                        apr_pool_t *pool)
{
  return svn_wc_get_diff_editor4(anchor,
                                 target,
                                 callbacks,
                                 callback_baton,
                                 SVN_DEPTH_INFINITY_OR_FILES(recurse),
                                 ignore_ancestry,
                                 use_text_base,
                                 reverse_order,
                                 cancel_func,
                                 cancel_baton,
                                 NULL,
                                 editor,
                                 edit_baton,
                                 pool);
}

svn_error_t *
svn_wc_get_diff_editor2(svn_wc_adm_access_t *anchor,
                        const char *target,
                        const svn_wc_diff_callbacks_t *callbacks,
                        void *callback_baton,
                        svn_boolean_t recurse,
                        svn_boolean_t ignore_ancestry,
                        svn_boolean_t use_text_base,
                        svn_boolean_t reverse_order,
                        svn_cancel_func_t cancel_func,
                        void *cancel_baton,
                        const svn_delta_editor_t **editor,
                        void **edit_baton,
                        apr_pool_t *pool)
{
  struct diff_callbacks_wrapper_baton *b = apr_palloc(pool, sizeof(*b));
  b->callbacks = callbacks;
  b->baton = callback_baton;
  return svn_wc_get_diff_editor5(anchor, target, &diff_callbacks_wrapper, b,
                                 SVN_DEPTH_INFINITY_OR_FILES(recurse),
                                 ignore_ancestry, use_text_base,
                                 reverse_order, cancel_func, cancel_baton,
                                 NULL, editor, edit_baton, pool);
}

svn_error_t *
svn_wc_get_diff_editor(svn_wc_adm_access_t *anchor,
                       const char *target,
                       const svn_wc_diff_callbacks_t *callbacks,
                       void *callback_baton,
                       svn_boolean_t recurse,
                       svn_boolean_t use_text_base,
                       svn_boolean_t reverse_order,
                       svn_cancel_func_t cancel_func,
                       void *cancel_baton,
                       const svn_delta_editor_t **editor,
                       void **edit_baton,
                       apr_pool_t *pool)
{
  return svn_wc_get_diff_editor2(anchor, target, callbacks, callback_baton,
                                 recurse, FALSE, use_text_base, reverse_order,
                                 cancel_func, cancel_baton,
                                 editor, edit_baton, pool);
}

svn_error_t *
svn_wc_diff5(svn_wc_adm_access_t *anchor,
             const char *target,
             const svn_wc_diff_callbacks3_t *callbacks,
             void *callback_baton,
             svn_depth_t depth,
             svn_boolean_t ignore_ancestry,
             const apr_array_header_t *changelist_filter,
             apr_pool_t *pool)
{
  struct diff_callbacks3_wrapper_baton *b = apr_palloc(pool, sizeof(*b));
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *db = svn_wc__adm_get_db(anchor);

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, db, pool));

  b->callbacks3 = callbacks;
  b->baton = callback_baton;
  b->anchor = svn_wc_adm_access_path(anchor);
  b->anchor_abspath = svn_wc__adm_access_abspath(anchor);

  SVN_ERR(svn_wc_diff6(wc_ctx,
                       svn_dirent_join(b->anchor_abspath, target, pool),
                       &diff_callbacks3_wrapper,
                       b,
                       depth,
                       ignore_ancestry,
                       FALSE,
                       FALSE,
                       changelist_filter,
                       NULL, NULL,
                       pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_diff4(svn_wc_adm_access_t *anchor,
             const char *target,
             const svn_wc_diff_callbacks2_t *callbacks,
             void *callback_baton,
             svn_depth_t depth,
             svn_boolean_t ignore_ancestry,
             const apr_array_header_t *changelist_filter,
             apr_pool_t *pool)
{
  struct diff_callbacks2_wrapper_baton *b = apr_palloc(pool, sizeof(*b));
  b->callbacks2 = callbacks;
  b->baton = callback_baton;

  return svn_wc_diff5(anchor, target, &diff_callbacks2_wrapper, b,
                      depth, ignore_ancestry, changelist_filter, pool);
}

svn_error_t *
svn_wc_diff3(svn_wc_adm_access_t *anchor,
             const char *target,
             const svn_wc_diff_callbacks2_t *callbacks,
             void *callback_baton,
             svn_boolean_t recurse,
             svn_boolean_t ignore_ancestry,
             apr_pool_t *pool)
{
  return svn_wc_diff4(anchor, target, callbacks, callback_baton,
                      SVN_DEPTH_INFINITY_OR_FILES(recurse), ignore_ancestry,
                      NULL, pool);
}

svn_error_t *
svn_wc_diff2(svn_wc_adm_access_t *anchor,
             const char *target,
             const svn_wc_diff_callbacks_t *callbacks,
             void *callback_baton,
             svn_boolean_t recurse,
             svn_boolean_t ignore_ancestry,
             apr_pool_t *pool)
{
  struct diff_callbacks_wrapper_baton *b = apr_pcalloc(pool, sizeof(*b));
  b->callbacks = callbacks;
  b->baton = callback_baton;
  return svn_wc_diff5(anchor, target, &diff_callbacks_wrapper, b,
                      SVN_DEPTH_INFINITY_OR_FILES(recurse), ignore_ancestry,
                      NULL, pool);
}

svn_error_t *
svn_wc_diff(svn_wc_adm_access_t *anchor,
            const char *target,
            const svn_wc_diff_callbacks_t *callbacks,
            void *callback_baton,
            svn_boolean_t recurse,
            apr_pool_t *pool)
{
  return svn_wc_diff2(anchor, target, callbacks, callback_baton,
                      recurse, FALSE, pool);
}

/*** From entries.c ***/
svn_error_t *
svn_wc_walk_entries2(const char *path,
                     svn_wc_adm_access_t *adm_access,
                     const svn_wc_entry_callbacks_t *walk_callbacks,
                     void *walk_baton,
                     svn_boolean_t show_hidden,
                     svn_cancel_func_t cancel_func,
                     void *cancel_baton,
                     apr_pool_t *pool)
{
  svn_wc_entry_callbacks2_t walk_cb2 = { 0 };
  walk_cb2.found_entry = walk_callbacks->found_entry;
  walk_cb2.handle_error = svn_wc__walker_default_error_handler;
  return svn_wc_walk_entries3(path, adm_access,
                              &walk_cb2, walk_baton, svn_depth_infinity,
                              show_hidden, cancel_func, cancel_baton, pool);
}

svn_error_t *
svn_wc_walk_entries(const char *path,
                    svn_wc_adm_access_t *adm_access,
                    const svn_wc_entry_callbacks_t *walk_callbacks,
                    void *walk_baton,
                    svn_boolean_t show_hidden,
                    apr_pool_t *pool)
{
  return svn_wc_walk_entries2(path, adm_access, walk_callbacks,
                              walk_baton, show_hidden, NULL, NULL,
                              pool);
}

svn_error_t *
svn_wc_mark_missing_deleted(const char *path,
                            svn_wc_adm_access_t *parent,
                            apr_pool_t *pool)
{
  /* With a single DB a node will never be missing */
  return svn_error_createf(SVN_ERR_WC_PATH_FOUND, NULL,
                           _("Unexpectedly found '%s': "
                             "path is marked 'missing'"),
                           svn_dirent_local_style(path, pool));
}


/*** From props.c ***/
svn_error_t *
svn_wc_parse_externals_description2(apr_array_header_t **externals_p,
                                    const char *parent_directory,
                                    const char *desc,
                                    apr_pool_t *pool)
{
  apr_array_header_t *list;
  apr_pool_t *subpool = svn_pool_create(pool);

  SVN_ERR(svn_wc_parse_externals_description3(externals_p ? &list : NULL,
                                              parent_directory, desc,
                                              TRUE, subpool));

  if (externals_p)
    {
      int i;

      *externals_p = apr_array_make(pool, list->nelts,
                                    sizeof(svn_wc_external_item_t *));
      for (i = 0; i < list->nelts; i++)
        {
          svn_wc_external_item2_t *item2 = APR_ARRAY_IDX(list, i,
                                             svn_wc_external_item2_t *);
          svn_wc_external_item_t *item = apr_palloc(pool, sizeof (*item));

          if (item2->target_dir)
            item->target_dir = apr_pstrdup(pool, item2->target_dir);
          if (item2->url)
            item->url = apr_pstrdup(pool, item2->url);
          item->revision = item2->revision;

          APR_ARRAY_PUSH(*externals_p, svn_wc_external_item_t *) = item;
        }
    }

  svn_pool_destroy(subpool);

  return SVN_NO_ERROR;
}


svn_error_t *
svn_wc_parse_externals_description(apr_hash_t **externals_p,
                                   const char *parent_directory,
                                   const char *desc,
                                   apr_pool_t *pool)
{
  apr_array_header_t *list;

  SVN_ERR(svn_wc_parse_externals_description2(externals_p ? &list : NULL,
                                              parent_directory, desc, pool));

  /* Store all of the items into the hash if that was requested. */
  if (externals_p)
    {
      int i;

      *externals_p = apr_hash_make(pool);
      for (i = 0; i < list->nelts; i++)
        {
          svn_wc_external_item_t *item;
          item = APR_ARRAY_IDX(list, i, svn_wc_external_item_t *);

          apr_hash_set(*externals_p, item->target_dir,
                       APR_HASH_KEY_STRING, item);
        }
    }
  return SVN_NO_ERROR;
}

svn_error_t *
svn_wc_prop_set3(const char *name,
                 const svn_string_t *value,
                 const char *path,
                 svn_wc_adm_access_t *adm_access,
                 svn_boolean_t skip_checks,
                 svn_wc_notify_func2_t notify_func,
                 void *notify_baton,
                 apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  const char *local_abspath;
  svn_error_t *err;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access),
                                         pool));

  err = svn_wc_prop_set4(wc_ctx, local_abspath,
                         name, value,
                         svn_depth_empty,
                         skip_checks, NULL /* changelist_filter */,
                         NULL, NULL /* cancellation */,
                         notify_func, notify_baton,
                         pool);

  if (err && err->apr_err == SVN_ERR_WC_INVALID_SCHEDULE)
    svn_error_clear(err);
  else
    SVN_ERR(err);

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_prop_set2(const char *name,
                 const svn_string_t *value,
                 const char *path,
                 svn_wc_adm_access_t *adm_access,
                 svn_boolean_t skip_checks,
                 apr_pool_t *pool)
{
  return svn_wc_prop_set3(name, value, path, adm_access, skip_checks,
                          NULL, NULL, pool);
}

svn_error_t *
svn_wc_prop_set(const char *name,
                const svn_string_t *value,
                const char *path,
                svn_wc_adm_access_t *adm_access,
                apr_pool_t *pool)
{
  return svn_wc_prop_set2(name, value, path, adm_access, FALSE, pool);
}

svn_error_t *
svn_wc_prop_list(apr_hash_t **props,
                 const char *path,
                 svn_wc_adm_access_t *adm_access,
                 apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  const char *local_abspath;
  svn_error_t *err;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access), pool));

  err = svn_wc_prop_list2(props, wc_ctx, local_abspath, pool, pool);
  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
    {
      *props = apr_hash_make(pool);
      svn_error_clear(err);
      err = NULL;
    }

  return svn_error_compose_create(err, svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_prop_get(const svn_string_t **value,
                const char *name,
                const char *path,
                svn_wc_adm_access_t *adm_access,
                apr_pool_t *pool)
{

  svn_wc_context_t *wc_ctx;
  const char *local_abspath;
  svn_error_t *err;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access), pool));

  err = svn_wc_prop_get2(value, wc_ctx, local_abspath, name, pool, pool);

  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
    {
      *value = NULL;
      svn_error_clear(err);
      err = NULL;
    }

  return svn_error_compose_create(err, svn_wc_context_destroy(wc_ctx));
}

/* baton for conflict_func_1to2_wrapper */
struct conflict_func_1to2_baton
{
  svn_wc_conflict_resolver_func_t inner_func;
  void *inner_baton;
};


/* Implements svn_wc_conflict_resolver_func2_t */
static svn_error_t *
conflict_func_1to2_wrapper(svn_wc_conflict_result_t **result,
                           const svn_wc_conflict_description2_t *conflict,
                           void *baton,
                           apr_pool_t *result_pool,
                           apr_pool_t *scratch_pool)
{
  struct conflict_func_1to2_baton *btn = baton;
  svn_wc_conflict_description_t *cd = svn_wc__cd2_to_cd(conflict,
                                                        scratch_pool);

  return svn_error_trace(btn->inner_func(result, cd, btn->inner_baton,
                                         result_pool));
}

svn_error_t *
svn_wc_merge_props2(svn_wc_notify_state_t *state,
                    const char *path,
                    svn_wc_adm_access_t *adm_access,
                    apr_hash_t *baseprops,
                    const apr_array_header_t *propchanges,
                    svn_boolean_t base_merge,
                    svn_boolean_t dry_run,
                    svn_wc_conflict_resolver_func_t conflict_func,
                    void *conflict_baton,
                    apr_pool_t *scratch_pool)
{
  const char *local_abspath;
  svn_error_t *err;
  struct conflict_func_1to2_baton conflict_wrapper;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));

  conflict_wrapper.inner_func = conflict_func;
  conflict_wrapper.inner_baton = conflict_baton;

  err = svn_wc__perform_props_merge(state,
                                    svn_wc__adm_get_db(adm_access),
                                    local_abspath,
                                    NULL /* left_version */,
                                    NULL /* right_version */,
                                    baseprops,
                                    propchanges,
                                    base_merge,
                                    dry_run,
                                    conflict_func ? conflict_func_1to2_wrapper
                                                  : NULL,
                                    &conflict_wrapper,
                                    NULL, NULL,
                                    scratch_pool);

  if (err)
    switch(err->apr_err)
      {
        case SVN_ERR_WC_PATH_NOT_FOUND:
        case SVN_ERR_WC_PATH_UNEXPECTED_STATUS:
          err->apr_err = SVN_ERR_UNVERSIONED_RESOURCE;
          break;
      }
  return svn_error_trace(err);
}

svn_error_t *
svn_wc_merge_props(svn_wc_notify_state_t *state,
                   const char *path,
                   svn_wc_adm_access_t *adm_access,
                   apr_hash_t *baseprops,
                   const apr_array_header_t *propchanges,
                   svn_boolean_t base_merge,
                   svn_boolean_t dry_run,
                   apr_pool_t *pool)
{
  return svn_wc_merge_props2(state, path, adm_access, baseprops, propchanges,
                             base_merge, dry_run, NULL, NULL, pool);
}


svn_error_t *
svn_wc_merge_prop_diffs(svn_wc_notify_state_t *state,
                        const char *path,
                        svn_wc_adm_access_t *adm_access,
                        const apr_array_header_t *propchanges,
                        svn_boolean_t base_merge,
                        svn_boolean_t dry_run,
                        apr_pool_t *pool)
{
  /* NOTE: Here, we use implementation knowledge.  The public
     svn_wc_merge_props2 doesn't allow NULL as baseprops argument, but we know
     that it works. */
  return svn_wc_merge_props2(state, path, adm_access, NULL, propchanges,
                             base_merge, dry_run, NULL, NULL, pool);
}

svn_error_t *
svn_wc_get_prop_diffs(apr_array_header_t **propchanges,
                      apr_hash_t **original_props,
                      const char *path,
                      svn_wc_adm_access_t *adm_access,
                      apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  const char *local_abspath;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access), pool));

  SVN_ERR(svn_wc_get_prop_diffs2(propchanges, original_props, wc_ctx,
                                 local_abspath, pool, pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}


svn_error_t *
svn_wc_props_modified_p(svn_boolean_t *modified_p,
                        const char *path,
                        svn_wc_adm_access_t *adm_access,
                        apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  const char *local_abspath;
  svn_error_t *err;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access), pool));

  err = svn_wc_props_modified_p2(modified_p,
                                 wc_ctx,
                                 local_abspath,
                                 pool);

  if (err)
    {
      if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
        return svn_error_trace(err);

      svn_error_clear(err);
      *modified_p = FALSE;
    }

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}


/*** From status.c ***/

struct status4_wrapper_baton
{
  svn_wc_status_func3_t old_func;
  void *old_baton;
  const char *anchor_abspath;
  const char *anchor_relpath;
  svn_wc_context_t *wc_ctx;
};

/* */
static svn_error_t *
status4_wrapper_func(void *baton,
                     const char *local_abspath,
                     const svn_wc_status3_t *status,
                     apr_pool_t *scratch_pool)
{
  struct status4_wrapper_baton *swb = baton;
  svn_wc_status2_t *dup;
  const char *path = local_abspath;

  SVN_ERR(svn_wc__status2_from_3(&dup, status, swb->wc_ctx, local_abspath,
                                 scratch_pool, scratch_pool));

  if (swb->anchor_abspath != NULL)
    {
      path = svn_dirent_join(
                swb->anchor_relpath,
                svn_dirent_skip_ancestor(swb->anchor_abspath, local_abspath),
                scratch_pool);
    }

  return (*swb->old_func)(swb->old_baton, path, dup, scratch_pool);
}

svn_error_t *
svn_wc_get_status_editor4(const svn_delta_editor_t **editor,
                          void **edit_baton,
                          void **set_locks_baton,
                          svn_revnum_t *edit_revision,
                          svn_wc_adm_access_t *anchor,
                          const char *target,
                          svn_depth_t depth,
                          svn_boolean_t get_all,
                          svn_boolean_t no_ignore,
                          const apr_array_header_t *ignore_patterns,
                          svn_wc_status_func3_t status_func,
                          void *status_baton,
                          svn_cancel_func_t cancel_func,
                          void *cancel_baton,
                          svn_wc_traversal_info_t *traversal_info,
                          apr_pool_t *pool)
{
  struct status4_wrapper_baton *swb = apr_palloc(pool, sizeof(*swb));
  svn_wc__db_t *wc_db;
  svn_wc_context_t *wc_ctx;
  const char *anchor_abspath;

  swb->old_func = status_func;
  swb->old_baton = status_baton;

  wc_db = svn_wc__adm_get_db(anchor);

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         wc_db, pool));

  swb->wc_ctx = wc_ctx;

  anchor_abspath = svn_wc__adm_access_abspath(anchor);

  if (!svn_dirent_is_absolute(svn_wc_adm_access_path(anchor)))
    {
      swb->anchor_abspath = anchor_abspath;
      swb->anchor_relpath = svn_wc_adm_access_path(anchor);
    }
  else
    {
      swb->anchor_abspath = NULL;
      swb->anchor_relpath = NULL;
    }

  /* Before subversion 1.7 status always handled depth as sticky. 1.7 made
     the output of svn status by default match the result of what would be
     updated by a similar svn update. (Following the documentation) */

  SVN_ERR(svn_wc_get_status_editor5(editor, edit_baton, set_locks_baton,
                                    edit_revision, wc_ctx, anchor_abspath,
                                    target, depth, get_all,
                                    no_ignore,
                                    (depth != svn_depth_unknown) /*as_sticky*/,
                                    FALSE /* server_performs_filtering */,
                                    ignore_patterns,
                                    status4_wrapper_func, swb,
                                    cancel_func, cancel_baton,
                                    pool, pool));

  if (traversal_info)
    {
      const char *local_path = svn_wc_adm_access_path(anchor);
      const char *local_abspath = anchor_abspath;
      if (*target)
        {
          local_path = svn_dirent_join(local_path, target, pool);
          local_abspath = svn_dirent_join(local_abspath, target, pool);
        }

      SVN_ERR(gather_traversal_info(wc_ctx, local_abspath, local_path, depth,
                                    traversal_info, TRUE, TRUE,
                                    pool));
    }

  /* We can't destroy wc_ctx here, because the editor needs it while it's
     driven. */
  return SVN_NO_ERROR;
}

struct status_editor3_compat_baton
{
  svn_wc_status_func2_t old_func;
  void *old_baton;
};

/* */
static svn_error_t *
status_editor3_compat_func(void *baton,
                           const char *path,
                           svn_wc_status2_t *status,
                           apr_pool_t *pool)
{
  struct status_editor3_compat_baton *secb = baton;

  secb->old_func(secb->old_baton, path, status);
  return SVN_NO_ERROR;
}

svn_error_t *
svn_wc_get_status_editor3(const svn_delta_editor_t **editor,
                          void **edit_baton,
                          void **set_locks_baton,
                          svn_revnum_t *edit_revision,
                          svn_wc_adm_access_t *anchor,
                          const char *target,
                          svn_depth_t depth,
                          svn_boolean_t get_all,
                          svn_boolean_t no_ignore,
                          const apr_array_header_t *ignore_patterns,
                          svn_wc_status_func2_t status_func,
                          void *status_baton,
                          svn_cancel_func_t cancel_func,
                          void *cancel_baton,
                          svn_wc_traversal_info_t *traversal_info,
                          apr_pool_t *pool)
{
  /* This baton must live beyond this function. Alloc on heap.  */
  struct status_editor3_compat_baton *secb = apr_palloc(pool, sizeof(*secb));

  secb->old_func = status_func;
  secb->old_baton = status_baton;

  return svn_wc_get_status_editor4(editor, edit_baton, set_locks_baton,
                                   edit_revision, anchor, target, depth,
                                   get_all, no_ignore, ignore_patterns,
                                   status_editor3_compat_func, secb,
                                   cancel_func, cancel_baton, traversal_info,
                                   pool);
}

svn_error_t *
svn_wc_get_status_editor2(const svn_delta_editor_t **editor,
                          void **edit_baton,
                          void **set_locks_baton,
                          svn_revnum_t *edit_revision,
                          svn_wc_adm_access_t *anchor,
                          const char *target,
                          apr_hash_t *config,
                          svn_boolean_t recurse,
                          svn_boolean_t get_all,
                          svn_boolean_t no_ignore,
                          svn_wc_status_func2_t status_func,
                          void *status_baton,
                          svn_cancel_func_t cancel_func,
                          void *cancel_baton,
                          svn_wc_traversal_info_t *traversal_info,
                          apr_pool_t *pool)
{
  apr_array_header_t *ignores;

  SVN_ERR(svn_wc_get_default_ignores(&ignores, config, pool));
  return svn_wc_get_status_editor3(editor,
                                   edit_baton,
                                   set_locks_baton,
                                   edit_revision,
                                   anchor,
                                   target,
                                   SVN_DEPTH_INFINITY_OR_IMMEDIATES(recurse),
                                   get_all,
                                   no_ignore,
                                   ignores,
                                   status_func,
                                   status_baton,
                                   cancel_func,
                                   cancel_baton,
                                   traversal_info,
                                   pool);
}


/* Helpers for deprecated svn_wc_status_editor(), of type
   svn_wc_status_func2_t. */
struct old_status_func_cb_baton
{
  svn_wc_status_func_t original_func;
  void *original_baton;
};

/* */
static void old_status_func_cb(void *baton,
                               const char *path,
                               svn_wc_status2_t *status)
{
  struct old_status_func_cb_baton *b = baton;
  svn_wc_status_t *stat = (svn_wc_status_t *) status;

  b->original_func(b->original_baton, path, stat);
}

svn_error_t *
svn_wc_get_status_editor(const svn_delta_editor_t **editor,
                         void **edit_baton,
                         svn_revnum_t *edit_revision,
                         svn_wc_adm_access_t *anchor,
                         const char *target,
                         apr_hash_t *config,
                         svn_boolean_t recurse,
                         svn_boolean_t get_all,
                         svn_boolean_t no_ignore,
                         svn_wc_status_func_t status_func,
                         void *status_baton,
                         svn_cancel_func_t cancel_func,
                         void *cancel_baton,
                         svn_wc_traversal_info_t *traversal_info,
                         apr_pool_t *pool)
{
  struct old_status_func_cb_baton *b = apr_pcalloc(pool, sizeof(*b));
  apr_array_header_t *ignores;
  b->original_func = status_func;
  b->original_baton = status_baton;
  SVN_ERR(svn_wc_get_default_ignores(&ignores, config, pool));
  return svn_wc_get_status_editor3(editor, edit_baton, NULL, edit_revision,
                                   anchor, target,
                                   SVN_DEPTH_INFINITY_OR_IMMEDIATES(recurse),
                                   get_all, no_ignore, ignores,
                                   old_status_func_cb, b,
                                   cancel_func, cancel_baton,
                                   traversal_info, pool);
}

svn_error_t *
svn_wc_status(svn_wc_status_t **status,
              const char *path,
              svn_wc_adm_access_t *adm_access,
              apr_pool_t *pool)
{
  svn_wc_status2_t *stat2;

  SVN_ERR(svn_wc_status2(&stat2, path, adm_access, pool));
  *status = (svn_wc_status_t *) stat2;
  return SVN_NO_ERROR;
}


static svn_wc_conflict_description_t *
conflict_description_dup(const svn_wc_conflict_description_t *conflict,
                         apr_pool_t *pool)
{
  svn_wc_conflict_description_t *new_conflict;

  new_conflict = apr_pcalloc(pool, sizeof(*new_conflict));

  /* Shallow copy all members. */
  *new_conflict = *conflict;

  if (conflict->path)
    new_conflict->path = apr_pstrdup(pool, conflict->path);
  if (conflict->property_name)
    new_conflict->property_name = apr_pstrdup(pool, conflict->property_name);
  if (conflict->mime_type)
    new_conflict->mime_type = apr_pstrdup(pool, conflict->mime_type);
  /* NOTE: We cannot make a deep copy of adm_access. */
  if (conflict->base_file)
    new_conflict->base_file = apr_pstrdup(pool, conflict->base_file);
  if (conflict->their_file)
    new_conflict->their_file = apr_pstrdup(pool, conflict->their_file);
  if (conflict->my_file)
    new_conflict->my_file = apr_pstrdup(pool, conflict->my_file);
  if (conflict->merged_file)
    new_conflict->merged_file = apr_pstrdup(pool, conflict->merged_file);
  if (conflict->src_left_version)
    new_conflict->src_left_version =
      svn_wc_conflict_version_dup(conflict->src_left_version, pool);
  if (conflict->src_right_version)
    new_conflict->src_right_version =
      svn_wc_conflict_version_dup(conflict->src_right_version, pool);

  return new_conflict;
}


svn_wc_status2_t *
svn_wc_dup_status2(const svn_wc_status2_t *orig_stat,
                   apr_pool_t *pool)
{
  svn_wc_status2_t *new_stat = apr_palloc(pool, sizeof(*new_stat));

  /* Shallow copy all members. */
  *new_stat = *orig_stat;

  /* Now go back and dup the deep items into this pool. */
  if (orig_stat->entry)
    new_stat->entry = svn_wc_entry_dup(orig_stat->entry, pool);

  if (orig_stat->repos_lock)
    new_stat->repos_lock = svn_lock_dup(orig_stat->repos_lock, pool);

  if (orig_stat->url)
    new_stat->url = apr_pstrdup(pool, orig_stat->url);

  if (orig_stat->ood_last_cmt_author)
    new_stat->ood_last_cmt_author
      = apr_pstrdup(pool, orig_stat->ood_last_cmt_author);

  if (orig_stat->tree_conflict)
    new_stat->tree_conflict
      = conflict_description_dup(orig_stat->tree_conflict, pool);

  /* Return the new hotness. */
  return new_stat;
}

svn_wc_status_t *
svn_wc_dup_status(const svn_wc_status_t *orig_stat,
                  apr_pool_t *pool)
{
  svn_wc_status_t *new_stat = apr_palloc(pool, sizeof(*new_stat));

  /* Shallow copy all members. */
  *new_stat = *orig_stat;

  /* Now go back and dup the deep item into this pool. */
  if (orig_stat->entry)
    new_stat->entry = svn_wc_entry_dup(orig_stat->entry, pool);

  /* Return the new hotness. */
  return new_stat;
}

svn_error_t *
svn_wc_get_ignores(apr_array_header_t **patterns,
                   apr_hash_t *config,
                   svn_wc_adm_access_t *adm_access,
                   apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  const char *local_abspath;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath,
                                  svn_wc_adm_access_path(adm_access), pool));

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access),
                                         pool));

  SVN_ERR(svn_wc_get_ignores2(patterns, wc_ctx, local_abspath, config, pool,
                              pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_status2(svn_wc_status2_t **status,
               const char *path,
               svn_wc_adm_access_t *adm_access,
               apr_pool_t *pool)
{
  const char *local_abspath;
  svn_wc_context_t *wc_ctx;
  svn_wc_status3_t *stat3;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access),
                                         pool));

  SVN_ERR(svn_wc_status3(&stat3, wc_ctx, local_abspath, pool, pool));
  SVN_ERR(svn_wc__status2_from_3(status, stat3, wc_ctx, local_abspath,
                                 pool, pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}


/*** From update_editor.c ***/

svn_error_t *
svn_wc_add_repos_file3(const char *dst_path,
                       svn_wc_adm_access_t *adm_access,
                       svn_stream_t *new_base_contents,
                       svn_stream_t *new_contents,
                       apr_hash_t *new_base_props,
                       apr_hash_t *new_props,
                       const char *copyfrom_url,
                       svn_revnum_t copyfrom_rev,
                       svn_cancel_func_t cancel_func,
                       void *cancel_baton,
                       svn_wc_notify_func2_t notify_func,
                       void *notify_baton,
                       apr_pool_t *pool)
{
  const char *local_abspath;
  svn_wc_context_t *wc_ctx;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, dst_path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access),
                                         pool));

  SVN_ERR(svn_wc_add_repos_file4(wc_ctx,
                                 local_abspath,
                                 new_base_contents,
                                 new_contents,
                                 new_base_props,
                                 new_props,
                                 copyfrom_url,
                                 copyfrom_rev,
                                 cancel_func, cancel_baton,
                                 pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_add_repos_file2(const char *dst_path,
                       svn_wc_adm_access_t *adm_access,
                       const char *new_text_base_path,
                       const char *new_text_path,
                       apr_hash_t *new_base_props,
                       apr_hash_t *new_props,
                       const char *copyfrom_url,
                       svn_revnum_t copyfrom_rev,
                       apr_pool_t *pool)
{
  svn_stream_t *new_base_contents;
  svn_stream_t *new_contents = NULL;

  SVN_ERR(svn_stream_open_readonly(&new_base_contents, new_text_base_path,
                                   pool, pool));

  if (new_text_path)
    {
      /* NOTE: the specified path may *not* be under version control.
         It is most likely sitting in .svn/tmp/. Thus, we cannot use the
         typical WC functions to access "special", "keywords" or "EOL"
         information. We need to look at the properties given to us. */

      /* If the new file is special, then we can simply open the given
         contents since it is already in normal form. */
      if (apr_hash_get(new_props,
                       SVN_PROP_SPECIAL, APR_HASH_KEY_STRING) != NULL)
        {
          SVN_ERR(svn_stream_open_readonly(&new_contents, new_text_path,
                                           pool, pool));
        }
      else
        {
          /* The new text contents need to be detrans'd into normal form. */
          svn_subst_eol_style_t eol_style;
          const char *eol_str;
          apr_hash_t *keywords = NULL;
          svn_string_t *list;

          list = apr_hash_get(new_props,
                              SVN_PROP_KEYWORDS, APR_HASH_KEY_STRING);
          if (list != NULL)
            {
              /* Since we are detranslating, all of the keyword values
                 can be "". */
              SVN_ERR(svn_subst_build_keywords2(&keywords,
                                                list->data,
                                                "", "", 0, "",
                                                pool));
              if (apr_hash_count(keywords) == 0)
                keywords = NULL;
            }

          svn_subst_eol_style_from_value(&eol_style, &eol_str,
                                         apr_hash_get(new_props,
                                                      SVN_PROP_EOL_STYLE,
                                                      APR_HASH_KEY_STRING));

          if (svn_subst_translation_required(eol_style, eol_str, keywords,
                                             FALSE, FALSE))
            {
              SVN_ERR(svn_subst_stream_detranslated(&new_contents,
                                                    new_text_path,
                                                    eol_style, eol_str,
                                                    FALSE,
                                                    keywords,
                                                    FALSE,
                                                    pool));
            }
          else
            {
              SVN_ERR(svn_stream_open_readonly(&new_contents, new_text_path,
                                               pool, pool));
            }
        }
    }

  SVN_ERR(svn_wc_add_repos_file3(dst_path, adm_access,
                                 new_base_contents, new_contents,
                                 new_base_props, new_props,
                                 copyfrom_url, copyfrom_rev,
                                 NULL, NULL, NULL, NULL,
                                 pool));

  /* The API contract states that the text files will be removed upon
     successful completion. add_repos_file3() does not remove the files
     since it only has streams on them. Toss 'em now. */
  svn_error_clear(svn_io_remove_file(new_text_base_path, pool));
  if (new_text_path)
    svn_error_clear(svn_io_remove_file(new_text_path, pool));

  return SVN_NO_ERROR;
}


svn_error_t *
svn_wc_add_repos_file(const char *dst_path,
                      svn_wc_adm_access_t *adm_access,
                      const char *new_text_path,
                      apr_hash_t *new_props,
                      const char *copyfrom_url,
                      svn_revnum_t copyfrom_rev,
                      apr_pool_t *pool)
{
  return svn_wc_add_repos_file2(dst_path, adm_access,
                                new_text_path, NULL,
                                new_props, NULL,
                                copyfrom_url, copyfrom_rev,
                                pool);
}

svn_error_t *
svn_wc_get_actual_target(const char *path,
                         const char **anchor,
                         const char **target,
                         apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;

  SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool));
  SVN_ERR(svn_wc_get_actual_target2(anchor, target, wc_ctx, path, pool, pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_is_wc_root(svn_boolean_t *wc_root,
                  const char *path,
                  svn_wc_adm_access_t *adm_access,
                  apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  const char *local_abspath;
  svn_error_t *err;

  /* Subversion <= 1.6 said that '.' or a drive root is a WC root. */
  if (svn_path_is_empty(path) || svn_dirent_is_root(path, strlen(path)))
    {
      *wc_root = TRUE;
      return SVN_NO_ERROR;
    }

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access),
                                         pool));

  err = svn_wc_is_wc_root2(wc_root, wc_ctx, local_abspath, pool);

  if (err
      && (err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY
          || err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND))
    {
      /* Subversion <= 1.6 said that an unversioned path is a WC root. */
      svn_error_clear(err);
      *wc_root = TRUE;
    }
  else
    SVN_ERR(err);

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_get_update_editor3(svn_revnum_t *target_revision,
                          svn_wc_adm_access_t *anchor,
                          const char *target,
                          svn_boolean_t use_commit_times,
                          svn_depth_t depth,
                          svn_boolean_t depth_is_sticky,
                          svn_boolean_t allow_unver_obstructions,
                          svn_wc_notify_func2_t notify_func,
                          void *notify_baton,
                          svn_cancel_func_t cancel_func,
                          void *cancel_baton,
                          svn_wc_conflict_resolver_func_t conflict_func,
                          void *conflict_baton,
                          svn_wc_get_file_t fetch_func,
                          void *fetch_baton,
                          const char *diff3_cmd,
                          const apr_array_header_t *preserved_exts,
                          const svn_delta_editor_t **editor,
                          void **edit_baton,
                          svn_wc_traversal_info_t *traversal_info,
                          apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *db = svn_wc__adm_get_db(anchor);
  svn_wc_external_update_t external_func = NULL;
  struct traversal_info_update_baton *eb = NULL;
  struct conflict_func_1to2_baton *cfw = NULL;

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, db, pool));

  if (traversal_info)
    {
      eb = apr_palloc(pool, sizeof(*eb));
      eb->db = db;
      eb->traversal = traversal_info;
      external_func = traversal_info_update;
    }

  if (conflict_func)
    {
      cfw = apr_pcalloc(pool, sizeof(*cfw));
      cfw->inner_func = conflict_func;
      cfw->inner_baton = conflict_baton;
    }

  if (diff3_cmd)
    SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, pool));

  SVN_ERR(svn_wc_get_update_editor4(editor, edit_baton,
                                    target_revision,
                                    wc_ctx,
                                    svn_wc__adm_access_abspath(anchor),
                                    target,
                                    use_commit_times,
                                    depth, depth_is_sticky,
                                    allow_unver_obstructions,
                                    TRUE /* adds_as_modification */,
                                    FALSE /* server_performs_filtering */,
                                    FALSE /* clean_checkout */,
                                    diff3_cmd,
                                    preserved_exts,
                                    NULL, NULL, /* fetch_dirents_func, baton */
                                    conflict_func ? conflict_func_1to2_wrapper
                                                  : NULL,
                                    cfw,
                                    external_func, eb,
                                    cancel_func, cancel_baton,
                                    notify_func, notify_baton,
                                    pool, pool));

  /* We can't destroy wc_ctx here, because the editor needs it while it's
     driven. */
  return SVN_NO_ERROR;
}

svn_error_t *
svn_wc_get_update_editor2(svn_revnum_t *target_revision,
                          svn_wc_adm_access_t *anchor,
                          const char *target,
                          svn_boolean_t use_commit_times,
                          svn_boolean_t recurse,
                          svn_wc_notify_func2_t notify_func,
                          void *notify_baton,
                          svn_cancel_func_t cancel_func,
                          void *cancel_baton,
                          const char *diff3_cmd,
                          const svn_delta_editor_t **editor,
                          void **edit_baton,
                          svn_wc_traversal_info_t *traversal_info,
                          apr_pool_t *pool)
{
  return svn_wc_get_update_editor3(target_revision, anchor, target,
                                   use_commit_times,
                                   SVN_DEPTH_INFINITY_OR_FILES(recurse), FALSE,
                                   FALSE, notify_func, notify_baton,
                                   cancel_func, cancel_baton, NULL, NULL,
                                   NULL, NULL,
                                   diff3_cmd, NULL, editor, edit_baton,
                                   traversal_info, pool);
}

svn_error_t *
svn_wc_get_update_editor(svn_revnum_t *target_revision,
                         svn_wc_adm_access_t *anchor,
                         const char *target,
                         svn_boolean_t use_commit_times,
                         svn_boolean_t recurse,
                         svn_wc_notify_func_t notify_func,
                         void *notify_baton,
                         svn_cancel_func_t cancel_func,
                         void *cancel_baton,
                         const char *diff3_cmd,
                         const svn_delta_editor_t **editor,
                         void **edit_baton,
                         svn_wc_traversal_info_t *traversal_info,
                         apr_pool_t *pool)
{
  /* This baton must live beyond this function. Alloc on heap.  */
  struct compat_notify_baton_t *nb = apr_palloc(pool, sizeof(*nb));

  nb->func = notify_func;
  nb->baton = notify_baton;

  return svn_wc_get_update_editor3(target_revision, anchor, target,
                                   use_commit_times,
                                   SVN_DEPTH_INFINITY_OR_FILES(recurse), FALSE,
                                   FALSE, compat_call_notify_func, nb,
                                   cancel_func, cancel_baton, NULL, NULL,
                                   NULL, NULL,
                                   diff3_cmd, NULL, editor, edit_baton,
                                   traversal_info, pool);
}

svn_error_t *
svn_wc_get_switch_editor3(svn_revnum_t *target_revision,
                          svn_wc_adm_access_t *anchor,
                          const char *target,
                          const char *switch_url,
                          svn_boolean_t use_commit_times,
                          svn_depth_t depth,
                          svn_boolean_t depth_is_sticky,
                          svn_boolean_t allow_unver_obstructions,
                          svn_wc_notify_func2_t notify_func,
                          void *notify_baton,
                          svn_cancel_func_t cancel_func,
                          void *cancel_baton,
                          svn_wc_conflict_resolver_func_t conflict_func,
                          void *conflict_baton,
                          const char *diff3_cmd,
                          const apr_array_header_t *preserved_exts,
                          const svn_delta_editor_t **editor,
                          void **edit_baton,
                          svn_wc_traversal_info_t *traversal_info,
                          apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *db = svn_wc__adm_get_db(anchor);
  svn_wc_external_update_t external_func = NULL;
  struct traversal_info_update_baton *eb = NULL;
  struct conflict_func_1to2_baton *cfw = NULL;

  SVN_ERR_ASSERT(switch_url && svn_uri_is_canonical(switch_url, pool));

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, db, pool));

  if (traversal_info)
    {
      eb = apr_palloc(pool, sizeof(*eb));
      eb->db = db;
      eb->traversal = traversal_info;
      external_func = traversal_info_update;
    }

  if (conflict_func)
    {
      cfw = apr_pcalloc(pool, sizeof(*cfw));
      cfw->inner_func = conflict_func;
      cfw->inner_baton = conflict_baton;
    }

  if (diff3_cmd)
    SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, pool));

  SVN_ERR(svn_wc_get_switch_editor4(editor, edit_baton,
                                    target_revision,
                                    wc_ctx,
                                    svn_wc__adm_access_abspath(anchor),
                                    target, switch_url,
                                    use_commit_times,
                                    depth, depth_is_sticky,
                                    allow_unver_obstructions,
                                    FALSE /* server_performs_filtering */,
                                    diff3_cmd,
                                    preserved_exts,
                                    NULL, NULL, /* fetch_dirents_func, baton */
                                    conflict_func ? conflict_func_1to2_wrapper
                                                  : NULL,
                                    cfw,
                                    external_func, eb,
                                    cancel_func, cancel_baton,
                                    notify_func, notify_baton,
                                    pool, pool));

  /* We can't destroy wc_ctx here, because the editor needs it while it's
     driven. */
  return SVN_NO_ERROR;
}

svn_error_t *
svn_wc_get_switch_editor2(svn_revnum_t *target_revision,
                          svn_wc_adm_access_t *anchor,
                          const char *target,
                          const char *switch_url,
                          svn_boolean_t use_commit_times,
                          svn_boolean_t recurse,
                          svn_wc_notify_func2_t notify_func,
                          void *notify_baton,
                          svn_cancel_func_t cancel_func,
                          void *cancel_baton,
                          const char *diff3_cmd,
                          const svn_delta_editor_t **editor,
                          void **edit_baton,
                          svn_wc_traversal_info_t *traversal_info,
                          apr_pool_t *pool)
{
  SVN_ERR_ASSERT(switch_url);

  return svn_wc_get_switch_editor3(target_revision, anchor, target,
                                   switch_url, use_commit_times,
                                   SVN_DEPTH_INFINITY_OR_FILES(recurse), FALSE,
                                   FALSE, notify_func, notify_baton,
                                   cancel_func, cancel_baton,
                                   NULL, NULL, diff3_cmd,
                                   NULL, editor, edit_baton, traversal_info,
                                   pool);
}

svn_error_t *
svn_wc_get_switch_editor(svn_revnum_t *target_revision,
                         svn_wc_adm_access_t *anchor,
                         const char *target,
                         const char *switch_url,
                         svn_boolean_t use_commit_times,
                         svn_boolean_t recurse,
                         svn_wc_notify_func_t notify_func,
                         void *notify_baton,
                         svn_cancel_func_t cancel_func,
                         void *cancel_baton,
                         const char *diff3_cmd,
                         const svn_delta_editor_t **editor,
                         void **edit_baton,
                         svn_wc_traversal_info_t *traversal_info,
                         apr_pool_t *pool)
{
  /* This baton must live beyond this function. Alloc on heap.  */
  struct compat_notify_baton_t *nb = apr_palloc(pool, sizeof(*nb));

  nb->func = notify_func;
  nb->baton = notify_baton;

  return svn_wc_get_switch_editor3(target_revision, anchor, target,
                                   switch_url, use_commit_times,
                                   SVN_DEPTH_INFINITY_OR_FILES(recurse), FALSE,
                                   FALSE, compat_call_notify_func, nb,
                                   cancel_func, cancel_baton,
                                   NULL, NULL, diff3_cmd,
                                   NULL, editor, edit_baton, traversal_info,
                                   pool);
}


svn_wc_external_item_t *
svn_wc_external_item_dup(const svn_wc_external_item_t *item,
                         apr_pool_t *pool)
{
  svn_wc_external_item_t *new_item = apr_palloc(pool, sizeof(*new_item));

  *new_item = *item;

  if (new_item->target_dir)
    new_item->target_dir = apr_pstrdup(pool, new_item->target_dir);

  if (new_item->url)
    new_item->url = apr_pstrdup(pool, new_item->url);

  return new_item;
}


svn_wc_traversal_info_t *
svn_wc_init_traversal_info(apr_pool_t *pool)
{
  svn_wc_traversal_info_t *ti = apr_palloc(pool, sizeof(*ti));

  ti->pool           = pool;
  ti->externals_old  = apr_hash_make(pool);
  ti->externals_new  = apr_hash_make(pool);
  ti->depths         = apr_hash_make(pool);

  return ti;
}


void
svn_wc_edited_externals(apr_hash_t **externals_old,
                        apr_hash_t **externals_new,
                        svn_wc_traversal_info_t *traversal_info)
{
  *externals_old = traversal_info->externals_old;
  *externals_new = traversal_info->externals_new;
}


void
svn_wc_traversed_depths(apr_hash_t **depths,
                        svn_wc_traversal_info_t *traversal_info)
{
  *depths = traversal_info->depths;
}


/*** From lock.c ***/

/* To preserve API compatibility with Subversion 1.0.0 */
svn_error_t *
svn_wc_adm_open(svn_wc_adm_access_t **adm_access,
                svn_wc_adm_access_t *associated,
                const char *path,
                svn_boolean_t write_lock,
                svn_boolean_t tree_lock,
                apr_pool_t *pool)
{
  return svn_wc_adm_open3(adm_access, associated, path, write_lock,
                          (tree_lock ? -1 : 0), NULL, NULL, pool);
}

svn_error_t *
svn_wc_adm_open2(svn_wc_adm_access_t **adm_access,
                 svn_wc_adm_access_t *associated,
                 const char *path,
                 svn_boolean_t write_lock,
                 int levels_to_lock,
                 apr_pool_t *pool)
{
  return svn_wc_adm_open3(adm_access, associated, path, write_lock,
                          levels_to_lock, NULL, NULL, pool);
}

svn_error_t *
svn_wc_adm_probe_open(svn_wc_adm_access_t **adm_access,
                      svn_wc_adm_access_t *associated,
                      const char *path,
                      svn_boolean_t write_lock,
                      svn_boolean_t tree_lock,
                      apr_pool_t *pool)
{
  return svn_wc_adm_probe_open3(adm_access, associated, path,
                                write_lock, (tree_lock ? -1 : 0),
                                NULL, NULL, pool);
}


svn_error_t *
svn_wc_adm_probe_open2(svn_wc_adm_access_t **adm_access,
                       svn_wc_adm_access_t *associated,
                       const char *path,
                       svn_boolean_t write_lock,
                       int levels_to_lock,
                       apr_pool_t *pool)
{
  return svn_wc_adm_probe_open3(adm_access, associated, path, write_lock,
                                levels_to_lock, NULL, NULL, pool);
}

svn_error_t *
svn_wc_adm_probe_try2(svn_wc_adm_access_t **adm_access,
                      svn_wc_adm_access_t *associated,
                      const char *path,
                      svn_boolean_t write_lock,
                      int levels_to_lock,
                      apr_pool_t *pool)
{
  return svn_wc_adm_probe_try3(adm_access, associated, path, write_lock,
                               levels_to_lock, NULL, NULL, pool);
}

svn_error_t *
svn_wc_adm_probe_try(svn_wc_adm_access_t **adm_access,
                     svn_wc_adm_access_t *associated,
                     const char *path,
                     svn_boolean_t write_lock,
                     svn_boolean_t tree_lock,
                     apr_pool_t *pool)
{
  return svn_wc_adm_probe_try3(adm_access, associated, path, write_lock,
                               (tree_lock ? -1 : 0), NULL, NULL, pool);
}

svn_error_t *
svn_wc_adm_close(svn_wc_adm_access_t *adm_access)
{
  /* This is the only pool we have access to. */
  apr_pool_t *scratch_pool = svn_wc_adm_access_pool(adm_access);

  return svn_wc_adm_close2(adm_access, scratch_pool);
}

svn_error_t *
svn_wc_locked(svn_boolean_t *locked,
              const char *path,
              apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  const char *local_abspath;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool));

  SVN_ERR(svn_wc_locked2(NULL, locked, wc_ctx, local_abspath, pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_check_wc(const char *path,
                int *wc_format,
                apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  const char *local_abspath;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool));

  SVN_ERR(svn_wc_check_wc2(wc_format, wc_ctx, local_abspath, pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}


/*** From translate.c ***/

svn_error_t *
svn_wc_translated_file(const char **xlated_p,
                       const char *vfile,
                       svn_wc_adm_access_t *adm_access,
                       svn_boolean_t force_repair,
                       apr_pool_t *pool)
{
  return svn_wc_translated_file2(xlated_p, vfile, vfile, adm_access,
                                 SVN_WC_TRANSLATE_TO_NF
                                 | (force_repair ?
                                    SVN_WC_TRANSLATE_FORCE_EOL_REPAIR : 0),
                                 pool);
}

svn_error_t *
svn_wc_translated_stream(svn_stream_t **stream,
                         const char *path,
                         const char *versioned_file,
                         svn_wc_adm_access_t *adm_access,
                         apr_uint32_t flags,
                         apr_pool_t *pool)
{
  const char *local_abspath;
  const char *versioned_abspath;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_dirent_get_absolute(&versioned_abspath, versioned_file, pool));

  return svn_error_trace(
    svn_wc__internal_translated_stream(stream, svn_wc__adm_get_db(adm_access),
                                       local_abspath, versioned_abspath, flags,
                                       pool, pool));
}

svn_error_t *
svn_wc_translated_file2(const char **xlated_path,
                        const char *src,
                        const char *versioned_file,
                        svn_wc_adm_access_t *adm_access,
                        apr_uint32_t flags,
                        apr_pool_t *pool)
{
  const char *versioned_abspath;
  const char *root;
  const char *tmp_root;
  const char *src_abspath;

  SVN_ERR(svn_dirent_get_absolute(&versioned_abspath, versioned_file, pool));
  SVN_ERR(svn_dirent_get_absolute(&src_abspath, src, pool));

  SVN_ERR(svn_wc__internal_translated_file(xlated_path, src_abspath,
                                           svn_wc__adm_get_db(adm_access),
                                           versioned_abspath,
                                           flags, NULL, NULL, pool, pool));

  if (strcmp(*xlated_path, src_abspath) == 0)
    *xlated_path = src;
  else if (! svn_dirent_is_absolute(versioned_file))
    {
      SVN_ERR(svn_io_temp_dir(&tmp_root, pool));
      if (! svn_dirent_is_child(tmp_root, *xlated_path, pool))
        {
          SVN_ERR(svn_dirent_get_absolute(&root, "", pool));

          if (svn_dirent_is_child(root, *xlated_path, pool))
            *xlated_path = svn_dirent_is_child(root, *xlated_path, pool);
        }
    }

  return SVN_NO_ERROR;
}

/*** From relocate.c ***/
svn_error_t *
svn_wc_relocate3(const char *path,
                 svn_wc_adm_access_t *adm_access,
                 const char *from,
                 const char *to,
                 svn_boolean_t recurse,
                 svn_wc_relocation_validator3_t validator,
                 void *validator_baton,
                 apr_pool_t *pool)
{
  const char *local_abspath;
  svn_wc_context_t *wc_ctx;

  if (! recurse)
    SVN_ERR(svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                             _("Non-recursive relocation not supported")));

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access),
                                         pool));

  SVN_ERR(svn_wc_relocate4(wc_ctx, local_abspath, from, to,
                           validator, validator_baton, pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

/* Compatibility baton and wrapper. */
struct compat2_baton {
  svn_wc_relocation_validator2_t validator;
  void *baton;
};

/* Compatibility baton and wrapper. */
struct compat_baton {
  svn_wc_relocation_validator_t validator;
  void *baton;
};

/* This implements svn_wc_relocate_validator3_t. */
static svn_error_t *
compat2_validator(void *baton,
                  const char *uuid,
                  const char *url,
                  const char *root_url,
                  apr_pool_t *pool)
{
  struct compat2_baton *cb = baton;
  /* The old callback type doesn't set root_url. */
  return cb->validator(cb->baton, uuid,
                       (root_url ? root_url : url), (root_url != NULL),
                       pool);
}

/* This implements svn_wc_relocate_validator3_t. */
static svn_error_t *
compat_validator(void *baton,
                 const char *uuid,
                 const char *url,
                 const char *root_url,
                 apr_pool_t *pool)
{
  struct compat_baton *cb = baton;
  /* The old callback type doesn't allow uuid to be NULL. */
  if (uuid)
    return cb->validator(cb->baton, uuid, url);
  return SVN_NO_ERROR;
}

svn_error_t *
svn_wc_relocate2(const char *path,
                 svn_wc_adm_access_t *adm_access,
                 const char *from,
                 const char *to,
                 svn_boolean_t recurse,
                 svn_wc_relocation_validator2_t validator,
                 void *validator_baton,
                 apr_pool_t *pool)
{
  struct compat2_baton cb;

  cb.validator = validator;
  cb.baton = validator_baton;

  return svn_wc_relocate3(path, adm_access, from, to, recurse,
                          compat2_validator, &cb, pool);
}

svn_error_t *
svn_wc_relocate(const char *path,
                svn_wc_adm_access_t *adm_access,
                const char *from,
                const char *to,
                svn_boolean_t recurse,
                svn_wc_relocation_validator_t validator,
                void *validator_baton,
                apr_pool_t *pool)
{
  struct compat_baton cb;

  cb.validator = validator;
  cb.baton = validator_baton;

  return svn_wc_relocate3(path, adm_access, from, to, recurse,
                          compat_validator, &cb, pool);
}


/*** From log.c ***/

svn_error_t *
svn_wc_cleanup2(const char *path,
                const char *diff3_cmd,
                svn_cancel_func_t cancel_func,
                void *cancel_baton,
                apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  const char *local_abspath;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, pool, pool));

  SVN_ERR(svn_wc_cleanup3(wc_ctx, local_abspath, cancel_func,
                          cancel_baton, pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_cleanup(const char *path,
               svn_wc_adm_access_t *optional_adm_access,
               const char *diff3_cmd,
               svn_cancel_func_t cancel_func,
               void *cancel_baton,
               apr_pool_t *pool)
{
  return svn_wc_cleanup2(path, diff3_cmd, cancel_func, cancel_baton, pool);
}

/*** From questions.c ***/

svn_error_t *
svn_wc_has_binary_prop(svn_boolean_t *has_binary_prop,
                       const char *path,
                       svn_wc_adm_access_t *adm_access,
                       apr_pool_t *pool)
{
  svn_wc__db_t *db = svn_wc__adm_get_db(adm_access);
  const char *local_abspath;
  const svn_string_t *value;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));

  SVN_ERR(svn_wc__internal_propget(&value, db, local_abspath,
                                   SVN_PROP_MIME_TYPE,
                                   pool, pool));

  if (value && (svn_mime_type_is_binary(value->data)))
    *has_binary_prop = TRUE;
  else
    *has_binary_prop = FALSE;

  return SVN_NO_ERROR;
}

svn_error_t *
svn_wc_conflicted_p2(svn_boolean_t *text_conflicted_p,
                     svn_boolean_t *prop_conflicted_p,
                     svn_boolean_t *tree_conflicted_p,
                     const char *path,
                     svn_wc_adm_access_t *adm_access,
                     apr_pool_t *pool)
{
  const char *local_abspath;
  svn_wc_context_t *wc_ctx;
  svn_error_t *err;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */,
                                         svn_wc__adm_get_db(adm_access),
                                         pool));

  err = svn_wc_conflicted_p3(text_conflicted_p, prop_conflicted_p,
                             tree_conflicted_p, wc_ctx, local_abspath, pool);

  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
    {
      svn_error_clear(err);

      if (text_conflicted_p)
        *text_conflicted_p = FALSE;
      if (prop_conflicted_p)
        *prop_conflicted_p = FALSE;
      if (tree_conflicted_p)
        *tree_conflicted_p = FALSE;
    }
  else if (err)
    return err;

  return SVN_NO_ERROR;
}

svn_error_t *
svn_wc_conflicted_p(svn_boolean_t *text_conflicted_p,
                    svn_boolean_t *prop_conflicted_p,
                    const char *dir_path,
                    const svn_wc_entry_t *entry,
                    apr_pool_t *pool)
{
  svn_node_kind_t kind;
  const char *path;

  *text_conflicted_p = FALSE;
  *prop_conflicted_p = FALSE;

  if (entry->conflict_old)
    {
      path = svn_dirent_join(dir_path, entry->conflict_old, pool);
      SVN_ERR(svn_io_check_path(path, &kind, pool));
      *text_conflicted_p = (kind == svn_node_file);
    }

  if ((! *text_conflicted_p) && (entry->conflict_new))
    {
      path = svn_dirent_join(dir_path, entry->conflict_new, pool);
      SVN_ERR(svn_io_check_path(path, &kind, pool));
      *text_conflicted_p = (kind == svn_node_file);
    }

  if ((! *text_conflicted_p) && (entry->conflict_wrk))
    {
      path = svn_dirent_join(dir_path, entry->conflict_wrk, pool);
      SVN_ERR(svn_io_check_path(path, &kind, pool));
      *text_conflicted_p = (kind == svn_node_file);
    }

  if (entry->prejfile)
    {
      path = svn_dirent_join(dir_path, entry->prejfile, pool);
      SVN_ERR(svn_io_check_path(path, &kind, pool));
      *prop_conflicted_p = (kind == svn_node_file);
    }

  return SVN_NO_ERROR;
}

svn_error_t *
svn_wc_text_modified_p(svn_boolean_t *modified_p,
                       const char *filename,
                       svn_boolean_t force_comparison,
                       svn_wc_adm_access_t *adm_access,
                       apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *db = svn_wc__adm_get_db(adm_access);
  const char *local_abspath;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, filename, pool));
  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, db, pool));

  SVN_ERR(svn_wc_text_modified_p2(modified_p, wc_ctx, local_abspath,
                                  force_comparison, pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}


/*** From copy.c ***/
svn_error_t *
svn_wc_copy2(const char *src,
             svn_wc_adm_access_t *dst_parent,
             const char *dst_basename,
             svn_cancel_func_t cancel_func,
             void *cancel_baton,
             svn_wc_notify_func2_t notify_func,
             void *notify_baton,
             apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *wc_db = svn_wc__adm_get_db(dst_parent);
  const char *src_abspath;
  const char *dst_abspath;

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, wc_db, pool));
  SVN_ERR(svn_dirent_get_absolute(&src_abspath, src, pool));

  dst_abspath = svn_dirent_join(svn_wc__adm_access_abspath(dst_parent),
                                dst_basename, pool);

  SVN_ERR(svn_wc_copy3(wc_ctx,
                       src_abspath,
                       dst_abspath,
                       FALSE /* metadata_only */,
                       cancel_func, cancel_baton,
                       notify_func, notify_baton,
                       pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_copy(const char *src_path,
            svn_wc_adm_access_t *dst_parent,
            const char *dst_basename,
            svn_cancel_func_t cancel_func,
            void *cancel_baton,
            svn_wc_notify_func_t notify_func,
            void *notify_baton,
            apr_pool_t *pool)
{
  struct compat_notify_baton_t nb;

  nb.func = notify_func;
  nb.baton = notify_baton;

  return svn_wc_copy2(src_path, dst_parent, dst_basename, cancel_func,
                      cancel_baton, compat_call_notify_func,
                      &nb, pool);
}


/*** From merge.c ***/

svn_error_t *
svn_wc_merge3(enum svn_wc_merge_outcome_t *merge_outcome,
              const char *left,
              const char *right,
              const char *merge_target,
              svn_wc_adm_access_t *adm_access,
              const char *left_label,
              const char *right_label,
              const char *target_label,
              svn_boolean_t dry_run,
              const char *diff3_cmd,
              const apr_array_header_t *merge_options,
              const apr_array_header_t *prop_diff,
              svn_wc_conflict_resolver_func_t conflict_func,
              void *conflict_baton,
              apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *db = svn_wc__adm_get_db(adm_access);
  const char *left_abspath, *right_abspath, *target_abspath;
  struct conflict_func_1to2_baton cfw;

  SVN_ERR(svn_dirent_get_absolute(&left_abspath, left, pool));
  SVN_ERR(svn_dirent_get_absolute(&right_abspath, right, pool));
  SVN_ERR(svn_dirent_get_absolute(&target_abspath, merge_target, pool));

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */, db, pool));

  cfw.inner_func = conflict_func;
  cfw.inner_baton = conflict_baton;

  if (diff3_cmd)
    SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, pool));

  SVN_ERR(svn_wc_merge4(merge_outcome,
                        wc_ctx,
                        left_abspath,
                        right_abspath,
                        target_abspath,
                        left_label,
                        right_label,
                        target_label,
                        NULL,
                        NULL,
                        dry_run,
                        diff3_cmd,
                        merge_options,
                        prop_diff,
                        conflict_func ? conflict_func_1to2_wrapper : NULL,
                        &cfw,
                        NULL, NULL,
                        pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

svn_error_t *
svn_wc_merge2(enum svn_wc_merge_outcome_t *merge_outcome,
              const char *left,
              const char *right,
              const char *merge_target,
              svn_wc_adm_access_t *adm_access,
              const char *left_label,
              const char *right_label,
              const char *target_label,
              svn_boolean_t dry_run,
              const char *diff3_cmd,
              const apr_array_header_t *merge_options,
              apr_pool_t *pool)
{
  return svn_wc_merge3(merge_outcome,
                       left, right, merge_target, adm_access,
                       left_label, right_label, target_label,
                       dry_run, diff3_cmd, merge_options, NULL,
                       NULL, NULL, pool);
}

svn_error_t *
svn_wc_merge(const char *left,
             const char *right,
             const char *merge_target,
             svn_wc_adm_access_t *adm_access,
             const char *left_label,
             const char *right_label,
             const char *target_label,
             svn_boolean_t dry_run,
             enum svn_wc_merge_outcome_t *merge_outcome,
             const char *diff3_cmd,
             apr_pool_t *pool)
{
  return svn_wc_merge3(merge_outcome,
                       left, right, merge_target, adm_access,
                       left_label, right_label, target_label,
                       dry_run, diff3_cmd, NULL, NULL, NULL,
                       NULL, pool);
}


/*** From util.c ***/

svn_wc_conflict_description_t *
svn_wc_conflict_description_create_text(const char *path,
                                        svn_wc_adm_access_t *adm_access,
                                        apr_pool_t *pool)
{
  svn_wc_conflict_description_t *conflict;

  conflict = apr_pcalloc(pool, sizeof(*conflict));
  conflict->path = path;
  conflict->node_kind = svn_node_file;
  conflict->kind = svn_wc_conflict_kind_text;
  conflict->access = adm_access;
  conflict->action = svn_wc_conflict_action_edit;
  conflict->reason = svn_wc_conflict_reason_edited;
  return conflict;
}

svn_wc_conflict_description_t *
svn_wc_conflict_description_create_prop(const char *path,
                                        svn_wc_adm_access_t *adm_access,
                                        svn_node_kind_t node_kind,
                                        const char *property_name,
                                        apr_pool_t *pool)
{
  svn_wc_conflict_description_t *conflict;

  conflict = apr_pcalloc(pool, sizeof(*conflict));
  conflict->path = path;
  conflict->node_kind = node_kind;
  conflict->kind = svn_wc_conflict_kind_property;
  conflict->access = adm_access;
  conflict->property_name = property_name;
  return conflict;
}

svn_wc_conflict_description_t *
svn_wc_conflict_description_create_tree(
                            const char *path,
                            svn_wc_adm_access_t *adm_access,
                            svn_node_kind_t node_kind,
                            svn_wc_operation_t operation,
                            svn_wc_conflict_version_t *src_left_version,
                            svn_wc_conflict_version_t *src_right_version,
                            apr_pool_t *pool)
{
  svn_wc_conflict_description_t *conflict;

  conflict = apr_pcalloc(pool, sizeof(*conflict));
  conflict->path = path;
  conflict->node_kind = node_kind;
  conflict->kind = svn_wc_conflict_kind_tree;
  conflict->access = adm_access;
  conflict->operation = operation;
  conflict->src_left_version = src_left_version;
  conflict->src_right_version = src_right_version;
  return conflict;
}


/*** From revision_status.c ***/

svn_error_t *
svn_wc_revision_status(svn_wc_revision_status_t **result_p,
                       const char *wc_path,
                       const char *trail_url,
                       svn_boolean_t committed,
                       svn_cancel_func_t cancel_func,
                       void *cancel_baton,
                       apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  const char *local_abspath;

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, wc_path, pool));
  SVN_ERR(svn_wc_context_create(&wc_ctx, NULL /* config */, pool, pool));

  SVN_ERR(svn_wc_revision_status2(result_p, wc_ctx, local_abspath, trail_url,
                                  committed, cancel_func, cancel_baton, pool,
                                  pool));

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}

/*** From crop.c ***/
svn_error_t *
svn_wc_crop_tree(svn_wc_adm_access_t *anchor,
                 const char *target,
                 svn_depth_t depth,
                 svn_wc_notify_func2_t notify_func,
                 void *notify_baton,
                 svn_cancel_func_t cancel_func,
                 void *cancel_baton,
                 apr_pool_t *pool)
{
  svn_wc_context_t *wc_ctx;
  svn_wc__db_t *db = svn_wc__adm_get_db(anchor);
  const char *local_abspath;

  local_abspath = svn_dirent_join(svn_wc__adm_access_abspath(anchor),
                                  target, pool);

  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, db, pool));

  if (depth == svn_depth_exclude)
    {
      SVN_ERR(svn_wc_exclude(wc_ctx,
                             local_abspath,
                             cancel_func, cancel_baton,
                             notify_func, notify_baton,
                             pool));
    }
  else
    {
      SVN_ERR(svn_wc_crop_tree2(wc_ctx,
                                local_abspath,
                                depth,
                                cancel_func, cancel_baton,
                                notify_func, notify_baton,
                                pool));
    }

  return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}
