コード例 #1
0
ファイル: upgrade.c プロジェクト: Alkzndr/freebsd
/* svn_wc_upgrade_get_repos_info_t implementation for calling
   svn_wc_upgrade() from svn_client_upgrade() */
static svn_error_t *
fetch_repos_info(const char **repos_root,
                 const char **repos_uuid,
                 void *baton,
                 const char *url,
                 apr_pool_t *result_pool,
                 apr_pool_t *scratch_pool)
{
  struct repos_info_baton *ri = baton;

  /* The same info is likely to retrieved multiple times (e.g. externals) */
  if (ri->last_repos && svn_uri__is_ancestor(ri->last_repos, url))
    {
      *repos_root = apr_pstrdup(result_pool, ri->last_repos);
      *repos_uuid = apr_pstrdup(result_pool, ri->last_uuid);
      return SVN_NO_ERROR;
    }

  SVN_ERR(svn_client_get_repos_root(repos_root, repos_uuid, url, ri->ctx,
                                    result_pool, scratch_pool));

  /* Store data for further calls */
  ri->last_repos = apr_pstrdup(ri->state_pool, *repos_root);
  ri->last_uuid = apr_pstrdup(ri->state_pool, *repos_uuid);

  return SVN_NO_ERROR;
}
コード例 #2
0
ファイル: status.c プロジェクト: cyrilmagsuci/freebsd
/* Implements svn_ra_reporter3_t->link_path. */
static svn_error_t *
reporter_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)
{
    report_baton_t *rb = report_baton;

    if (!svn_uri__is_ancestor(rb->ancestor, url))
    {
        const char *ancestor;

        ancestor = svn_uri_get_longest_ancestor(url, rb->ancestor, pool);

        /* If we got a shorter ancestor, truncate our current ancestor.
           Note that svn_uri_get_longest_ancestor will allocate its return
           value even if it identical to one of its arguments. */

        rb->ancestor[strlen(ancestor)] = '\0';
        rb->depth = svn_depth_infinity;
    }

    return rb->wrapped_reporter->link_path(rb->wrapped_report_baton, path, url,
                                           revision, depth, start_empty,
                                           lock_token, pool);
}
コード例 #3
0
svn_error_t *svn_ra_reparent(svn_ra_session_t *session,
                             const char *url,
                             apr_pool_t *pool)
{
  const char *repos_root;

  /* Make sure the new URL is in the same repository, so that the
     implementations don't have to do it. */
  SVN_ERR(svn_ra_get_repos_root2(session, &repos_root, pool));
  if (! svn_uri__is_ancestor(repos_root, url))
    return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
                             _("'%s' isn't in the same repository as '%s'"),
                             url, repos_root);

  return session->vtable->reparent(session, url, pool);
}
コード例 #4
0
ファイル: update.c プロジェクト: Alkzndr/freebsd
/* Implements svn_wc_dirents_func_t for update and switch handling. Assumes
   a struct svn_client__dirent_fetcher_baton_t * baton */
svn_error_t *
svn_client__dirent_fetcher(void *baton,
                           apr_hash_t **dirents,
                           const char *repos_root_url,
                           const char *repos_relpath,
                           apr_pool_t *result_pool,
                           apr_pool_t *scratch_pool)
{
  struct svn_client__dirent_fetcher_baton_t *dfb = baton;
  const char *old_url = NULL;
  const char *session_relpath;
  svn_node_kind_t kind;
  const char *url;

  url = svn_path_url_add_component2(repos_root_url, repos_relpath,
                                    scratch_pool);

  if (!svn_uri__is_ancestor(dfb->anchor_url, url))
    {
      SVN_ERR(svn_client__ensure_ra_session_url(&old_url, dfb->ra_session,
                                                url, scratch_pool));
      session_relpath = "";
    }
  else
    SVN_ERR(svn_ra_get_path_relative_to_session(dfb->ra_session,
                                                &session_relpath, url,
                                                scratch_pool));

  /* Is session_relpath still a directory? */
  SVN_ERR(svn_ra_check_path(dfb->ra_session, session_relpath,
                            dfb->target_revision, &kind, scratch_pool));

  if (kind == svn_node_dir)
    SVN_ERR(svn_ra_get_dir2(dfb->ra_session, dirents, NULL, NULL,
                            session_relpath, dfb->target_revision,
                            SVN_DIRENT_KIND, result_pool));
  else
    *dirents = NULL;

  if (old_url)
    SVN_ERR(svn_ra_reparent(dfb->ra_session, old_url, scratch_pool));

  return SVN_NO_ERROR;
}
コード例 #5
0
ファイル: serf.c プロジェクト: 2asoft/freebsd
/* Implements svn_ra__vtable_t.reparent(). */
svn_error_t *
svn_ra_serf__reparent(svn_ra_session_t *ra_session,
                      const char *url,
                      apr_pool_t *pool)
{
  svn_ra_serf__session_t *session = ra_session->priv;
  apr_uri_t new_url;

  /* If it's the URL we already have, wave our hands and do nothing. */
  if (strcmp(session->session_url_str, url) == 0)
    {
      return SVN_NO_ERROR;
    }

  if (!session->repos_root_str)
    {
      const char *vcc_url;
      SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, pool));
    }

  if (!svn_uri__is_ancestor(session->repos_root_str, url))
    {
      return svn_error_createf(
          SVN_ERR_RA_ILLEGAL_URL, NULL,
          _("URL '%s' is not a child of the session's repository root "
            "URL '%s'"), url, session->repos_root_str);
    }

  SVN_ERR(svn_ra_serf__uri_parse(&new_url, url, pool));

  /* ### Maybe we should use a string buffer for these strings so we
     ### don't allocate memory in the session on every reparent? */
  session->session_url.path = apr_pstrdup(session->pool, new_url.path);
  session->session_url_str = apr_pstrdup(session->pool, url);

  return SVN_NO_ERROR;
}
コード例 #6
0
static svn_error_t *
switch_internal(svn_revnum_t *result_rev,
                const char *local_abspath,
                const char *anchor_abspath,
                const char *switch_url,
                const svn_opt_revision_t *peg_revision,
                const svn_opt_revision_t *revision,
                svn_depth_t depth,
                svn_boolean_t depth_is_sticky,
                svn_boolean_t ignore_externals,
                svn_boolean_t allow_unver_obstructions,
                svn_boolean_t ignore_ancestry,
                svn_boolean_t *timestamp_sleep,
                svn_client_ctx_t *ctx,
                apr_pool_t *pool)
{
  const svn_ra_reporter3_t *reporter;
  void *report_baton;
  const char *url, *target, *source_root, *switch_rev_url;
  svn_ra_session_t *ra_session;
  svn_revnum_t revnum;
  svn_error_t *err = SVN_NO_ERROR;
  const char *diff3_cmd;
  svn_boolean_t use_commit_times;
  svn_boolean_t sleep_here = FALSE;
  svn_boolean_t *use_sleep = timestamp_sleep ? timestamp_sleep : &sleep_here;
  const svn_delta_editor_t *switch_editor;
  void *switch_edit_baton;
  const char *preserved_exts_str;
  apr_array_header_t *preserved_exts;
  svn_boolean_t server_supports_depth;
  struct svn_client__dirent_fetcher_baton_t dfb;
  svn_config_t *cfg = ctx->config ? apr_hash_get(ctx->config,
                                                 SVN_CONFIG_CATEGORY_CONFIG,
                                                 APR_HASH_KEY_STRING)
                                  : NULL;

  /* An unknown depth can't be sticky. */
  if (depth == svn_depth_unknown)
    depth_is_sticky = FALSE;

  /* Do not support the situation of both exclude and switch a target. */
  if (depth == svn_depth_exclude)
    return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                             _("Cannot both exclude and switch a path"));

  /* Get the external diff3, if any. */
  svn_config_get(cfg, &diff3_cmd, SVN_CONFIG_SECTION_HELPERS,
                 SVN_CONFIG_OPTION_DIFF3_CMD, NULL);

  if (diff3_cmd != NULL)
    SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, pool));

  /* See if the user wants last-commit timestamps instead of current ones. */
  SVN_ERR(svn_config_get_bool(cfg, &use_commit_times,
                              SVN_CONFIG_SECTION_MISCELLANY,
                              SVN_CONFIG_OPTION_USE_COMMIT_TIMES, FALSE));

  {
    svn_boolean_t has_working;
    SVN_ERR(svn_wc__node_has_working(&has_working, ctx->wc_ctx, local_abspath,
                                     pool));

    if (has_working)
      return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                               _("Cannot switch '%s' because it is not in the "
                                 "repository yet"),
                               svn_dirent_local_style(local_abspath, pool));
  }

  /* See which files the user wants to preserve the extension of when
     conflict files are made. */
  svn_config_get(cfg, &preserved_exts_str, SVN_CONFIG_SECTION_MISCELLANY,
                 SVN_CONFIG_OPTION_PRESERVED_CF_EXTS, "");
  preserved_exts = *preserved_exts_str
    ? svn_cstring_split(preserved_exts_str, "\n\r\t\v ", FALSE, pool)
    : NULL;

  /* Sanity check.  Without these, the switch is meaningless. */
  SVN_ERR_ASSERT(switch_url && (switch_url[0] != '\0'));

  if (strcmp(local_abspath, anchor_abspath))
    target = svn_dirent_basename(local_abspath, pool);
  else
    target = "";

  SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, anchor_abspath, pool, pool));
  if (! url)
    return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL,
                             _("Directory '%s' has no URL"),
                             svn_dirent_local_style(anchor_abspath, pool));

  /* We may need to crop the tree if the depth is sticky */
  if (depth_is_sticky && depth < svn_depth_infinity)
    {
      svn_node_kind_t target_kind;

      if (depth == svn_depth_exclude)
        {
          SVN_ERR(svn_wc_exclude(ctx->wc_ctx,
                                 local_abspath,
                                 ctx->cancel_func, ctx->cancel_baton,
                                 ctx->notify_func2, ctx->notify_baton2,
                                 pool));

          /* Target excluded, we are done now */
          return SVN_NO_ERROR;
        }

      SVN_ERR(svn_wc_read_kind(&target_kind, ctx->wc_ctx, local_abspath, TRUE,
                               pool));

      if (target_kind == svn_node_dir)
        SVN_ERR(svn_wc_crop_tree2(ctx->wc_ctx, local_abspath, depth,
                                  ctx->cancel_func, ctx->cancel_baton,
                                  ctx->notify_func2, ctx->notify_baton2,
                                  pool));
    }

  /* Open an RA session to 'source' URL */
  SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum,
                                           &switch_rev_url,
                                           switch_url, anchor_abspath,
                                           peg_revision, revision,
                                           ctx, pool));

  SVN_ERR(svn_ra_get_repos_root2(ra_session, &source_root, pool));

  /* Disallow a switch operation to change the repository root of the
     target. */
  if (! svn_uri__is_ancestor(source_root, url))
    return svn_error_createf(SVN_ERR_WC_INVALID_SWITCH, NULL,
                             _("'%s'\nis not the same repository as\n'%s'"),
                             url, source_root);

  /* If we're not ignoring ancestry, then error out if the switch
     source and target don't have a common ancestory.

     ### We're acting on the anchor here, not the target.  Is that
     ### okay? */
  if (! ignore_ancestry)
    {
      const char *target_url, *yc_path;
      svn_revnum_t target_rev, yc_rev;

      SVN_ERR(svn_wc__node_get_url(&target_url, ctx->wc_ctx, local_abspath,
                                   pool, pool));
      SVN_ERR(svn_wc__node_get_base_rev(&target_rev, ctx->wc_ctx,
                                        local_abspath, pool));
      /* ### It would be nice if this function could reuse the existing
             ra session instead of opening two for its own use. */
      SVN_ERR(svn_client__get_youngest_common_ancestor(&yc_path, &yc_rev,
                                                       switch_rev_url, revnum,
                                                       target_url, target_rev,
                                                       ctx, pool));
      if (! (yc_path && SVN_IS_VALID_REVNUM(yc_rev)))
        return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
                                 _("'%s' shares no common ancestry with '%s'"),
                                 switch_url, local_abspath);
    }


  SVN_ERR(svn_ra_reparent(ra_session, url, pool));

  /* Fetch the switch (update) editor.  If REVISION is invalid, that's
     okay; the RA driver will call editor->set_target_revision() later on. */
  SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
                                SVN_RA_CAPABILITY_DEPTH, pool));

  dfb.ra_session = ra_session;
  SVN_ERR(svn_ra_get_session_url(ra_session, &dfb.anchor_url, pool));
  dfb.target_revision = revnum;

  SVN_ERR(svn_wc_get_switch_editor4(&switch_editor, &switch_edit_baton,
                                    &revnum, ctx->wc_ctx, anchor_abspath,
                                    target, switch_rev_url, use_commit_times,
                                    depth,
                                    depth_is_sticky, allow_unver_obstructions,
                                    server_supports_depth,
                                    diff3_cmd, preserved_exts,
                                    svn_client__dirent_fetcher, &dfb,
                                    ctx->conflict_func2, ctx->conflict_baton2,
                                    NULL, NULL,
                                    ctx->cancel_func, ctx->cancel_baton,
                                    ctx->notify_func2, ctx->notify_baton2,
                                    pool, pool));

  /* Tell RA to do an update of URL+TARGET to REVISION; if we pass an
     invalid revnum, that means RA will use the latest revision. */
  SVN_ERR(svn_ra_do_switch2(ra_session, &reporter, &report_baton, revnum,
                            target,
                            depth_is_sticky ? depth : svn_depth_unknown,
                            switch_rev_url,
                            switch_editor, switch_edit_baton, pool));

  /* 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.

     We pass in an external_func for recording all externals. It
     shouldn't be needed for a switch if it wasn't for the relative
     externals of type '../path'. All of those must be resolved to
     the new location.  */
  err = svn_wc_crawl_revisions5(ctx->wc_ctx, local_abspath, reporter,
                                report_baton, TRUE, depth, (! depth_is_sticky),
                                (! server_supports_depth),
                                use_commit_times,
                                ctx->cancel_func, ctx->cancel_baton,
                                ctx->notify_func2, ctx->notify_baton2, pool);

  if (err)
    {
      /* Don't rely on the error handling to handle the sleep later, do
         it now */
      svn_io_sleep_for_timestamps(local_abspath, pool);
      return svn_error_trace(err);
    }
  *use_sleep = TRUE;

  /* We handle externals after the switch is complete, so that
     handling external items (and any errors therefrom) doesn't delay
     the primary operation. */
  if (SVN_DEPTH_IS_RECURSIVE(depth) && (! ignore_externals))
    {
      apr_hash_t *new_externals;
      apr_hash_t *new_depths;
      SVN_ERR(svn_wc__externals_gather_definitions(&new_externals,
                                                   &new_depths,
                                                   ctx->wc_ctx, local_abspath,
                                                   depth, pool, pool));

      SVN_ERR(svn_client__handle_externals(new_externals,
                                           new_depths,
                                           source_root, local_abspath,
                                           depth, use_sleep,
                                           ctx, pool));
    }

  /* Sleep to ensure timestamp integrity (we do this regardless of
     errors in the actual switch operation(s)). */
  if (sleep_here)
    svn_io_sleep_for_timestamps(local_abspath, pool);

  /* Return errors we might have sustained. */
  if (err)
    return svn_error_trace(err);

  /* Let everyone know we're finished here. */
  if (ctx->notify_func2)
    {
      svn_wc_notify_t *notify
        = svn_wc_create_notify(anchor_abspath, svn_wc_notify_update_completed,
                               pool);
      notify->kind = svn_node_none;
      notify->content_state = notify->prop_state
        = svn_wc_notify_state_inapplicable;
      notify->lock_state = svn_wc_notify_lock_state_inapplicable;
      notify->revision = revnum;
      (*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
    }

  /* If the caller wants the result revision, give it to them. */
  if (result_rev)
    *result_rev = revnum;

  return SVN_NO_ERROR;
}
コード例 #7
0
ファイル: externals.c プロジェクト: ngkaho1234/freebsd
/* Try to update a directory external at PATH to URL at REVISION.
   Use POOL for temporary allocations, and use the client context CTX. */
static svn_error_t *
switch_dir_external(const char *local_abspath,
                    const char *url,
                    const char *url_from_externals_definition,
                    const svn_opt_revision_t *peg_revision,
                    const svn_opt_revision_t *revision,
                    const char *defining_abspath,
                    svn_boolean_t *timestamp_sleep,
                    svn_client_ctx_t *ctx,
                    apr_pool_t *pool)
{
  svn_node_kind_t kind;
  svn_error_t *err;
  svn_revnum_t external_peg_rev = SVN_INVALID_REVNUM;
  svn_revnum_t external_rev = SVN_INVALID_REVNUM;
  apr_pool_t *subpool = svn_pool_create(pool);
  const char *repos_root_url;
  const char *repos_uuid;

  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));

  if (peg_revision->kind == svn_opt_revision_number)
    external_peg_rev = peg_revision->value.number;

  if (revision->kind == svn_opt_revision_number)
    external_rev = revision->value.number;

  /* 
   * The code below assumes existing versioned paths are *not* part of
   * the external's defining working copy.
   * The working copy library does not support registering externals
   * on top of existing BASE nodes and will error out if we try.
   * So if the external target is part of the defining working copy's
   * BASE tree, don't attempt to create the external. Doing so would
   * leave behind a switched path instead of an external (since the
   * switch succeeds but registration of the external in the DB fails).
   * The working copy then cannot be updated until the path is switched back.
   * See issue #4085.
   */
  SVN_ERR(svn_wc__node_get_base(&kind, NULL, NULL,
                                &repos_root_url, &repos_uuid,
                                NULL, ctx->wc_ctx, local_abspath,
                                TRUE, /* ignore_enoent */
                                TRUE, /* show hidden */
                                pool, pool));
  if (kind != svn_node_unknown)
    {
      const char *wcroot_abspath;
      const char *defining_wcroot_abspath;

      SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath, ctx->wc_ctx,
                                 local_abspath, pool, pool));
      SVN_ERR(svn_wc__get_wcroot(&defining_wcroot_abspath, ctx->wc_ctx,
                                 defining_abspath, pool, pool));
      if (strcmp(wcroot_abspath, defining_wcroot_abspath) == 0)
        return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
                                 _("The external '%s' defined in %s at '%s' "
                                   "cannot be checked out because '%s' is "
                                   "already a versioned path."),
                                   url_from_externals_definition,
                                   SVN_PROP_EXTERNALS,
                                   svn_dirent_local_style(defining_abspath,
                                                          pool),
                                   svn_dirent_local_style(local_abspath,
                                                          pool));
    }

  /* If path is a directory, try to update/switch to the correct URL
     and revision. */
  SVN_ERR(svn_io_check_path(local_abspath, &kind, pool));
  if (kind == svn_node_dir)
    {
      const char *node_url;

      /* Doubles as an "is versioned" check. */
      err = svn_wc__node_get_url(&node_url, ctx->wc_ctx, local_abspath,
                                 pool, subpool);
      if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
        {
          svn_error_clear(err);
          err = SVN_NO_ERROR;
          goto relegate;
        }
      else if (err)
        return svn_error_trace(err);

      if (node_url)
        {
          /* If we have what appears to be a version controlled
             subdir, and its top-level URL matches that of our
             externals definition, perform an update. */
          if (strcmp(node_url, url) == 0)
            {
              SVN_ERR(svn_client__update_internal(NULL, local_abspath,
                                                  revision, svn_depth_unknown,
                                                  FALSE, FALSE, FALSE, TRUE,
                                                  FALSE, TRUE,
                                                  timestamp_sleep,
                                                  ctx, subpool));

              /* We just decided that this existing directory is an external,
                 so update the external registry with this information, like
                 when checking out an external */
              SVN_ERR(svn_wc__external_register(ctx->wc_ctx,
                                    defining_abspath,
                                    local_abspath, svn_node_dir,
                                    repos_root_url, repos_uuid,
                                    svn_uri_skip_ancestor(repos_root_url,
                                                          url, pool),
                                    external_peg_rev,
                                    external_rev,
                                    pool));

              svn_pool_destroy(subpool);
              goto cleanup;
            }

          /* We'd really prefer not to have to do a brute-force
             relegation -- blowing away the current external working
             copy and checking it out anew -- so we'll first see if we
             can get away with a generally cheaper relocation (if
             required) and switch-style update.

             To do so, we need to know the repository root URL of the
             external working copy as it currently sits. */
          err = svn_wc__node_get_repos_info(NULL, NULL,
                                            &repos_root_url, &repos_uuid,
                                            ctx->wc_ctx, local_abspath,
                                            pool, subpool);
          if (err)
            {
              if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND
                  && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
                return svn_error_trace(err);

              svn_error_clear(err);
              repos_root_url = NULL;
              repos_uuid = NULL;
            }

          if (repos_root_url)
            {
              /* If the new external target URL is not obviously a
                 child of the external working copy's current
                 repository root URL... */
              if (! svn_uri__is_ancestor(repos_root_url, url))
                {
                  const char *repos_root;

                  /* ... then figure out precisely which repository
                      root URL that target URL *is* a child of ... */
                  SVN_ERR(svn_client_get_repos_root(&repos_root, NULL, url,
                                                    ctx, subpool, subpool));

                  /* ... and use that to try to relocate the external
                     working copy to the target location.  */
                  err = svn_client_relocate2(local_abspath, repos_root_url,
                                             repos_root, FALSE, ctx, subpool);

                  /* If the relocation failed because the new URL
                     points to a totally different repository, we've
                     no choice but to relegate and check out a new WC. */
                  if (err
                      && (err->apr_err == SVN_ERR_WC_INVALID_RELOCATION
                          || (err->apr_err
                              == SVN_ERR_CLIENT_INVALID_RELOCATION)))
                    {
                      svn_error_clear(err);
                      goto relegate;
                    }
                  else if (err)
                    return svn_error_trace(err);

                  /* If the relocation went without a hitch, we should
                     have a new repository root URL. */
                  repos_root_url = repos_root;
                }

              SVN_ERR(svn_client__switch_internal(NULL, local_abspath, url,
                                                  peg_revision, revision,
                                                  svn_depth_infinity,
                                                  TRUE, FALSE, FALSE,
                                                  TRUE /* ignore_ancestry */,
                                                  timestamp_sleep,
                                                  ctx, subpool));

              SVN_ERR(svn_wc__external_register(ctx->wc_ctx,
                                                defining_abspath,
                                                local_abspath, svn_node_dir,
                                                repos_root_url, repos_uuid,
                                                svn_uri_skip_ancestor(
                                                            repos_root_url,
                                                            url, subpool),
                                                external_peg_rev,
                                                external_rev,
                                                subpool));

              svn_pool_destroy(subpool);
              goto cleanup;
            }
        }
    }

 relegate:

  /* Fall back on removing the WC and checking out a new one. */

  /* Ensure that we don't have any RA sessions or WC locks from failed
     operations above. */
  svn_pool_destroy(subpool);

  if (kind == svn_node_dir)
    {
      /* Buh-bye, old and busted ... */
      SVN_ERR(relegate_dir_external(ctx->wc_ctx, defining_abspath,
                                    local_abspath,
                                    ctx->cancel_func, ctx->cancel_baton,
                                    ctx->notify_func2, ctx->notify_baton2,
                                    pool));
    }
  else
    {
      /* The target dir might have multiple components.  Guarantee
         the path leading down to the last component. */
      const char *parent = svn_dirent_dirname(local_abspath, pool);
      SVN_ERR(svn_io_make_dir_recursively(parent, pool));
    }

  /* ... Hello, new hotness. */
  SVN_ERR(svn_client__checkout_internal(NULL, url, local_abspath, peg_revision,
                                        revision, svn_depth_infinity,
                                        FALSE, FALSE, timestamp_sleep,
                                        ctx, pool));

  SVN_ERR(svn_wc__node_get_repos_info(NULL, NULL,
                                      &repos_root_url,
                                      &repos_uuid,
                                      ctx->wc_ctx, local_abspath,
                                      pool, pool));

  SVN_ERR(svn_wc__external_register(ctx->wc_ctx,
                                    defining_abspath,
                                    local_abspath, svn_node_dir,
                                    repos_root_url, repos_uuid,
                                    svn_uri_skip_ancestor(repos_root_url,
                                                          url, pool),
                                    external_peg_rev,
                                    external_rev,
                                    pool));

 cleanup:
  /* Issues #4123 and #4130: We don't need to keep the newly checked
     out external's DB open. */
  SVN_ERR(svn_wc__close_db(local_abspath, ctx->wc_ctx, pool));

  return SVN_NO_ERROR;
}
コード例 #8
0
ファイル: switch.c プロジェクト: geofft/subversion
/* ...

   Add the paths of any conflict victims to CONFLICTED_PATHS, if that
   is not null.
*/
static svn_error_t *
switch_internal(svn_revnum_t *result_rev,
                apr_hash_t *conflicted_paths,
                const char *local_abspath,
                const char *anchor_abspath,
                const char *switch_url,
                const svn_opt_revision_t *peg_revision,
                const svn_opt_revision_t *revision,
                svn_depth_t depth,
                svn_boolean_t depth_is_sticky,
                svn_boolean_t ignore_externals,
                svn_boolean_t allow_unver_obstructions,
                svn_boolean_t ignore_ancestry,
                svn_boolean_t *timestamp_sleep,
                svn_client_ctx_t *ctx,
                apr_pool_t *pool)
{
  const svn_ra_reporter3_t *reporter;
  void *report_baton;
  const char *anchor_url, *target;
  svn_client__pathrev_t *switch_loc;
  svn_ra_session_t *ra_session;
  svn_revnum_t revnum;
  const char *diff3_cmd;
  apr_hash_t *wcroot_iprops;
  apr_array_header_t *inherited_props;
  svn_boolean_t use_commit_times;
  const svn_delta_editor_t *switch_editor;
  void *switch_edit_baton;
  const char *preserved_exts_str;
  apr_array_header_t *preserved_exts;
  svn_boolean_t server_supports_depth;
  struct svn_client__dirent_fetcher_baton_t dfb;
  svn_config_t *cfg = ctx->config
                      ? svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG)
                      : NULL;

  /* An unknown depth can't be sticky. */
  if (depth == svn_depth_unknown)
    depth_is_sticky = FALSE;

  /* Do not support the situation of both exclude and switch a target. */
  if (depth == svn_depth_exclude)
    return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                             _("Cannot both exclude and switch a path"));

  /* Get the external diff3, if any. */
  svn_config_get(cfg, &diff3_cmd, SVN_CONFIG_SECTION_HELPERS,
                 SVN_CONFIG_OPTION_DIFF3_CMD, NULL);

  if (diff3_cmd != NULL)
    SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, pool));

  /* See if the user wants last-commit timestamps instead of current ones. */
  SVN_ERR(svn_config_get_bool(cfg, &use_commit_times,
                              SVN_CONFIG_SECTION_MISCELLANY,
                              SVN_CONFIG_OPTION_USE_COMMIT_TIMES, FALSE));

  {
    svn_boolean_t has_working;
    SVN_ERR(svn_wc__node_has_working(&has_working, ctx->wc_ctx, local_abspath,
                                     pool));

    if (has_working)
      return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                               _("Cannot switch '%s' because it is not in the "
                                 "repository yet"),
                               svn_dirent_local_style(local_abspath, pool));
  }

  /* See which files the user wants to preserve the extension of when
     conflict files are made. */
  svn_config_get(cfg, &preserved_exts_str, SVN_CONFIG_SECTION_MISCELLANY,
                 SVN_CONFIG_OPTION_PRESERVED_CF_EXTS, "");
  preserved_exts = *preserved_exts_str
    ? svn_cstring_split(preserved_exts_str, "\n\r\t\v ", FALSE, pool)
    : NULL;

  /* Sanity check.  Without these, the switch is meaningless. */
  SVN_ERR_ASSERT(switch_url && (switch_url[0] != '\0'));

  if (strcmp(local_abspath, anchor_abspath))
    target = svn_dirent_basename(local_abspath, pool);
  else
    target = "";

  SVN_ERR(svn_wc__node_get_url(&anchor_url, ctx->wc_ctx, anchor_abspath,
                               pool, pool));
  if (! anchor_url)
    return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL,
                             _("Directory '%s' has no URL"),
                             svn_dirent_local_style(anchor_abspath, pool));

  /* We may need to crop the tree if the depth is sticky */
  if (depth_is_sticky && depth < svn_depth_infinity)
    {
      svn_node_kind_t target_kind;

      if (depth == svn_depth_exclude)
        {
          SVN_ERR(svn_wc_exclude(ctx->wc_ctx,
                                 local_abspath,
                                 ctx->cancel_func, ctx->cancel_baton,
                                 ctx->notify_func2, ctx->notify_baton2,
                                 pool));

          /* Target excluded, we are done now */
          return SVN_NO_ERROR;
        }

      SVN_ERR(svn_wc_read_kind2(&target_kind, ctx->wc_ctx, local_abspath,
                                TRUE, TRUE, pool));

      if (target_kind == svn_node_dir)
        SVN_ERR(svn_wc_crop_tree2(ctx->wc_ctx, local_abspath, depth,
                                  ctx->cancel_func, ctx->cancel_baton,
                                  ctx->notify_func2, ctx->notify_baton2,
                                  pool));
    }

  /* Open an RA session to 'source' URL */
  SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &switch_loc,
                                            switch_url, anchor_abspath,
                                            peg_revision, revision,
                                            ctx, pool));

  /* Disallow a switch operation to change the repository root of the
     target. */
  if (! svn_uri__is_ancestor(switch_loc->repos_root_url, anchor_url))
    return svn_error_createf(SVN_ERR_WC_INVALID_SWITCH, NULL,
                             _("'%s'\nis not the same repository as\n'%s'"),
                             anchor_url, switch_loc->repos_root_url);

  /* If we're not ignoring ancestry, then error out if the switch
     source and target don't have a common ancestory.

     ### We're acting on the anchor here, not the target.  Is that
     ### okay? */
  if (! ignore_ancestry)
    {
      svn_client__pathrev_t *target_base_loc, *yca;

      SVN_ERR(svn_client__wc_node_get_base(&target_base_loc, local_abspath,
                                           ctx->wc_ctx, pool, pool));

      if (!target_base_loc)
        yca = NULL; /* Not versioned */
      else
        {
          SVN_ERR(svn_client__get_youngest_common_ancestor(
                  &yca, switch_loc, target_base_loc, ra_session, ctx,
                  pool, pool));
        }
      if (! yca)
        return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
                                 _("'%s' shares no common ancestry with '%s'"),
                                 switch_url,
                                 svn_dirent_local_style(local_abspath, pool));
    }

  wcroot_iprops = apr_hash_make(pool);

  /* Will the base of LOCAL_ABSPATH require an iprop cache post-switch?
     If we are switching LOCAL_ABSPATH to the root of the repository then
     we don't need to cache inherited properties.  In all other cases we
     *might* need to cache iprops. */
  if (strcmp(switch_loc->repos_root_url, switch_loc->url) != 0)
    {
      svn_boolean_t wc_root;
      svn_boolean_t needs_iprop_cache = TRUE;

      SVN_ERR(svn_wc__is_wcroot(&wc_root, ctx->wc_ctx, local_abspath,
                                pool));

      /* Switching the WC root to anything but the repos root means
         we need an iprop cache. */
      if (!wc_root)
        {
          /* We know we are switching a subtree to something other than the
             repos root, but if we are unswitching that subtree we don't
             need an iprops cache. */
          const char *target_parent_url;
          const char *unswitched_url;

          /* Calculate the URL LOCAL_ABSPATH would have if it was unswitched
             relative to its parent. */
          SVN_ERR(svn_wc__node_get_url(&target_parent_url, ctx->wc_ctx,
                                       svn_dirent_dirname(local_abspath,
                                                          pool),
                                       pool, pool));
          unswitched_url = svn_path_url_add_component2(
            target_parent_url,
            svn_dirent_basename(local_abspath, pool),
            pool);

          /* If LOCAL_ABSPATH will be unswitched relative to its parent, then
             it doesn't need an iprop cache.  Note: It doesn't matter if
             LOCAL_ABSPATH is withing a switched subtree, only if it's the
             *root* of a switched subtree.*/
          if (strcmp(unswitched_url, switch_loc->url) == 0)
            needs_iprop_cache = FALSE;
      }


      if (needs_iprop_cache)
        {
          SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props,
                                             "", switch_loc->rev, pool,
                                             pool));
          svn_hash_sets(wcroot_iprops, local_abspath, inherited_props);
        }
    }

  SVN_ERR(svn_ra_reparent(ra_session, anchor_url, pool));

  /* Fetch the switch (update) editor.  If REVISION is invalid, that's
     okay; the RA driver will call editor->set_target_revision() later on. */
  SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
                                SVN_RA_CAPABILITY_DEPTH, pool));

  dfb.ra_session = ra_session;
  dfb.anchor_url = anchor_url;
  dfb.target_revision = switch_loc->rev;

  SVN_ERR(svn_wc__get_switch_editor(&switch_editor, &switch_edit_baton,
                                    &revnum, ctx->wc_ctx, anchor_abspath,
                                    target, switch_loc->url, wcroot_iprops,
                                    use_commit_times, depth,
                                    depth_is_sticky, allow_unver_obstructions,
                                    server_supports_depth,
                                    diff3_cmd, preserved_exts,
                                    svn_client__dirent_fetcher, &dfb,
                                    conflicted_paths ? record_conflict : NULL,
                                    conflicted_paths,
                                    NULL, NULL,
                                    ctx->cancel_func, ctx->cancel_baton,
                                    ctx->notify_func2, ctx->notify_baton2,
                                    pool, pool));

  /* Tell RA to do an update of URL+TARGET to REVISION; if we pass an
     invalid revnum, that means RA will use the latest revision. */
  SVN_ERR(svn_ra_do_switch3(ra_session, &reporter, &report_baton,
                            switch_loc->rev,
                            target,
                            depth_is_sticky ? depth : svn_depth_unknown,
                            switch_loc->url,
                            FALSE /* send_copyfrom_args */,
                            ignore_ancestry,
                            switch_editor, switch_edit_baton,
                            pool, pool));

  /* Past this point, we assume the WC is going to be modified so we will
   * need to sleep for timestamps. */
  *timestamp_sleep = TRUE;

  /* Drive the reporter structure, describing the revisions within
     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),
                                  (! server_supports_depth),
                                  use_commit_times,
                                  ctx->cancel_func, ctx->cancel_baton,
                                  ctx->notify_func2, ctx->notify_baton2,
                                  pool));

  /* We handle externals after the switch is complete, so that
     handling external items (and any errors therefrom) doesn't delay
     the primary operation. */
  if (SVN_DEPTH_IS_RECURSIVE(depth) && (! ignore_externals))
    {
      apr_hash_t *new_externals;
      apr_hash_t *new_depths;
      SVN_ERR(svn_wc__externals_gather_definitions(&new_externals,
                                                   &new_depths,
                                                   ctx->wc_ctx, local_abspath,
                                                   depth, pool, pool));

      SVN_ERR(svn_client__handle_externals(new_externals,
                                           new_depths,
                                           switch_loc->repos_root_url,
                                           local_abspath,
                                           depth, timestamp_sleep,
                                           ctx, pool));
    }

  /* Let everyone know we're finished here. */
  if (ctx->notify_func2)
    {
      svn_wc_notify_t *notify
        = svn_wc_create_notify(anchor_abspath, svn_wc_notify_update_completed,
                               pool);
      notify->kind = svn_node_none;
      notify->content_state = notify->prop_state
        = svn_wc_notify_state_inapplicable;
      notify->lock_state = svn_wc_notify_lock_state_inapplicable;
      notify->revision = revnum;
      (*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
    }

  /* If the caller wants the result revision, give it to them. */
  if (result_rev)
    *result_rev = revnum;

  return SVN_NO_ERROR;
}
コード例 #9
0
ファイル: old-and-busted.c プロジェクト: Ranga123/test1
/* NOTE: this is used for upgrading old XML-based entries file. Be wary of
         removing items.

   ### many attributes are no longer used within the old-style log files.
   ### These attrs need to be recognized for old entries, however. For these
   ### cases, the code will parse the attribute, but not set *MODIFY_FLAGS
   ### for that particular field. MODIFY_FLAGS is *only* used by the
   ### log-based entry modification system, and will go way once we
   ### completely move away from loggy.

   Set *NEW_ENTRY to a new entry, taking attributes from ATTS, whose
   keys and values are both char *.  Allocate the entry and copy
   attributes into POOL as needed. */
static svn_error_t *
atts_to_entry(svn_wc_entry_t **new_entry,
              apr_hash_t *atts,
              apr_pool_t *pool)
{
    svn_wc_entry_t *entry = alloc_entry(pool);
    const char *name;

    /* Find the name and set up the entry under that name. */
    name = svn_hash_gets(atts, ENTRIES_ATTR_NAME);
    entry->name = name ? apr_pstrdup(pool, name) : SVN_WC_ENTRY_THIS_DIR;

    /* Attempt to set revision (resolve_to_defaults may do it later, too)

       ### not used by loggy; no need to set MODIFY_FLAGS  */
    {
        const char *revision_str
            = svn_hash_gets(atts, ENTRIES_ATTR_REVISION);

        if (revision_str)
            entry->revision = SVN_STR_TO_REV(revision_str);
        else
            entry->revision = SVN_INVALID_REVNUM;
    }

    /* Attempt to set up url path (again, see resolve_to_defaults).

       ### not used by loggy; no need to set MODIFY_FLAGS  */
    entry->url = extract_string(atts, ENTRIES_ATTR_URL, pool);
    if (entry->url)
        entry->url = svn_uri_canonicalize(entry->url, pool);

    /* Set up repository root.  Make sure it is a prefix of url.

       ### not used by loggy; no need to set MODIFY_FLAGS  */
    entry->repos = extract_string(atts, ENTRIES_ATTR_REPOS, pool);
    if (entry->repos)
        entry->repos = svn_uri_canonicalize(entry->repos, pool);

    if (entry->url && entry->repos
            && !svn_uri__is_ancestor(entry->repos, entry->url))
        return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
                                 _("Entry for '%s' has invalid repository "
                                   "root"),
                                 name ? name : SVN_WC_ENTRY_THIS_DIR);

    /* Set up kind. */
    /* ### not used by loggy; no need to set MODIFY_FLAGS  */
    {
        const char *kindstr
            = svn_hash_gets(atts, ENTRIES_ATTR_KIND);

        entry->kind = svn_node_none;
        if (kindstr)
        {
            if (strcmp(kindstr, ENTRIES_VALUE_FILE) == 0)
                entry->kind = svn_node_file;
            else if (strcmp(kindstr, ENTRIES_VALUE_DIR) == 0)
                entry->kind = svn_node_dir;
            else
                return svn_error_createf
                       (SVN_ERR_NODE_UNKNOWN_KIND, NULL,
                        _("Entry '%s' has invalid node kind"),
                        (name ? name : SVN_WC_ENTRY_THIS_DIR));
        }
    }

    /* Look for a schedule attribute on this entry. */
    /* ### not used by loggy; no need to set MODIFY_FLAGS  */
    {
        const char *schedulestr
            = svn_hash_gets(atts, ENTRIES_ATTR_SCHEDULE);

        entry->schedule = svn_wc_schedule_normal;
        if (schedulestr)
        {
            if (strcmp(schedulestr, ENTRIES_VALUE_ADD) == 0)
                entry->schedule = svn_wc_schedule_add;
            else if (strcmp(schedulestr, ENTRIES_VALUE_DELETE) == 0)
                entry->schedule = svn_wc_schedule_delete;
            else if (strcmp(schedulestr, ENTRIES_VALUE_REPLACE) == 0)
                entry->schedule = svn_wc_schedule_replace;
            else if (strcmp(schedulestr, "") == 0)
                entry->schedule = svn_wc_schedule_normal;
            else
                return svn_error_createf(
                           SVN_ERR_ENTRY_ATTRIBUTE_INVALID, NULL,
                           _("Entry '%s' has invalid 'schedule' value"),
                           (name ? name : SVN_WC_ENTRY_THIS_DIR));
        }
    }

    /* Is this entry in a state of mental torment (conflict)? */
    entry->prejfile = extract_string_normalize(atts,
                      ENTRIES_ATTR_PREJFILE,
                      pool);
    entry->conflict_old = extract_string_normalize(atts,
                          ENTRIES_ATTR_CONFLICT_OLD,
                          pool);
    entry->conflict_new = extract_string_normalize(atts,
                          ENTRIES_ATTR_CONFLICT_NEW,
                          pool);
    entry->conflict_wrk = extract_string_normalize(atts,
                          ENTRIES_ATTR_CONFLICT_WRK,
                          pool);

    /* Is this entry copied? */
    /* ### not used by loggy; no need to set MODIFY_FLAGS  */
    SVN_ERR(do_bool_attr(&entry->copied, atts, ENTRIES_ATTR_COPIED, name));

    /* ### not used by loggy; no need to set MODIFY_FLAGS  */
    entry->copyfrom_url = extract_string(atts, ENTRIES_ATTR_COPYFROM_URL, pool);

    /* ### not used by loggy; no need to set MODIFY_FLAGS  */
    {
        const char *revstr;

        revstr = svn_hash_gets(atts, ENTRIES_ATTR_COPYFROM_REV);
        if (revstr)
            entry->copyfrom_rev = SVN_STR_TO_REV(revstr);
    }

    /* Is this entry deleted?

       ### not used by loggy; no need to set MODIFY_FLAGS  */
    SVN_ERR(do_bool_attr(&entry->deleted, atts, ENTRIES_ATTR_DELETED, name));

    /* Is this entry absent?

       ### not used by loggy; no need to set MODIFY_FLAGS  */
    SVN_ERR(do_bool_attr(&entry->absent, atts, ENTRIES_ATTR_ABSENT, name));

    /* Is this entry incomplete?

       ### not used by loggy; no need to set MODIFY_FLAGS  */
    SVN_ERR(do_bool_attr(&entry->incomplete, atts, ENTRIES_ATTR_INCOMPLETE,
                         name));

    /* Attempt to set up timestamps. */
    /* ### not used by loggy; no need to set MODIFY_FLAGS  */
    {
        const char *text_timestr;

        text_timestr = svn_hash_gets(atts, ENTRIES_ATTR_TEXT_TIME);
        if (text_timestr)
            SVN_ERR(svn_time_from_cstring(&entry->text_time, text_timestr, pool));

        /* Note: we do not persist prop_time, so there is no need to attempt
           to parse a new prop_time value from the log. Certainly, on any
           recent working copy, there will not be a log record to alter
           the prop_time value. */
    }

    /* Checksum. */
    /* ### not used by loggy; no need to set MODIFY_FLAGS  */
    entry->checksum = extract_string(atts, ENTRIES_ATTR_CHECKSUM, pool);

    /* UUID.

       ### not used by loggy; no need to set MODIFY_FLAGS  */
    entry->uuid = extract_string(atts, ENTRIES_ATTR_UUID, pool);

    /* Setup last-committed values. */
    {
        const char *cmt_datestr, *cmt_revstr;

        cmt_datestr = svn_hash_gets(atts, ENTRIES_ATTR_CMT_DATE);
        if (cmt_datestr)
        {
            SVN_ERR(svn_time_from_cstring(&entry->cmt_date, cmt_datestr, pool));
        }
        else
            entry->cmt_date = 0;

        cmt_revstr = svn_hash_gets(atts, ENTRIES_ATTR_CMT_REV);
        if (cmt_revstr)
        {
            entry->cmt_rev = SVN_STR_TO_REV(cmt_revstr);
        }
        else
            entry->cmt_rev = SVN_INVALID_REVNUM;

        entry->cmt_author = extract_string(atts, ENTRIES_ATTR_CMT_AUTHOR, pool);
    }

    /* ### not used by loggy; no need to set MODIFY_FLAGS  */
    entry->lock_token = extract_string(atts, ENTRIES_ATTR_LOCK_TOKEN, pool);
    entry->lock_owner = extract_string(atts, ENTRIES_ATTR_LOCK_OWNER, pool);
    entry->lock_comment = extract_string(atts, ENTRIES_ATTR_LOCK_COMMENT, pool);
    {
        const char *cdate_str =
            svn_hash_gets(atts, ENTRIES_ATTR_LOCK_CREATION_DATE);
        if (cdate_str)
        {
            SVN_ERR(svn_time_from_cstring(&entry->lock_creation_date,
                                          cdate_str, pool));
        }
    }
    /* ----- end of lock handling.  */

    /* Note: if there are attributes for the (deprecated) has_props,
       has_prop_mods, cachable_props, or present_props, then we're just
       going to ignore them. */

    /* Translated size */
    /* ### not used by loggy; no need to set MODIFY_FLAGS  */
    {
        const char *val = svn_hash_gets(atts, ENTRIES_ATTR_WORKING_SIZE);
        if (val)
        {
            /* Cast to off_t; it's safe: we put in an off_t to start with... */
            entry->working_size = (apr_off_t)apr_strtoi64(val, NULL, 0);
        }
    }

    *new_entry = entry;
    return SVN_NO_ERROR;
}
コード例 #10
0
ファイル: old-and-busted.c プロジェクト: Ranga123/test1
/* Allocate an entry from POOL and read it from [*BUF, END).  The
   buffer may be modified in place while parsing.  Return the new
   entry in *NEW_ENTRY.  Advance *BUF to point at the end of the entry
   record.
   The entries file format should be provided in ENTRIES_FORMAT. */
static svn_error_t *
read_entry(svn_wc_entry_t **new_entry,
           char **buf, const char *end,
           int entries_format,
           apr_pool_t *pool)
{
    svn_wc_entry_t *entry = alloc_entry(pool);
    const char *name;

#define MAYBE_DONE if (**buf == '\f') goto done

    /* Find the name and set up the entry under that name. */
    SVN_ERR(read_path(&name, buf, end, pool));
    entry->name = name ? name : SVN_WC_ENTRY_THIS_DIR;

    /* Set up kind. */
    {
        const char *kindstr;
        SVN_ERR(read_val(&kindstr, buf, end));
        if (kindstr)
        {
            if (strcmp(kindstr, ENTRIES_VALUE_FILE) == 0)
                entry->kind = svn_node_file;
            else if (strcmp(kindstr, ENTRIES_VALUE_DIR) == 0)
                entry->kind = svn_node_dir;
            else
                return svn_error_createf
                       (SVN_ERR_NODE_UNKNOWN_KIND, NULL,
                        _("Entry '%s' has invalid node kind"),
                        (name ? name : SVN_WC_ENTRY_THIS_DIR));
        }
        else
            entry->kind = svn_node_none;
    }
    MAYBE_DONE;

    /* Attempt to set revision (resolve_to_defaults may do it later, too) */
    SVN_ERR(read_revnum(&entry->revision, buf, end, pool));
    MAYBE_DONE;

    /* Attempt to set up url path (again, see resolve_to_defaults). */
    SVN_ERR(read_url(&entry->url, buf, end, entries_format, pool));
    MAYBE_DONE;

    /* Set up repository root.  Make sure it is a prefix of url. */
    SVN_ERR(read_url(&entry->repos, buf, end, entries_format, pool));
    if (entry->repos && entry->url
            && ! svn_uri__is_ancestor(entry->repos, entry->url))
        return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
                                 _("Entry for '%s' has invalid repository "
                                   "root"),
                                 name ? name : SVN_WC_ENTRY_THIS_DIR);
    MAYBE_DONE;

    /* Look for a schedule attribute on this entry. */
    {
        const char *schedulestr;
        SVN_ERR(read_val(&schedulestr, buf, end));
        entry->schedule = svn_wc_schedule_normal;
        if (schedulestr)
        {
            if (strcmp(schedulestr, ENTRIES_VALUE_ADD) == 0)
                entry->schedule = svn_wc_schedule_add;
            else if (strcmp(schedulestr, ENTRIES_VALUE_DELETE) == 0)
                entry->schedule = svn_wc_schedule_delete;
            else if (strcmp(schedulestr, ENTRIES_VALUE_REPLACE) == 0)
                entry->schedule = svn_wc_schedule_replace;
            else
                return svn_error_createf(
                           SVN_ERR_ENTRY_ATTRIBUTE_INVALID, NULL,
                           _("Entry '%s' has invalid 'schedule' value"),
                           name ? name : SVN_WC_ENTRY_THIS_DIR);
        }
    }
    MAYBE_DONE;

    /* Attempt to set up text timestamp. */
    SVN_ERR(read_time(&entry->text_time, buf, end, pool));
    MAYBE_DONE;

    /* Checksum. */
    SVN_ERR(read_str(&entry->checksum, buf, end, pool));
    MAYBE_DONE;

    /* Setup last-committed values. */
    SVN_ERR(read_time(&entry->cmt_date, buf, end, pool));
    MAYBE_DONE;

    SVN_ERR(read_revnum(&entry->cmt_rev, buf, end, pool));
    MAYBE_DONE;

    SVN_ERR(read_str(&entry->cmt_author, buf, end, pool));
    MAYBE_DONE;

    /* has-props, has-prop-mods, cachable-props, present-props are all
       deprecated. Read any values that may be in the 'entries' file, but
       discard them, and just put default values into the entry. */
    {
        const char *unused_value;

        /* has-props flag. */
        SVN_ERR(read_val(&unused_value, buf, end));
        entry->has_props = FALSE;
        MAYBE_DONE;

        /* has-prop-mods flag. */
        SVN_ERR(read_val(&unused_value, buf, end));
        entry->has_prop_mods = FALSE;
        MAYBE_DONE;

        /* Use the empty string for cachable_props, indicating that we no
           longer attempt to cache any properties. An empty string for
           present_props means that no cachable props are present. */

        /* cachable-props string. */
        SVN_ERR(read_val(&unused_value, buf, end));
        entry->cachable_props = "";
        MAYBE_DONE;

        /* present-props string. */
        SVN_ERR(read_val(&unused_value, buf, end));
        entry->present_props = "";
        MAYBE_DONE;
    }

    /* Is this entry in a state of mental torment (conflict)? */
    {
        SVN_ERR(read_path(&entry->prejfile, buf, end, pool));
        MAYBE_DONE;
        SVN_ERR(read_path(&entry->conflict_old, buf, end, pool));
        MAYBE_DONE;
        SVN_ERR(read_path(&entry->conflict_new, buf, end, pool));
        MAYBE_DONE;
        SVN_ERR(read_path(&entry->conflict_wrk, buf, end, pool));
        MAYBE_DONE;
    }

    /* Is this entry copied? */
    SVN_ERR(read_bool(&entry->copied, ENTRIES_BOOL_COPIED, buf, end));
    MAYBE_DONE;

    SVN_ERR(read_url(&entry->copyfrom_url, buf, end, entries_format, pool));
    MAYBE_DONE;
    SVN_ERR(read_revnum(&entry->copyfrom_rev, buf, end, pool));
    MAYBE_DONE;

    /* Is this entry deleted? */
    SVN_ERR(read_bool(&entry->deleted, ENTRIES_BOOL_DELETED, buf, end));
    MAYBE_DONE;

    /* Is this entry absent? */
    SVN_ERR(read_bool(&entry->absent, ENTRIES_BOOL_ABSENT, buf, end));
    MAYBE_DONE;

    /* Is this entry incomplete? */
    SVN_ERR(read_bool(&entry->incomplete, ENTRIES_BOOL_INCOMPLETE, buf, end));
    MAYBE_DONE;

    /* UUID. */
    SVN_ERR(read_str(&entry->uuid, buf, end, pool));
    MAYBE_DONE;

    /* Lock token. */
    SVN_ERR(read_str(&entry->lock_token, buf, end, pool));
    MAYBE_DONE;

    /* Lock owner. */
    SVN_ERR(read_str(&entry->lock_owner, buf, end, pool));
    MAYBE_DONE;

    /* Lock comment. */
    SVN_ERR(read_str(&entry->lock_comment, buf, end, pool));
    MAYBE_DONE;

    /* Lock creation date. */
    SVN_ERR(read_time(&entry->lock_creation_date, buf, end, pool));
    MAYBE_DONE;

    /* Changelist. */
    SVN_ERR(read_str(&entry->changelist, buf, end, pool));
    MAYBE_DONE;

    /* Keep entry in working copy after deletion? */
    SVN_ERR(read_bool(&entry->keep_local, ENTRIES_BOOL_KEEP_LOCAL, buf, end));
    MAYBE_DONE;

    /* Translated size */
    {
        const char *val;

        /* read_val() returns NULL on an empty (e.g. default) entry line,
           and entry has already been initialized accordingly already */
        SVN_ERR(read_val(&val, buf, end));
        if (val)
            entry->working_size = (apr_off_t)apr_strtoi64(val, NULL, 0);
    }
    MAYBE_DONE;

    /* Depth. */
    {
        const char *result;
        SVN_ERR(read_val(&result, buf, end));
        if (result)
        {
            svn_boolean_t invalid;
            svn_boolean_t is_this_dir;

            entry->depth = svn_depth_from_word(result);

            /* Verify the depth value:
               THIS_DIR should not have an excluded value and SUB_DIR should only
               have excluded value. Remember that infinity value is not stored and
               should not show up here. Otherwise, something bad may have
               happened. However, infinity value itself will always be okay. */
            is_this_dir = !name;
            /* '!=': XOR */
            invalid = is_this_dir != (entry->depth != svn_depth_exclude);
            if (entry->depth != svn_depth_infinity && invalid)
                return svn_error_createf(
                           SVN_ERR_ENTRY_ATTRIBUTE_INVALID, NULL,
                           _("Entry '%s' has invalid 'depth' value"),
                           name ? name : SVN_WC_ENTRY_THIS_DIR);
        }
        else
            entry->depth = svn_depth_infinity;

    }
    MAYBE_DONE;

    /* Tree conflict data. */
    SVN_ERR(read_str(&entry->tree_conflict_data, buf, end, pool));
    MAYBE_DONE;

    /* File external URL and revision. */
    {
        const char *str;
        SVN_ERR(read_str(&str, buf, end, pool));
        SVN_ERR(svn_wc__unserialize_file_external(&entry->file_external_path,
                &entry->file_external_peg_rev,
                &entry->file_external_rev,
                str,
                pool));
    }
    MAYBE_DONE;

done:
    *new_entry = entry;
    return SVN_NO_ERROR;
}
コード例 #11
0
ファイル: adm_files.c プロジェクト: DJEX93/dsploit
svn_error_t *
svn_wc__internal_ensure_adm(svn_wc__db_t *db,
                            const char *local_abspath,
                            const char *url,
                            const char *repos_root_url,
                            const char *repos_uuid,
                            svn_revnum_t revision,
                            svn_depth_t depth,
                            apr_pool_t *scratch_pool)
{
  int format;
  const char *repos_relpath;
  svn_wc__db_status_t status;
  const char *db_repos_relpath, *db_repos_root_url, *db_repos_uuid;
  svn_revnum_t db_revision;

  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
  SVN_ERR_ASSERT(url != NULL);
  SVN_ERR_ASSERT(repos_root_url != NULL);
  SVN_ERR_ASSERT(repos_uuid != NULL);
  SVN_ERR_ASSERT(svn_uri__is_ancestor(repos_root_url, url));

  SVN_ERR(svn_wc__internal_check_wc(&format, db, local_abspath, TRUE,
                                    scratch_pool));

  repos_relpath = svn_uri__is_child(repos_root_url, url, scratch_pool);
  if (repos_relpath == NULL)
    repos_relpath = "";

  /* Early out: we know we're not dealing with an existing wc, so
     just create one. */
  if (format == 0)
    return svn_error_trace(init_adm(db, local_abspath,
                                    repos_relpath, repos_root_url, repos_uuid,
                                    revision, depth, scratch_pool));

  SVN_ERR(svn_wc__db_read_info(&status, NULL,
                               &db_revision, &db_repos_relpath,
                               &db_repos_root_url, &db_repos_uuid,
                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                               NULL, NULL, NULL, NULL,
                               NULL, NULL, NULL,
                               db, local_abspath, scratch_pool, scratch_pool));

  /* When the directory exists and is scheduled for deletion or is not-present
   * do not check the revision or the URL.  The revision can be any
   * arbitrary revision and the URL may differ if the add is
   * being driven from a merge which will have a different URL. */
  if (status != svn_wc__db_status_deleted
      && status != svn_wc__db_status_not_present)
    {
      /* ### Should we match copyfrom_revision? */
      if (db_revision != revision)
        return
          svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
                            _("Revision %ld doesn't match existing "
                              "revision %ld in '%s'"),
                            revision, db_revision, local_abspath);

      if (!db_repos_root_url)
        {
          if (status == svn_wc__db_status_added)
            SVN_ERR(svn_wc__db_scan_addition(NULL, NULL,
                                             &db_repos_relpath,
                                             &db_repos_root_url,
                                             &db_repos_uuid,
                                             NULL, NULL, NULL, NULL,
                                             db, local_abspath,
                                             scratch_pool, scratch_pool));
          else
            SVN_ERR(svn_wc__db_scan_base_repos(&db_repos_relpath,
                                               &db_repos_root_url,
                                               &db_repos_uuid,
                                               db, local_abspath,
                                               scratch_pool, scratch_pool));
        }

      /* The caller gives us a URL which should match the entry. However,
         some callers compensate for an old problem in entry->url and pass
         the copyfrom_url instead. See ^/notes/api-errata/wc002.txt. As
         a result, we allow the passed URL to match copyfrom_url if it
         does not match the entry's primary URL.  */
      /* ### comparing URLs, should they be canonicalized first? */
      if (strcmp(db_repos_uuid, repos_uuid)
          || strcmp(db_repos_root_url, repos_root_url)
          || !svn_relpath__is_ancestor(db_repos_relpath, repos_relpath))
        {
          const char *copyfrom_root_url, *copyfrom_repos_relpath;

          SVN_ERR(svn_wc__internal_get_copyfrom_info(&copyfrom_root_url,
                                                     &copyfrom_repos_relpath,
                                                     NULL, NULL, NULL,
                                                     db, local_abspath,
                                                     scratch_pool,
                                                     scratch_pool));

          if (copyfrom_root_url == NULL
              || strcmp(copyfrom_root_url, repos_root_url)
              || strcmp(copyfrom_repos_relpath, repos_relpath))
            return
              svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
                                _("URL '%s' (uuid: '%s') doesn't match existing "
                                  "URL '%s' (uuid: '%s') in '%s'"),
                                url,
                                db_repos_uuid,
                                svn_path_url_add_component2(db_repos_root_url,
                                                            db_repos_relpath,
                                                            scratch_pool),
                                repos_uuid,
                                local_abspath);
        }
    }

  return SVN_NO_ERROR;
}
コード例 #12
0
svn_error_t *
svn_client__path_relative_to_root(const char **rel_path,
                                  svn_wc_context_t *wc_ctx,
                                  const char *abspath_or_url,
                                  const char *repos_root,
                                  svn_boolean_t include_leading_slash,
                                  svn_ra_session_t *ra_session,
                                  apr_pool_t *result_pool,
                                  apr_pool_t *scratch_pool)
{
  const char *repos_relpath;

  /* If we have a WC path... */
  if (! svn_path_is_url(abspath_or_url))
    {
      /* ...fetch its entry, and attempt to get both its full URL and
         repository root URL.  If we can't get REPOS_ROOT from the WC
         entry, we'll get it from the RA layer.*/

      SVN_ERR(svn_wc__node_get_repos_relpath(&repos_relpath,
                                             wc_ctx,
                                             abspath_or_url,
                                             result_pool,
                                             scratch_pool));

      SVN_ERR_ASSERT(repos_relpath != NULL);
    }
     /* Merge handling passes a root that is not the repos root */
  else if (repos_root != NULL)
    {
      if (!svn_uri__is_ancestor(repos_root, abspath_or_url))
        return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
                                 _("URL '%s' is not a child of repository "
                                   "root URL '%s'"),
                                 abspath_or_url, repos_root);

      repos_relpath = svn_uri_skip_ancestor(repos_root, abspath_or_url,
                                            result_pool);
    }
  else
    {
      svn_error_t *err;

      SVN_ERR_ASSERT(ra_session != NULL);

      /* Ask the RA layer to create a relative path for us */
      err = svn_ra_get_path_relative_to_root(ra_session, &repos_relpath,
                                             abspath_or_url, scratch_pool);

      if (err)
        {
          if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
            return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, err,
                                     _("URL '%s' is not inside repository"),
                                     abspath_or_url);

          return svn_error_trace(err);
        }
    }

  if (include_leading_slash)
    *rel_path = apr_pstrcat(result_pool, "/", repos_relpath, NULL);
  else
    *rel_path = repos_relpath;

   return SVN_NO_ERROR;
}