You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/05/12 01:28:08 UTC

svn commit: r1481454 [2/5] - in /subversion/branches/fsfs-format7: ./ build/ac-macros/ build/generator/ contrib/server-side/fsfsfixer/ contrib/server-side/fsfsfixer/fixer/ subversion/bindings/ctypes-python/ subversion/bindings/swig/ subversion/bindings...

Modified: subversion/branches/fsfs-format7/subversion/libsvn_client/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_client/log.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_client/log.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_client/log.c Sat May 11 23:28:06 2013
@@ -42,6 +42,7 @@
 #include "svn_private_config.h"
 #include "private/svn_wc_private.h"
 
+#include <assert.h>
 
 /*** Getting misc. information ***/
 
@@ -260,57 +261,225 @@ limit_receiver(void *baton, svn_log_entr
   return rb->receiver(rb->baton, log_entry, pool);
 }
 
-
-/*** Public Interface. ***/
+/* Resolve the URLs or WC path in TARGETS as per the svn_client_log5 API.
 
+   The limitations on TARGETS specified by svn_client_log5 are enforced here.
+   So TARGETS can only contain a single WC path or a URL and zero or more
+   relative paths -- anything else will raise an error. 
 
-svn_error_t *
-svn_client_log5(const apr_array_header_t *targets,
-                const svn_opt_revision_t *peg_revision,
-                const apr_array_header_t *revision_ranges,
-                int limit,
-                svn_boolean_t discover_changed_paths,
-                svn_boolean_t strict_node_history,
-                svn_boolean_t include_merged_revisions,
-                const apr_array_header_t *revprops,
-                svn_log_entry_receiver_t real_receiver,
-                void *real_receiver_baton,
-                svn_client_ctx_t *ctx,
-                apr_pool_t *pool)
+   PEG_REVISION, TARGETS, and CTX are as per svn_client_log5.
+
+   If TARGETS contains a single WC path then set *RA_TARGET to the absolute
+   path of that single path if PEG_REVISION is dependent on the working copy
+   (e.g. PREV).  Otherwise set *RA_TARGET to the corresponding URL for the
+   single WC path.  Set *RELATIVE_TARGETS to an array with a single
+   element "".
+
+   If TARGETS contains only a single URL, then set *RA_TARGET to a copy of
+   that URL and *RELATIVE_TARGETS to an array with a single element "".
+
+   If TARGETS contains a single URL and one or more relative paths, then
+   set *RA_TARGET to a copy of that URL and *RELATIVE_TARGETS to a copy of
+   each relative path after the URL.
+
+   If *PEG_REVISION is svn_opt_revision_unspecified, then *PEG_REVISION is
+   set to svn_opt_revision_head for URLs or svn_opt_revision_working for a
+   WC path.
+
+   *RA_TARGET and *RELATIVE_TARGETS are allocated in RESULT_POOL. */
+static svn_error_t *
+resolve_log_targets(apr_array_header_t **relative_targets,
+                    const char **ra_target,
+                    svn_opt_revision_t *peg_revision,
+                    const apr_array_header_t *targets,
+                    svn_client_ctx_t *ctx,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
 {
-  svn_ra_session_t *ra_session;
-  const char *url_or_path;
-  svn_boolean_t has_log_revprops;
-  apr_array_header_t *condensed_targets;
-  svn_opt_revision_t session_opt_rev;
-  const char *ra_target;
-  pre_15_receiver_baton_t rb = {0};
-  apr_pool_t *iterpool;
   int i;
-  svn_opt_revision_t peg_rev;
-  svn_boolean_t url_targets = FALSE;
+  svn_boolean_t url_targets;
+
+  /* Per svn_client_log5, TARGETS contains either a URL followed by zero or
+     more relative paths, or one working copy path. */
+  const char *url_or_path = APR_ARRAY_IDX(targets, 0, const char *);
+
+  /* svn_client_log5 requires at least one target. */
+  if (targets->nelts == 0)
+    return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL,
+                            _("No valid target found"));
+
+  /* Initialize the output array.  At a minimum, we need room for one
+     (possibly empty) relpath.  Otherwise, we have to hold a relpath
+     for every item in TARGETS except the first.  */
+  *relative_targets = apr_array_make(result_pool,
+                                     MAX(1, targets->nelts - 1),
+                                     sizeof(const char *));
 
-  if (revision_ranges->nelts == 0)
+  if (svn_path_is_url(url_or_path))
     {
-      return svn_error_create
-        (SVN_ERR_CLIENT_BAD_REVISION, NULL,
-         _("Missing required revision specification"));
+      /* An unspecified PEG_REVISION for a URL path defaults
+         to svn_opt_revision_head. */
+      if (peg_revision->kind == svn_opt_revision_unspecified)
+        peg_revision->kind = svn_opt_revision_head;
+
+      /* The logic here is this: If we get passed one argument, we assume
+         it is the full URL to a file/dir we want log info for. If we get
+         a URL plus some paths, then we assume that the URL is the base,
+         and that the paths passed are relative to it.  */
+      if (targets->nelts > 1)
+        {
+          /* We have some paths, let's use them. Start after the URL.  */
+          for (i = 1; i < targets->nelts; i++)
+            {
+              const char *target;
+
+              target = APR_ARRAY_IDX(targets, i, const char *);
+
+              if (svn_path_is_url(target) || svn_dirent_is_absolute(target))
+                return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                                         _("'%s' is not a relative path"),
+                                          target);
+
+              APR_ARRAY_PUSH(*relative_targets, const char *) =
+                apr_pstrdup(result_pool, target);
+            }
+        }
+      else
+        {
+          /* If we have a single URL, then the session will be rooted at
+             it, so just send an empty string for the paths we are
+             interested in. */
+          APR_ARRAY_PUSH(*relative_targets, const char *) = "";
+        }
+
+      /* Remember that our targets are URLs. */
+      url_targets = TRUE;
     }
+  else /* WC path target. */
+    {
+      const char *target;
+      const char *target_abspath;
 
-  /* Make a copy of PEG_REVISION, we may need to change it to a
-     default value. */
-  peg_rev = *peg_revision;
+      url_targets = FALSE;
+      if (targets->nelts > 1)
+        return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+                                _("When specifying working copy paths, only "
+                                  "one target may be given"));
 
-  /* Use the passed URL, if there is one.  */
-  url_or_path = APR_ARRAY_IDX(targets, 0, const char *);
-  session_opt_rev.kind = svn_opt_revision_unspecified;
+      /* An unspecified PEG_REVISION for a working copy path defaults
+         to svn_opt_revision_working. */
+      if (peg_revision->kind == svn_opt_revision_unspecified)
+        peg_revision->kind = svn_opt_revision_working;
 
-  for (i = 0; i < revision_ranges->nelts; i++)
+      /* Get URLs for each target */
+      target = APR_ARRAY_IDX(targets, 0, const char *);
+
+      SVN_ERR(svn_dirent_get_absolute(&target_abspath, target, scratch_pool));
+      SVN_ERR(svn_wc__node_get_url(&url_or_path, ctx->wc_ctx, target_abspath,
+                                   scratch_pool, scratch_pool));
+      APR_ARRAY_PUSH(*relative_targets, const char *) = "";
+    }
+
+  /* If this is a revision type that requires access to the working copy,
+   * we use our initial target path to figure out where to root the RA
+   * session, otherwise we use our URL. */
+  if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind))
+    {
+      if (url_targets)
+        return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL,
+                                _("PREV, BASE, or COMMITTED revision "
+                                  "keywords are invalid for URL"));
+
+      else
+        SVN_ERR(svn_dirent_get_absolute(
+          ra_target, APR_ARRAY_IDX(targets, 0, const char *), result_pool));
+    }
+  else
+    {
+      *ra_target = apr_pstrdup(result_pool, url_or_path);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Keep track of oldest and youngest opt revs found.
+
+   If REV is younger than *YOUNGEST_REV, or *YOUNGEST_REV is
+   svn_opt_revision_unspecified, then set *YOUNGEST_REV equal to REV.
+
+   If REV is older than *OLDEST_REV, or *OLDEST_REV is
+   svn_opt_revision_unspecified, then set *OLDEST_REV equal to REV. */
+static void
+find_youngest_and_oldest_revs(svn_revnum_t *youngest_rev,
+                              svn_revnum_t *oldest_rev,
+                              svn_revnum_t rev)
+{
+  /* Is REV younger than YOUNGEST_REV? */
+  if (! SVN_IS_VALID_REVNUM(*youngest_rev)
+      || rev > *youngest_rev)
+    *youngest_rev = rev;
+
+  if (! SVN_IS_VALID_REVNUM(*oldest_rev)
+      || rev < *oldest_rev)
+    *oldest_rev = rev;
+}
+
+typedef struct rev_range_t
+{
+  svn_revnum_t range_start;
+  svn_revnum_t range_end;
+} rev_range_t;
+
+/* Convert array of svn_opt_revision_t ranges to an array of svn_revnum_t
+   ranges.
+
+   Given a log target URL_OR_ABSPATH@PEG_REV and an array of
+   svn_opt_revision_range_t's OPT_REV_RANGES, resolve the opt revs in
+   OPT_REV_RANGES to svn_revnum_t's and return these in *REVISION_RANGES, an
+   array of rev_range_t *.
+
+   Set *YOUNGEST_REV and *OLDEST_REV to the youngest and oldest revisions
+   found in *REVISION_RANGES.
+
+   If the repository needs to be contacted to resolve svn_opt_revision_date or
+   svn_opt_revision_head revisions, then the session used to do this is
+   RA_SESSION; it must be an open session to any URL in the right repository.
+*/
+static svn_error_t*
+convert_opt_rev_array_to_rev_range_array(
+  apr_array_header_t **revision_ranges,
+  svn_revnum_t *youngest_rev,
+  svn_revnum_t *oldest_rev,
+  svn_ra_session_t *ra_session,
+  const char *url_or_abspath,
+  const apr_array_header_t *opt_rev_ranges,
+  const svn_opt_revision_t *peg_rev,
+  svn_client_ctx_t *ctx,
+  apr_pool_t *result_pool,
+  apr_pool_t *scratch_pool)
+{
+  int i;
+  svn_revnum_t head_rev = SVN_INVALID_REVNUM;
+
+  /* Initialize the input/output parameters. */
+  *youngest_rev = *oldest_rev = SVN_INVALID_REVNUM;
+
+  /* Convert OPT_REV_RANGES to an array of rev_range_t and find the youngest
+     and oldest revision range that spans all of OPT_REV_RANGES. */
+  *revision_ranges = apr_array_make(result_pool, opt_rev_ranges->nelts,
+                                    sizeof(rev_range_t *));
+
+  for (i = 0; i < opt_rev_ranges->nelts; i++)
     {
       svn_opt_revision_range_t *range;
+      rev_range_t *rev_range;
+      svn_boolean_t start_same_as_end = FALSE;
 
-      range = APR_ARRAY_IDX(revision_ranges, i, svn_opt_revision_range_t *);
+      range = APR_ARRAY_IDX(opt_rev_ranges, i, svn_opt_revision_range_t *);
 
+      /* Right now RANGE can be any valid pair of svn_opt_revision_t's.  We
+         will now convert all RANGEs in place to the corresponding
+         svn_opt_revision_number kind. */
       if ((range->start.kind != svn_opt_revision_unspecified)
           && (range->end.kind == svn_opt_revision_unspecified))
         {
@@ -329,15 +498,15 @@ svn_client_log5(const apr_array_header_t
           /* Default to any specified peg revision.  Otherwise, if the
            * first target is a URL, then we default to HEAD:0.  Lastly,
            * the default is BASE:0 since WC@HEAD may not exist. */
-          if (peg_rev.kind == svn_opt_revision_unspecified)
+          if (peg_rev->kind == svn_opt_revision_unspecified)
             {
-              if (svn_path_is_url(url_or_path))
+              if (svn_path_is_url(url_or_abspath))
                 range->start.kind = svn_opt_revision_head;
               else
                 range->start.kind = svn_opt_revision_base;
             }
           else
-            range->start = peg_rev;
+            range->start = *peg_rev;
 
           if (range->end.kind == svn_opt_revision_unspecified)
             {
@@ -354,163 +523,117 @@ svn_client_log5(const apr_array_header_t
              _("Missing required revision specification"));
         }
 
-      /* Determine the revision to open the RA session to. */
-      if (session_opt_rev.kind == svn_opt_revision_unspecified)
+      /* Does RANGE describe a single svn_opt_revision_t? */
+      if (range->start.kind == range->end.kind)
         {
-          if (range->start.kind == svn_opt_revision_number &&
-              range->end.kind == svn_opt_revision_number)
+          if (range->start.kind == svn_opt_revision_number)
             {
-              session_opt_rev =
-                  (range->start.value.number > range->end.value.number ?
-                   range->start : range->end);
+              if (range->start.value.number == range->end.value.number)
+                start_same_as_end = TRUE;
             }
-          else if (range->start.kind == svn_opt_revision_head ||
-                   range->end.kind == svn_opt_revision_head)
+          else if (range->start.kind == svn_opt_revision_date)
             {
-              session_opt_rev.kind = svn_opt_revision_head;
+              if (range->start.value.date == range->end.value.date)
+                start_same_as_end = TRUE;
             }
-          else if (range->start.kind == svn_opt_revision_date &&
-                   range->end.kind == svn_opt_revision_date)
+          else
             {
-              session_opt_rev =
-                  (range->start.value.date > range->end.value.date ?
-                   range->start : range->end);
+              start_same_as_end = TRUE;
             }
         }
-    }
-
-  /* Use the passed URL, if there is one.  */
-  if (svn_path_is_url(url_or_path))
-    {
-      /* Initialize this array, since we'll be building it below */
-      condensed_targets = apr_array_make(pool, 1, sizeof(const char *));
-
-      /* The logic here is this: If we get passed one argument, we assume
-         it is the full URL to a file/dir we want log info for. If we get
-         a URL plus some paths, then we assume that the URL is the base,
-         and that the paths passed are relative to it.  */
-      if (targets->nelts > 1)
-        {
-          /* We have some paths, let's use them. Start after the URL.  */
-          for (i = 1; i < targets->nelts; i++)
-            {
-              const char *target;
-
-              target = APR_ARRAY_IDX(targets, i, const char *);
 
-              if (svn_path_is_url(target) || svn_dirent_is_absolute(target))
-                return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
-                                         _("'%s' is not a relative path"),
-                                          target);
-
-              APR_ARRAY_PUSH(condensed_targets, const char *) = target;
-            }
-        }
+      rev_range = apr_palloc(result_pool, sizeof(*rev_range));
+      SVN_ERR(svn_client__get_revision_number(
+                &rev_range->range_start, &head_rev,
+                ctx->wc_ctx, url_or_abspath, ra_session,
+                &range->start, scratch_pool));
+      if (start_same_as_end)
+        rev_range->range_end = rev_range->range_start;
       else
-        {
-          /* If we have a single URL, then the session will be rooted at
-             it, so just send an empty string for the paths we are
-             interested in. */
-          APR_ARRAY_PUSH(condensed_targets, const char *) = "";
-        }
-
-      /* Remember that our targets are URLs. */
-      url_targets = TRUE;
+        SVN_ERR(svn_client__get_revision_number(
+                  &rev_range->range_end, &head_rev,
+                  ctx->wc_ctx, url_or_abspath, ra_session,
+                  &range->end, scratch_pool));
+
+      /* Possibly update the oldest and youngest revisions requested. */
+      find_youngest_and_oldest_revs(youngest_rev,
+                                    oldest_rev,
+                                    rev_range->range_start);
+      find_youngest_and_oldest_revs(youngest_rev,
+                                    oldest_rev,
+                                    rev_range->range_end);
+      APR_ARRAY_PUSH(*revision_ranges, rev_range_t *) = rev_range;
     }
-  else
-    {
-      apr_array_header_t *target_urls;
-      apr_array_header_t *real_targets;
 
-      /* See FIXME about multiple wc targets, below. */
-      if (targets->nelts > 1)
-        return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
-                                _("When specifying working copy paths, only "
-                                  "one target may be given"));
+  return SVN_NO_ERROR;
+}
 
-      /* An unspecified PEG_REVISION for a working copy path defaults
-         to svn_opt_revision_working. */
-      if (peg_rev.kind == svn_opt_revision_unspecified)
-          peg_rev.kind = svn_opt_revision_working;
+static int
+compare_rev_to_segment(const void *key_p,
+                       const void *element_p)
+{
+  svn_revnum_t rev =
+    * (svn_revnum_t *)key_p;
+  const svn_location_segment_t *segment =
+    *((const svn_location_segment_t * const *) element_p);
+
+  if (rev < segment->range_start)
+    return -1;
+  else if (rev > segment->range_end)
+    return 1;
+  else
+    return 0;
+}
 
-      /* Get URLs for each target */
-      target_urls = apr_array_make(pool, 1, sizeof(const char *));
-      real_targets = apr_array_make(pool, 1, sizeof(const char *));
-      iterpool = svn_pool_create(pool);
-      for (i = 0; i < targets->nelts; i++)
-        {
-          const char *url;
-          const char *target = APR_ARRAY_IDX(targets, i, const char *);
-          const char *target_abspath;
-
-          svn_pool_clear(iterpool);
-          SVN_ERR(svn_dirent_get_absolute(&target_abspath, target, iterpool));
-          SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, target_abspath,
-                                       pool, iterpool));
-
-          if (! url)
-            return svn_error_createf
-              (SVN_ERR_ENTRY_MISSING_URL, NULL,
-               _("Entry '%s' has no URL"),
-               svn_dirent_local_style(target, pool));
-
-          APR_ARRAY_PUSH(target_urls, const char *) = url;
-          APR_ARRAY_PUSH(real_targets, const char *) = target;
-        }
-
-      /* if we have no valid target_urls, just exit. */
-      if (target_urls->nelts == 0)
-        return SVN_NO_ERROR;
-
-      /* Find the base URL and condensed targets relative to it. */
-      SVN_ERR(svn_uri_condense_targets(&url_or_path, &condensed_targets,
-                                       target_urls, TRUE, pool, iterpool));
-
-      if (condensed_targets->nelts == 0)
-        APR_ARRAY_PUSH(condensed_targets, const char *) = "";
-
-      /* 'targets' now becomes 'real_targets', which has bogus,
-         unversioned things removed from it. */
-      targets = real_targets;
-      svn_pool_destroy(iterpool);
-    }
-
-
-  {
-    svn_client__pathrev_t *actual_loc;
-
-    /* If this is a revision type that requires access to the working copy,
-     * we use our initial target path to figure out where to root the RA
-     * session, otherwise we use our URL. */
-    if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_rev.kind))
-      {
-        if (url_targets)
-          SVN_ERR(svn_uri_condense_targets(&ra_target, NULL, targets,
-                                           TRUE, pool, pool));
-        else
-          SVN_ERR(svn_dirent_condense_targets(&ra_target, NULL, targets,
-                                              TRUE, pool, pool));
-      }
-    else
-      ra_target = url_or_path;
-
-    SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &actual_loc,
-                                             ra_target, NULL,
-                                             &peg_rev, &session_opt_rev,
-                                             ctx, pool));
+/* Run svn_ra_get_log2 for PATHS, one or more paths relative to RA_SESSION's
+   common parent, for each revision in REVISION_RANGES, an array of
+   rev_range_t.
+
+   RA_SESSION is an open session pointing to ACTUAL_LOC.
+
+   LOG_SEGMENTS is an array of svn_location_segment_t * items representing the
+   history of PATHS from the oldest to youngest revisions found in
+   REVISION_RANGES.
+
+   The TARGETS, LIMIT, DISCOVER_CHANGED_PATHS, STRICT_NODE_HISTORY,
+   INCLUDE_MERGED_REVISIONS, REVPROPS, REAL_RECEIVER, and REAL_RECEIVER_BATON
+   parameters are all as per the svn_client_log5 API. */
+static svn_error_t *
+run_ra_get_log(apr_array_header_t *revision_ranges,
+               apr_array_header_t *paths,
+               apr_array_header_t *log_segments,
+               svn_client__pathrev_t *actual_loc,
+               svn_ra_session_t *ra_session,
+               /* The following are as per svn_client_log5. */ 
+               const apr_array_header_t *targets,
+               int limit,
+               svn_boolean_t discover_changed_paths,
+               svn_boolean_t strict_node_history,
+               svn_boolean_t include_merged_revisions,
+               const apr_array_header_t *revprops,
+               svn_log_entry_receiver_t real_receiver,
+               void *real_receiver_baton,
+               svn_client_ctx_t *ctx,
+               apr_pool_t *scratch_pool)
+{
+  int i;
+  pre_15_receiver_baton_t rb = {0};
+  apr_pool_t *iterpool;
+  svn_boolean_t has_log_revprops;
 
-    SVN_ERR(svn_ra_has_capability(ra_session, &has_log_revprops,
-                                  SVN_RA_CAPABILITY_LOG_REVPROPS, pool));
+  SVN_ERR(svn_ra_has_capability(ra_session, &has_log_revprops,
+                                SVN_RA_CAPABILITY_LOG_REVPROPS,
+                                scratch_pool));
 
-    if (!has_log_revprops) {
+  if (!has_log_revprops)
+    {
       /* See above pre-1.5 notes. */
       rb.ctx = ctx;
 
       /* Create ra session on first use */
-      rb.ra_session_pool = pool;
+      rb.ra_session_pool = scratch_pool;
       rb.ra_session_url = actual_loc->url;
     }
-  }
 
   /* It's a bit complex to correctly handle the special revision words
    * such as "BASE", "COMMITTED", and "PREV".  For example, if the
@@ -559,35 +682,54 @@ svn_client_log5(const apr_array_header_t
    * epg wonders if the repository could send a unified stream of log
    * entries if the paths and revisions were passed down.
    */
-  iterpool = svn_pool_create(pool);
+  iterpool = svn_pool_create(scratch_pool);
   for (i = 0; i < revision_ranges->nelts; i++)
     {
-      svn_revnum_t start_revnum, end_revnum, youngest_rev = SVN_INVALID_REVNUM;
+      const char *old_session_url;
       const char *path = APR_ARRAY_IDX(targets, 0, const char *);
       const char *local_abspath_or_url;
-      svn_opt_revision_range_t *range;
+      rev_range_t *range;
       limit_receiver_baton_t lb;
       svn_log_entry_receiver_t passed_receiver;
       void *passed_receiver_baton;
       const apr_array_header_t *passed_receiver_revprops;
+      svn_location_segment_t **matching_segment;
+      svn_revnum_t younger_rev;
 
       svn_pool_clear(iterpool);
 
       if (!svn_path_is_url(path))
-        SVN_ERR(svn_dirent_get_absolute(&local_abspath_or_url, path, iterpool));
+        SVN_ERR(svn_dirent_get_absolute(&local_abspath_or_url, path,
+                                        iterpool));
       else
         local_abspath_or_url = path;
 
-      range = APR_ARRAY_IDX(revision_ranges, i, svn_opt_revision_range_t *);
+      range = APR_ARRAY_IDX(revision_ranges, i, rev_range_t *);
 
-      SVN_ERR(svn_client__get_revision_number(&start_revnum, &youngest_rev,
-                                              ctx->wc_ctx, local_abspath_or_url,
-                                              ra_session, &range->start,
-                                              iterpool));
-      SVN_ERR(svn_client__get_revision_number(&end_revnum, &youngest_rev,
-                                              ctx->wc_ctx, local_abspath_or_url,
-                                              ra_session, &range->end,
-                                              iterpool));
+      /* Issue #4355: Account for renames spanning requested
+         revision ranges. */
+      younger_rev = MAX(range->range_start, range->range_end);
+      matching_segment = bsearch(&younger_rev, log_segments->elts,
+                                 log_segments->nelts, log_segments->elt_size,
+                                 compare_rev_to_segment);
+      SVN_ERR_ASSERT(*matching_segment);
+      
+      /* A segment with a NULL path means there is gap in the history.
+         We'll just proceed and let svn_ra_get_log2 fail with a useful
+         error...*/
+      if ((*matching_segment)->path != NULL)
+        {
+          /* ...but if there is history, then we must account for issue
+             #4355 and make sure our RA session is pointing at the correct
+             location. */
+          const char *segment_url = svn_path_url_add_component2(
+            actual_loc->repos_root_url, (*matching_segment)->path,
+            scratch_pool);
+          SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url,
+                                                    ra_session,
+                                                    segment_url,
+                                                    scratch_pool));
+        }
 
       if (has_log_revprops)
         {
@@ -617,9 +759,9 @@ svn_client_log5(const apr_array_header_t
         }
 
       SVN_ERR(svn_ra_get_log2(ra_session,
-                              condensed_targets,
-                              start_revnum,
-                              end_revnum,
+                              paths,
+                              range->range_start,
+                              range->range_end,
                               limit,
                               discover_changed_paths,
                               strict_node_history,
@@ -642,3 +784,85 @@ svn_client_log5(const apr_array_header_t
 
   return SVN_NO_ERROR;
 }
+
+/*** Public Interface. ***/
+
+svn_error_t *
+svn_client_log5(const apr_array_header_t *targets,
+                const svn_opt_revision_t *peg_revision,
+                const apr_array_header_t *opt_rev_ranges,
+                int limit,
+                svn_boolean_t discover_changed_paths,
+                svn_boolean_t strict_node_history,
+                svn_boolean_t include_merged_revisions,
+                const apr_array_header_t *revprops,
+                svn_log_entry_receiver_t real_receiver,
+                void *real_receiver_baton,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *pool)
+{
+  svn_ra_session_t *ra_session;
+  const char *old_session_url;
+  const char *ra_target;
+  svn_opt_revision_t youngest_opt_rev;
+  svn_revnum_t youngest_rev;
+  svn_revnum_t oldest_rev;
+  svn_opt_revision_t peg_rev;
+  svn_client__pathrev_t *actual_loc;
+  apr_array_header_t *log_segments;
+  apr_array_header_t *revision_ranges;
+  apr_array_header_t *relative_targets;
+
+  if (opt_rev_ranges->nelts == 0)
+    {
+      return svn_error_create
+        (SVN_ERR_CLIENT_BAD_REVISION, NULL,
+         _("Missing required revision specification"));
+    }
+
+  /* Make a copy of PEG_REVISION, we may need to change it to a
+     default value. */
+  peg_rev = *peg_revision;
+
+  SVN_ERR(resolve_log_targets(&relative_targets, &ra_target, &peg_rev,
+                              targets, ctx, pool, pool));
+
+  SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &actual_loc,
+                                            ra_target, NULL, &peg_rev, &peg_rev,
+                                            ctx, pool));
+
+  /* Convert OPT_REV_RANGES to an array of rev_range_t and find the youngest
+     and oldest revision range that spans all of OPT_REV_RANGES. */
+  SVN_ERR(convert_opt_rev_array_to_rev_range_array(&revision_ranges,
+                                                   &youngest_rev,
+                                                   &oldest_rev,
+                                                   ra_session,
+                                                   ra_target,
+                                                   opt_rev_ranges, &peg_rev,
+                                                   ctx, pool,  pool));
+
+  /* Make ACTUAL_LOC and RA_SESSION point to the youngest operative rev. */
+  youngest_opt_rev.kind = svn_opt_revision_number;
+  youngest_opt_rev.value.number = youngest_rev;
+  SVN_ERR(svn_client__resolve_rev_and_url(&actual_loc, ra_session,
+                                          ra_target, &peg_rev,
+                                          &youngest_opt_rev, ctx, pool));
+  SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session,
+                                            actual_loc->url, pool));
+
+  /* Get the svn_location_segment_t's representing the requested log ranges. */
+  SVN_ERR(svn_client__repos_location_segments(&log_segments, ra_session,
+                                              actual_loc->url,
+                                              actual_loc->rev, /* peg */
+                                              actual_loc->rev, /* start */
+                                              oldest_rev,      /* end */
+                                              ctx, pool));
+
+  SVN_ERR(run_ra_get_log(revision_ranges, relative_targets, log_segments,
+                         actual_loc, ra_session, targets, limit,
+                         discover_changed_paths, strict_node_history,
+                         include_merged_revisions, revprops, real_receiver,
+                         real_receiver_baton, ctx, pool));
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/fsfs-format7/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_client/merge.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_client/merge.c Sat May 11 23:28:06 2013
@@ -436,7 +436,7 @@ check_repos_match(const merge_target_t *
   if (!svn_uri__is_ancestor(target->loc.repos_root_url, url))
     return svn_error_createf(
         SVN_ERR_UNSUPPORTED_FEATURE, NULL,
-         _("Url '%s' of '%s' is not in repository '%s'"),
+         _("URL '%s' of '%s' is not in repository '%s'"),
          url, svn_dirent_local_style(local_abspath, scratch_pool),
          target->loc.repos_root_url);
 
@@ -6229,7 +6229,7 @@ get_wc_explicit_mergeinfo_catalog(apr_ha
               err = svn_error_createf(
                 SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING, err,
                 _("Invalid mergeinfo detected on '%s', "
-                  "mergetracking not possible"),
+                  "merge tracking not possible"),
                 svn_dirent_local_style(wc_path, scratch_pool));
             }
           return svn_error_trace(err);
@@ -7378,7 +7378,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
               err = svn_error_createf(
                 SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING, err,
                 _("Invalid mergeinfo detected on merge target '%s', "
-                  "mergetracking not possible"),
+                  "merge tracking not possible"),
                 svn_dirent_local_style(target_abspath, scratch_pool));
             }
           return svn_error_trace(err);
@@ -12028,16 +12028,17 @@ operative_rev_receiver(void *baton,
   return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
 }
 
-/* Wrapper around svn_client_mergeinfo_log2. All arguments are as per
-   that API.  The discover_changed_paths, depth, and revprops args to
-   svn_client_mergeinfo_log2 are always TRUE, svn_depth_infinity_t,
+/* Wrapper around svn_client__mergeinfo_log. All arguments are as per
+   that private API.  The discover_changed_paths, depth, and revprops args to
+   svn_client__mergeinfo_log are always TRUE, svn_depth_infinity_t,
    and NULL respectively.
 
    If RECEIVER raises a SVN_ERR_CEASE_INVOCATION error, but still sets
    *REVISION to a valid revnum, then clear the error.  Otherwise return
    any error. */
 static svn_error_t*
-short_circuit_mergeinfo_log(svn_boolean_t finding_merged,
+short_circuit_mergeinfo_log(svn_mergeinfo_catalog_t *target_mergeinfo_cat,
+                            svn_boolean_t finding_merged,
                             const char *target_path_or_url,
                             const svn_opt_revision_t *target_peg_revision,
                             const char *source_path_or_url,
@@ -12047,18 +12048,21 @@ short_circuit_mergeinfo_log(svn_boolean_
                             svn_log_entry_receiver_t receiver,
                             svn_revnum_t *revision,
                             svn_client_ctx_t *ctx,
+                            apr_pool_t *result_pool,
                             apr_pool_t *scratch_pool)
 {
-  svn_error_t *err = svn_client_mergeinfo_log2(finding_merged,
+  svn_error_t *err = svn_client__mergeinfo_log(finding_merged,
                                                target_path_or_url,
                                                target_peg_revision,
+                                               target_mergeinfo_cat,
                                                source_path_or_url,
                                                source_peg_revision,
                                                source_start_revision,
                                                source_end_revision,
                                                receiver, revision,
                                                TRUE, svn_depth_infinity,
-                                               NULL, ctx, scratch_pool);
+                                               NULL, ctx, result_pool,
+                                               scratch_pool);
 
   if (err)
     {
@@ -12128,6 +12132,7 @@ find_last_merged_location(svn_client__pa
   svn_opt_revision_t source_peg_rev, source_start_rev, source_end_rev,
     target_opt_rev;
   svn_revnum_t youngest_merged_rev = SVN_INVALID_REVNUM;
+  svn_mergeinfo_catalog_t target_mergeinfo_cat = NULL;
 
   source_peg_rev.kind = svn_opt_revision_number;
   source_peg_rev.value.number = source_branch->tip->rev;
@@ -12140,14 +12145,15 @@ find_last_merged_location(svn_client__pa
 
   /* Find the youngest revision fully merged from SOURCE_BRANCH to TARGET,
      if such a revision exists. */
-  SVN_ERR(short_circuit_mergeinfo_log(TRUE, /* Find merged */
+  SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat,
+                                      TRUE, /* Find merged */
                                       target->url, &target_opt_rev,
                                       source_branch->tip->url,
                                       &source_peg_rev,
                                       &source_end_rev, &source_start_rev,
                                       operative_rev_receiver,
                                       &youngest_merged_rev,
-                                      ctx, scratch_pool));
+                                      ctx, result_pool, scratch_pool));
 
   if (!SVN_IS_VALID_REVNUM(youngest_merged_rev))
     {
@@ -12174,14 +12180,15 @@ find_last_merged_location(svn_client__pa
          (i.e. finding the youngest revision after the YCA where all revs have
          been merged) that doesn't matter. */
       source_end_rev.value.number = youngest_merged_rev;
-      SVN_ERR(short_circuit_mergeinfo_log(FALSE, /* Find eligible */
+      SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat,
+                                          FALSE, /* Find eligible */
                                           target->url, &target_opt_rev,
                                           source_branch->tip->url,
                                           &source_peg_rev,
                                           &source_start_rev, &source_end_rev,
                                           operative_rev_receiver,
                                           &oldest_eligible_rev,
-                                          ctx, scratch_pool));
+                                          ctx, scratch_pool, scratch_pool));
 
       /* If there are revisions eligible for merging, use the oldest one
          to calculate the base.  Otherwise there are no operative revisions

Modified: subversion/branches/fsfs-format7/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_client/mergeinfo.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_client/mergeinfo.c Sat May 11 23:28:06 2013
@@ -1647,11 +1647,11 @@ svn_client_mergeinfo_get_merged(apr_hash
   return SVN_NO_ERROR;
 }
 
-
 svn_error_t *
-svn_client_mergeinfo_log2(svn_boolean_t finding_merged,
+svn_client__mergeinfo_log(svn_boolean_t finding_merged,
                           const char *target_path_or_url,
                           const svn_opt_revision_t *target_peg_revision,
+                          svn_mergeinfo_catalog_t *target_mergeinfo_catalog,
                           const char *source_path_or_url,
                           const svn_opt_revision_t *source_peg_revision,
                           const svn_opt_revision_t *source_start_revision,
@@ -1662,12 +1662,15 @@ svn_client_mergeinfo_log2(svn_boolean_t 
                           svn_depth_t depth,
                           const apr_array_header_t *revprops,
                           svn_client_ctx_t *ctx,
+                          apr_pool_t *result_pool,
                           apr_pool_t *scratch_pool)
 {
   const char *log_target = NULL;
   const char *repos_root;
   const char *target_repos_relpath;
   svn_mergeinfo_catalog_t target_mergeinfo_cat;
+  svn_ra_session_t *target_session = NULL;
+  svn_client__pathrev_t *pathrev;
 
   /* A hash of paths, at or under TARGET_PATH_OR_URL, mapped to
      rangelists.  Not technically mergeinfo, so not using the
@@ -1684,6 +1687,7 @@ svn_client_mergeinfo_log2(svn_boolean_t 
   apr_hash_index_t *hi;
   apr_pool_t *iterpool;
   svn_boolean_t oldest_revs_first = TRUE;
+  apr_pool_t *subpool;
 
   /* We currently only support depth = empty | infinity. */
   if (depth != svn_depth_infinity && depth != svn_depth_empty)
@@ -1709,6 +1713,8 @@ svn_client_mergeinfo_log2(svn_boolean_t 
       && (source_start_revision->kind != svn_opt_revision_unspecified))
     return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, NULL);
 
+  subpool = svn_pool_create(scratch_pool);
+
   /* We need the union of TARGET_PATH_OR_URL@TARGET_PEG_REVISION's mergeinfo
      and MERGE_SOURCE_URL's history.  It's not enough to do path
      matching, because renames in the history of MERGE_SOURCE_URL
@@ -1716,10 +1722,45 @@ svn_client_mergeinfo_log2(svn_boolean_t 
      the target, that vastly simplifies matters (we'll have nothing to
      do). */
   /* This get_mergeinfo() call doubles as a mergeinfo capabilities check. */
-  SVN_ERR(get_mergeinfo(&target_mergeinfo_cat, &repos_root,
-                        target_path_or_url, target_peg_revision,
-                        depth == svn_depth_infinity, TRUE,
-                        ctx, scratch_pool, scratch_pool));
+  if (target_mergeinfo_catalog)
+    {
+      if (*target_mergeinfo_catalog)
+        {
+          /* The caller provided the mergeinfo catalog for
+             TARGET_PATH_OR_URL, so we don't need to accquire
+             it ourselves.  We do need to get the repos_root
+             though, because get_mergeinfo() won't do it for us. */
+          target_mergeinfo_cat = *target_mergeinfo_catalog;
+          SVN_ERR(svn_client__ra_session_from_path2(&target_session, &pathrev,
+                                                    target_path_or_url, NULL,
+                                                    target_peg_revision,
+                                                    target_peg_revision,
+                                                    ctx, subpool));
+          SVN_ERR(svn_ra_get_repos_root2(target_session, &repos_root,
+                                         scratch_pool));
+        }
+      else
+        {
+          /* The caller didn't provide the mergeinfo catalog for
+             TARGET_PATH_OR_URL, but wants us to pass a copy back
+             when we get it, so use RESULT_POOL. */
+          SVN_ERR(get_mergeinfo(target_mergeinfo_catalog, &repos_root,
+                                target_path_or_url, target_peg_revision,
+                                depth == svn_depth_infinity, TRUE,
+                                ctx, result_pool, scratch_pool));
+          target_mergeinfo_cat = *target_mergeinfo_catalog;
+        }
+    }
+  else
+    {
+      /* The caller didn't provide the mergeinfo catalog for
+         TARGET_PATH_OR_URL, nor does it want a copy, so we can use
+         nothing but SCRATCH_POOL. */
+      SVN_ERR(get_mergeinfo(&target_mergeinfo_cat, &repos_root,
+                            target_path_or_url, target_peg_revision,
+                            depth == svn_depth_infinity, TRUE,
+                            ctx, scratch_pool, scratch_pool));
+    }
 
   if (!svn_path_is_url(target_path_or_url))
     {
@@ -1751,6 +1792,7 @@ svn_client_mergeinfo_log2(svn_boolean_t 
          history. */
       if (finding_merged)
         {
+          svn_pool_destroy(subpool);
           return SVN_NO_ERROR;
         }
       else
@@ -1768,18 +1810,17 @@ svn_client_mergeinfo_log2(svn_boolean_t 
    * ### TODO: As the source and target must be in the same repository, we
    * should share a single session, tracking the two URLs separately. */
   {
-    apr_pool_t *sesspool = svn_pool_create(scratch_pool);
-    svn_ra_session_t *source_session, *target_session;
-    svn_client__pathrev_t *pathrev;
+    svn_ra_session_t *source_session;
     svn_revnum_t start_rev, end_rev, youngest_rev = SVN_INVALID_REVNUM;
 
     if (! finding_merged)
       {
-        SVN_ERR(svn_client__ra_session_from_path2(&target_session, &pathrev,
-                                                  target_path_or_url, NULL,
-                                                  target_peg_revision,
-                                                  target_peg_revision,
-                                                  ctx, sesspool));
+        if (!target_session)
+          SVN_ERR(svn_client__ra_session_from_path2(&target_session, &pathrev,
+                                                    target_path_or_url, NULL,
+                                                    target_peg_revision,
+                                                    target_peg_revision,
+                                                    ctx, subpool));
         SVN_ERR(svn_client__get_history_as_mergeinfo(&target_history, NULL,
                                                      pathrev,
                                                      SVN_INVALID_REVNUM,
@@ -1792,17 +1833,17 @@ svn_client_mergeinfo_log2(svn_boolean_t 
                                               source_path_or_url, NULL,
                                               source_peg_revision,
                                               source_peg_revision,
-                                              ctx, sesspool));
+                                              ctx, subpool));
     SVN_ERR(svn_client__get_revision_number(&start_rev, &youngest_rev,
                                             ctx->wc_ctx, source_path_or_url,
                                             source_session,
                                             source_start_revision,
-                                            sesspool));
+                                            subpool));
     SVN_ERR(svn_client__get_revision_number(&end_rev, &youngest_rev,
                                             ctx->wc_ctx, source_path_or_url,
                                             source_session,
                                             source_end_revision,
-                                            sesspool));
+                                            subpool));
     SVN_ERR(svn_client__get_history_as_mergeinfo(&source_history, NULL,
                                                  pathrev,
                                                  MAX(end_rev, start_rev),
@@ -1813,7 +1854,7 @@ svn_client_mergeinfo_log2(svn_boolean_t 
       oldest_revs_first = FALSE;
 
     /* Close the source and target sessions. */
-    svn_pool_destroy(sesspool);
+    svn_pool_destroy(subpool);
   }
 
   /* Separate the explicit or inherited mergeinfo on TARGET_PATH_OR_URL,
@@ -2086,6 +2127,31 @@ svn_client_mergeinfo_log2(svn_boolean_t 
 }
 
 svn_error_t *
+svn_client_mergeinfo_log2(svn_boolean_t finding_merged,
+                          const char *target_path_or_url,
+                          const svn_opt_revision_t *target_peg_revision,
+                          const char *source_path_or_url,
+                          const svn_opt_revision_t *source_peg_revision,
+                          const svn_opt_revision_t *source_start_revision,
+                          const svn_opt_revision_t *source_end_revision,
+                          svn_log_entry_receiver_t log_receiver,
+                          void *log_receiver_baton,
+                          svn_boolean_t discover_changed_paths,
+                          svn_depth_t depth,
+                          const apr_array_header_t *revprops,
+                          svn_client_ctx_t *ctx,
+                          apr_pool_t *scratch_pool)
+{
+  return svn_client__mergeinfo_log(finding_merged, target_path_or_url,
+                                   target_peg_revision, NULL,
+                                   source_path_or_url, source_peg_revision,
+                                   source_start_revision, source_end_revision,
+                                   log_receiver, log_receiver_baton,
+                                   discover_changed_paths, depth, revprops,
+                                   ctx, scratch_pool, scratch_pool);
+}
+
+svn_error_t *
 svn_client_suggest_merge_sources(apr_array_header_t **suggestions,
                                  const char *path_or_url,
                                  const svn_opt_revision_t *peg_revision,

Modified: subversion/branches/fsfs-format7/subversion/libsvn_client/ra.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_client/ra.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_client/ra.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_client/ra.c Sat May 11 23:28:06 2013
@@ -158,7 +158,7 @@ push_wc_prop(void *baton,
   if (! cb->commit_items)
     return svn_error_createf
       (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
-       _("Attempt to set wc property '%s' on '%s' in a non-commit operation"),
+       _("Attempt to set wcprop '%s' on '%s' in a non-commit operation"),
        name, svn_dirent_local_style(relpath, pool));
 
   for (i = 0; i < cb->commit_items->nelts; i++)
@@ -447,39 +447,14 @@ svn_client_open_ra_session2(svn_ra_sessi
                                                   scratch_pool));
 }
 
-
-
-
-/* Given PATH_OR_URL, which contains either a working copy path or an
-   absolute URL, a peg revision PEG_REVISION, and a desired revision
-   REVISION, find the path at which that object exists in REVISION,
-   following copy history if necessary.  If REVISION is younger than
-   PEG_REVISION, then check that PATH_OR_URL is the same node in both
-   PEG_REVISION and REVISION, and return @c
-   SVN_ERR_CLIENT_UNRELATED_RESOURCES if it is not the same node.
-
-   If PEG_REVISION->kind is 'unspecified', the peg revision is 'head'
-   for a URL or 'working' for a WC path.  If REVISION->kind is
-   'unspecified', the operative revision is the peg revision.
-
-   Store the actual location of the object in *RESOLVED_LOC_P.
-
-   RA_SESSION should be an open RA session pointing at the URL of
-   PATH_OR_URL, or NULL, in which case this function will open its own
-   temporary session.
-
-   Use authentication baton cached in CTX to authenticate against the
-   repository.
-
-   Use POOL for all allocations. */
-static svn_error_t *
-resolve_rev_and_url(svn_client__pathrev_t **resolved_loc_p,
-                    svn_ra_session_t *ra_session,
-                    const char *path_or_url,
-                    const svn_opt_revision_t *peg_revision,
-                    const svn_opt_revision_t *revision,
-                    svn_client_ctx_t *ctx,
-                    apr_pool_t *pool)
+svn_error_t *
+svn_client__resolve_rev_and_url(svn_client__pathrev_t **resolved_loc_p,
+                                svn_ra_session_t *ra_session,
+                                const char *path_or_url,
+                                const svn_opt_revision_t *peg_revision,
+                                const svn_opt_revision_t *revision,
+                                svn_client_ctx_t *ctx,
+                                apr_pool_t *pool)
 {
   svn_opt_revision_t peg_rev = *peg_revision;
   svn_opt_revision_t start_rev = *revision;
@@ -545,9 +520,9 @@ svn_client__ra_session_from_path2(svn_ra
   if (corrected_url && svn_path_is_url(path_or_url))
     path_or_url = corrected_url;
 
-  SVN_ERR(resolve_rev_and_url(&resolved_loc, ra_session,
-                              path_or_url, peg_revision, revision,
-                              ctx, pool));
+  SVN_ERR(svn_client__resolve_rev_and_url(&resolved_loc, ra_session,
+                                          path_or_url, peg_revision, revision,
+                                          ctx, pool));
 
   /* Make the session point to the real URL. */
   SVN_ERR(svn_ra_reparent(ra_session, resolved_loc->url, pool));
@@ -1009,9 +984,9 @@ svn_client__youngest_common_ancestor(con
                                             path_or_url1, NULL,
                                             revision1, revision1,
                                             ctx, sesspool));
-  SVN_ERR(resolve_rev_and_url(&loc2, session,
-                              path_or_url2, revision2, revision2,
-                              ctx, scratch_pool));
+  SVN_ERR(svn_client__resolve_rev_and_url(&loc2, session,
+                                          path_or_url2, revision2, revision2,
+                                          ctx, scratch_pool));
 
   SVN_ERR(svn_client__get_youngest_common_ancestor(
             &ancestor, loc1, loc2, session, ctx, result_pool, scratch_pool));

Modified: subversion/branches/fsfs-format7/subversion/libsvn_client/repos_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_client/repos_diff.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_client/repos_diff.c Sat May 11 23:28:06 2013
@@ -328,7 +328,7 @@ get_file_from_ra(struct file_baton *fb,
                                      fb->pool, scratch_pool));
 
       fstream = svn_stream_checksummed2(fstream, NULL, &fb->start_md5_checksum,
-                                        svn_checksum_md5, TRUE, scratch_pool);
+                                        svn_checksum_md5, TRUE, fb->pool);
 
       /* Retrieve the file and its properties */
       SVN_ERR(svn_ra_get_file(fb->edit_baton->ra_session,

Modified: subversion/branches/fsfs-format7/subversion/libsvn_client/switch.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_client/switch.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_client/switch.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_client/switch.c Sat May 11 23:28:06 2013
@@ -340,8 +340,8 @@ switch_internal(svn_revnum_t *result_rev
   *timestamp_sleep = TRUE;
 
   /* Drive the reporter structure, describing the revisions within
-     PATH.  When we call reporter->finish_report, the update_editor
-     will be driven by svn_repos_dir_delta2. */
+     LOCAL_ABSPATH.  When this calls reporter->finish_report, the
+     reporter will drive the switch_editor. */
   SVN_ERR(svn_wc_crawl_revisions5(ctx->wc_ctx, local_abspath, reporter,
                                   report_baton, TRUE,
                                   depth, (! depth_is_sticky),

Modified: subversion/branches/fsfs-format7/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_client/update.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_client/update.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_client/update.c Sat May 11 23:28:06 2013
@@ -454,8 +454,8 @@ update_internal(svn_revnum_t *result_rev
   *timestamp_sleep = TRUE;
 
   /* Drive the reporter structure, describing the revisions within
-     PATH.  When we call reporter->finish_report, the
-     update_editor will be driven by svn_repos_dir_delta2. */
+     LOCAL_ABSPATH.  When this calls reporter->finish_report, the
+     reporter will drive the update_editor. */
   SVN_ERR(svn_wc_crawl_revisions5(ctx->wc_ctx, local_abspath, reporter,
                                   report_baton, TRUE,
                                   depth, (! depth_is_sticky),

Modified: subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/serf.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_ra_serf/serf.c Sat May 11 23:28:06 2013
@@ -119,8 +119,9 @@ load_http_auth_types(apr_pool_t *pool, s
             *authn_types |= SERF_AUTHN_NEGOTIATE;
           else
             return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
-                                     _("Invalid config: unknown http auth"
-                                       "type '%s'"), token);
+                                     _("Invalid config: unknown %s "
+                                       "'%s'"),
+                                     SVN_CONFIG_OPTION_HTTP_AUTH_TYPES, token);
       }
     }
   else

Modified: subversion/branches/fsfs-format7/subversion/libsvn_repos/delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_repos/delta.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_repos/delta.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_repos/delta.c Sat May 11 23:28:06 2013
@@ -196,17 +196,6 @@ authz_root_check(svn_fs_root_t *root,
 }
 
 
-static svn_error_t *
-not_a_dir_error(const char *role,
-                const char *path)
-{
-  return svn_error_createf
-    (SVN_ERR_FS_NOT_DIRECTORY, 0,
-     "Invalid %s directory '%s'",
-     role, path ? path : "(null)");
-}
-
-
 /* Public interface to computing directory deltas.  */
 svn_error_t *
 svn_repos_dir_delta2(svn_fs_root_t *src_root,
@@ -237,7 +226,8 @@ svn_repos_dir_delta2(svn_fs_root_t *src_
   if (src_parent_dir)
     src_parent_dir = svn_relpath_canonicalize(src_parent_dir, pool);
   else
-    return not_a_dir_error("source parent", src_parent_dir);
+    return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, 0,
+                            "Invalid source parent directory '(null)'");
 
   /* TGT_FULLPATH must be valid. */
   if (tgt_fullpath)

Modified: subversion/branches/fsfs-format7/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_repos/dump.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_repos/dump.c Sat May 11 23:28:06 2013
@@ -1097,7 +1097,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
 {
   const svn_delta_editor_t *dump_editor;
   void *dump_edit_baton = NULL;
-  svn_revnum_t i;
+  svn_revnum_t rev;
   svn_fs_t *fs = svn_repos_fs(repos);
   apr_pool_t *subpool = svn_pool_create(pool);
   svn_revnum_t youngest;
@@ -1129,10 +1129,6 @@ svn_repos_dump_fs3(svn_repos_t *repos,
                              _("End revision %ld is invalid "
                                "(youngest revision is %ld)"),
                              end_rev, youngest);
-  if ((start_rev == 0) && incremental)
-    incremental = FALSE; /* revision 0 looks the same regardless of
-                            whether or not this is an incremental
-                            dump, so just simplify things. */
 
   /* Write out the UUID. */
   SVN_ERR(svn_fs_get_uuid(fs, &uuid, pool));
@@ -1156,10 +1152,9 @@ svn_repos_dump_fs3(svn_repos_t *repos,
     notify = svn_repos_notify_create(svn_repos_notify_dump_rev_end,
                                      pool);
 
-  /* Main loop:  we're going to dump revision i.  */
-  for (i = start_rev; i <= end_rev; i++)
+  /* Main loop:  we're going to dump revision REV.  */
+  for (rev = start_rev; rev <= end_rev; rev++)
     {
-      svn_revnum_t from_rev, to_rev;
       svn_fs_root_t *to_root;
       svn_boolean_t use_deltas_for_rev;
 
@@ -1169,56 +1164,35 @@ svn_repos_dump_fs3(svn_repos_t *repos,
       if (cancel_func)
         SVN_ERR(cancel_func(cancel_baton));
 
-      /* Special-case the initial revision dump: it needs to contain
-         *all* nodes, because it's the foundation of all future
-         revisions in the dumpfile. */
-      if ((i == start_rev) && (! incremental))
-        {
-          /* Special-special-case a dump of revision 0. */
-          if (i == 0)
-            {
-              /* Just write out the one revision 0 record and move on.
-                 The parser might want to use its properties. */
-              SVN_ERR(write_revision_record(stream, fs, 0, subpool));
-              to_rev = 0;
-              goto loop_end;
-            }
-
-          /* Compare START_REV to revision 0, so that everything
-             appears to be added.  */
-          from_rev = 0;
-          to_rev = i;
-        }
-      else
-        {
-          /* In the normal case, we want to compare consecutive revs. */
-          from_rev = i - 1;
-          to_rev = i;
-        }
-
       /* Write the revision record. */
-      SVN_ERR(write_revision_record(stream, fs, to_rev, subpool));
+      SVN_ERR(write_revision_record(stream, fs, rev, subpool));
+
+      /* When dumping revision 0, we just write out the revision record.
+         The parser might want to use its properties. */
+      if (rev == 0)
+        goto loop_end;
 
       /* Fetch the editor which dumps nodes to a file.  Regardless of
          what we've been told, don't use deltas for the first rev of a
          non-incremental dump. */
-      use_deltas_for_rev = use_deltas && (incremental || i != start_rev);
-      SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton, fs, to_rev,
+      use_deltas_for_rev = use_deltas && (incremental || rev != start_rev);
+      SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton, fs, rev,
                               "", stream, &found_old_reference,
                               &found_old_mergeinfo, NULL,
                               notify_func, notify_baton,
                               start_rev, use_deltas_for_rev, FALSE, subpool));
 
       /* Drive the editor in one way or another. */
-      SVN_ERR(svn_fs_revision_root(&to_root, fs, to_rev, subpool));
+      SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, subpool));
 
       /* If this is the first revision of a non-incremental dump,
          we're in for a full tree dump.  Otherwise, we want to simply
          replay the revision.  */
-      if ((i == start_rev) && (! incremental))
+      if ((rev == start_rev) && (! incremental))
         {
+          /* Compare against revision 0, so everything appears to be added. */
           svn_fs_root_t *from_root;
-          SVN_ERR(svn_fs_revision_root(&from_root, fs, from_rev, subpool));
+          SVN_ERR(svn_fs_revision_root(&from_root, fs, 0, subpool));
           SVN_ERR(svn_repos_dir_delta2(from_root, "", "",
                                        to_root, "",
                                        dump_editor, dump_edit_baton,
@@ -1232,6 +1206,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
         }
       else
         {
+          /* The normal case: compare consecutive revs. */
           SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
                                     dump_editor, dump_edit_baton,
                                     NULL, NULL, subpool));
@@ -1244,7 +1219,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
     loop_end:
       if (notify_func)
         {
-          notify->revision = to_rev;
+          notify->revision = rev;
           notify_func(notify_baton, notify, subpool);
         }
     }

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-membuffer.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/cache-membuffer.c Sat May 11 23:28:06 2013
@@ -1014,8 +1014,6 @@ find_entry(svn_membuffer_t *cache,
        */
       if (group->used == GROUP_SIZE)
         {
-          static int count = 0;
-          
           /* every entry gets the same chance of being removed.
            * Otherwise, we free the first entry, fill it and remove it
            * again on the next occasion without considering the other
@@ -1037,7 +1035,6 @@ find_entry(svn_membuffer_t *cache,
               let_entry_age(cache, entry);
 
           drop_entry(cache, entry);
-          printf("%d\n", ++count);
         }
 
       /* initialize entry for the new key
@@ -1551,7 +1548,7 @@ svn_cache__membuffer_cache_create(svn_me
         {
           /* We are OOM. There is no need to proceed with "half a cache".
            */
-          return svn_error_wrap_apr(APR_ENOMEM, _("OOM"));
+          return svn_error_wrap_apr(APR_ENOMEM, "OOM");
         }
 
 #if APR_HAS_THREADS
@@ -2342,9 +2339,9 @@ combine_key(svn_membuffer_cache_t *cache
   /* scramble key DATA.  All of this must be reversible to prevent key
    * collisions.  So, we limit ourselves to xor and permutations. */
   data[1] = (data[1] << 27) | (data[1] >> 37);
+  data[0] = (data[0] << 43) | (data[0] >> 21);
   data[1] ^= data[0] & 0xffff;
   data[0] ^= data[1] & 0xffffffffffff0000ull;
-  data[0] = (data[0] << 43) | (data[0] >> 21);
 
   /* combine with this cache's namespace */
   cache->combined_key[0] = data[0] ^ cache->prefix[0];

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/config_file.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/config_file.c Sat May 11 23:28:06 2013
@@ -1152,6 +1152,16 @@ svn_config_ensure(const char *config_dir
         "### ra_local (the file:// scheme). The value represents the number" NL
         "### of MB used by the cache."                                       NL
         "# memory-cache-size = 16"                                           NL
+        "### Set diff-ignore-content-type to 'yes' to cause 'svn diff' to"   NL
+        "### attempt to show differences of all modified files regardless"   NL
+        "### of their MIME content type.  By default, Subversion will only"  NL
+        "### attempt to show differences for files believed to have human-"  NL
+        "### readable (non-binary) content.  This option is especially"      NL
+        "### useful when Subversion is configured (via the 'diff-cmd'"       NL
+        "### option) to employ an external differencing tool which is able"  NL
+        "### to show meaningful differences for binary file formats.  [New"  NL
+        "### in 1.9]"                                                        NL
+        "# diff-ignore-content-type = no"                                    NL
         ""                                                                   NL
         "### Section for configuring automatic properties."                  NL
         "[auto-props]"                                                       NL

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/error.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/error.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/error.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/error.c Sat May 11 23:28:06 2013
@@ -679,7 +679,7 @@ svn_strerror(apr_status_t statcode, char
 }
 
 #ifdef SVN_DEBUG
-/* Defines svn__errno */
+/* Defines svn__errno and svn__apr_errno */
 #include "errorcode.inc"
 #endif
 
@@ -705,6 +705,12 @@ svn_error_symbolic_name(apr_status_t sta
   for (i = 0; i < sizeof(svn__errno) / sizeof(svn__errno[0]); i++)
     if (svn__errno[i].errcode == (int)statcode)
       return svn__errno[i].errname;
+
+  /* Try APR errors. */
+  /* Linear search through a sorted array */
+  for (i = 0; i < sizeof(svn__apr_errno) / sizeof(svn__apr_errno[0]); i++)
+    if (svn__apr_errno[i].errcode == (int)statcode)
+      return svn__apr_errno[i].errname;
 #endif /* SVN_DEBUG */
 
   /* ### TODO: do we need APR_* error macros?  What about APR_TO_OS_ERROR()? */

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/sqlite.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/sqlite.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/sqlite.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/sqlite.c Sat May 11 23:28:06 2013
@@ -38,6 +38,11 @@
 #include "private/svn_skel.h"
 #include "private/svn_token.h"
 
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+#include "private/svn_utf_private.h"
+#include "private/svn_string_private.h"
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
+
 #ifdef SQLITE3_DEBUG
 #include "private/svn_debug.h"
 #endif
@@ -60,6 +65,13 @@ extern int (*const svn_sqlite3__api_conf
 #error SQLite is too old -- version 3.7.12 is the minimum required version
 #endif
 
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+/* Limit the length of a GLOB or LIKE pattern. */
+#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
+# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
+#endif
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
+
 const char *
 svn_sqlite__compiled_version(void)
 {
@@ -104,6 +116,13 @@ struct svn_sqlite__db_t
   int nbr_statements;
   svn_sqlite__stmt_t **prepared_stmts;
   apr_pool_t *state_pool;
+
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+  /* Buffers for SQLite extensoins. */
+  svn_membuf_t sqlext_buf1;
+  svn_membuf_t sqlext_buf2;
+  svn_membuf_t sqlext_buf3;
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
 };
 
 struct svn_sqlite__stmt_t
@@ -873,6 +892,99 @@ close_apr(void *data)
   return APR_SUCCESS;
 }
 
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+/* Unicode normalizing collation for WC paths */
+static int
+collate_ucs_nfd(void *baton,
+                int len1, const void *key1,
+                int len2, const void *key2)
+{
+  svn_sqlite__db_t *db = baton;
+  int result;
+
+  if (svn_utf__normcmp(key1, len1, key2, len2,
+                       &db->sqlext_buf1, &db->sqlext_buf2, &result))
+    {
+      /* There is really nothing we can do here if an error occurs
+         during Unicode normalizetion, and attempting to recover could
+         result in the wc.db index being corrupted. Presumably this
+         can only happen if the index already contains invalid UTF-8
+         strings, which should never happen in any case ... */
+      SVN_ERR_MALFUNCTION_NO_RETURN();
+    }
+
+  return result;
+}
+
+static void
+glob_like_ucs_nfd_common(sqlite3_context *context,
+                         int argc, sqlite3_value **argv,
+                         svn_boolean_t sql_like)
+{
+  svn_sqlite__db_t *const db = sqlite3_user_data(context);
+
+  const char *const pattern = (void*)sqlite3_value_text(argv[0]);
+  const apr_size_t pattern_len = sqlite3_value_bytes(argv[0]);
+  const char *const string = (void*)sqlite3_value_text(argv[1]);
+  const apr_size_t string_len = sqlite3_value_bytes(argv[1]);
+
+  const char *escape = NULL;
+  apr_size_t escape_len = 0;
+
+  svn_boolean_t match;
+  svn_error_t *err;
+
+  if (pattern_len > SQLITE_MAX_LIKE_PATTERN_LENGTH)
+    {
+      sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
+      return;
+    }
+
+  if (argc == 3 && sql_like)
+    {
+      escape = (void*)sqlite3_value_text(argv[2]);
+      escape_len = sqlite3_value_bytes(argv[2]);
+    }
+
+  if (pattern && string)
+    {
+      err = svn_utf__glob(pattern, pattern_len, string, string_len,
+                          escape, escape_len, sql_like,
+                          &db->sqlext_buf1, &db->sqlext_buf2, &db->sqlext_buf3,
+                          &match);
+
+      if (err)
+        {
+          const char *errmsg;
+          svn_membuf__ensure(&db->sqlext_buf1, 512);
+          errmsg = svn_err_best_message(err,
+                                        db->sqlext_buf1.data,
+                                        db->sqlext_buf1.size - 1);
+          svn_error_clear(err);
+          sqlite3_result_error(context, errmsg, -1);
+          return;
+        }
+
+      sqlite3_result_int(context, match);
+    }
+}
+
+/* Unicode normalizing implementation of GLOB */
+static void
+glob_ucs_nfd(sqlite3_context *context,
+             int argc, sqlite3_value **argv)
+{
+  glob_like_ucs_nfd_common(context, argc, argv, FALSE);
+}
+
+/* Unicode normalizing implementation of LIKE */
+static void
+like_ucs_nfd(sqlite3_context *context,
+             int argc, sqlite3_value **argv)
+{
+  glob_like_ucs_nfd_common(context, argc, argv, TRUE);
+}
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
 
 svn_error_t *
 svn_sqlite__open(svn_sqlite__db_t **db, const char *path,
@@ -887,6 +999,28 @@ svn_sqlite__open(svn_sqlite__db_t **db, 
 
   SVN_ERR(internal_open(&(*db)->db3, path, mode, scratch_pool));
 
+#ifdef SVN_UNICODE_NORMALIZATION_FIXES
+  /* Create extension buffers with space for 200 UCS-4 characters. */
+  svn_membuf__create(&(*db)->sqlext_buf1, 800, result_pool);
+  svn_membuf__create(&(*db)->sqlext_buf2, 800, result_pool);
+  svn_membuf__create(&(*db)->sqlext_buf3, 800, result_pool);
+
+  /* Register collation and LIKE and GLOB operator replacements. */
+  SQLITE_ERR(sqlite3_create_collation((*db)->db3,
+                                      "svn-ucs-nfd", SQLITE_UTF8,
+                                      *db, collate_ucs_nfd),
+             *db);
+  SQLITE_ERR(sqlite3_create_function((*db)->db3, "glob", 2, SQLITE_UTF8,
+                                     *db, glob_ucs_nfd, NULL, NULL),
+             *db);
+  SQLITE_ERR(sqlite3_create_function((*db)->db3, "like", 2, SQLITE_UTF8,
+                                     *db, like_ucs_nfd, NULL, NULL),
+             *db);
+  SQLITE_ERR(sqlite3_create_function((*db)->db3, "like", 3, SQLITE_UTF8,
+                                     *db, like_ucs_nfd, NULL, NULL),
+             *db);
+#endif /* SVN_UNICODE_NORMALIZATION_FIXES */
+
 #ifdef SQLITE3_DEBUG
   sqlite3_trace((*db)->db3, sqlite_tracer, (*db)->db3);
 #endif

Modified: subversion/branches/fsfs-format7/subversion/libsvn_subr/sqlite3wrapper.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_subr/sqlite3wrapper.c?rev=1481454&r1=1481453&r2=1481454&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_subr/sqlite3wrapper.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_subr/sqlite3wrapper.c Sat May 11 23:28:06 2013
@@ -39,6 +39,17 @@
 #      pragma GCC diagnostic ignored "-Wshorten-64-to-32"
 #    endif
 #  endif
+#  ifdef __APPLE__
+#    include <Availability.h>
+#    if __MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+       /* <libkern/OSAtomic.h> is included on OS X by sqlite3.c, and
+          on old systems (Leopard or older), it cannot be compiled
+          with -std=c89 because it uses inline. This is a work-around. */
+#      define inline __inline__
+#      include <libkern/OSAtomic.h>
+#      undef inline
+#    endif
+#  endif
 #  include <sqlite3.c>
 #  if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 6))
 #    pragma GCC diagnostic pop