示例#1
0
/* Go up the directory tree from LOCAL_ABSPATH, looking for a versioned
 * directory.  If found, return its path in *EXISTING_PARENT_ABSPATH.
 * Otherwise, return SVN_ERR_CLIENT_NO_VERSIONED_PARENT. */
static svn_error_t *
find_existing_parent(const char **existing_parent_abspath,
                     svn_client_ctx_t *ctx,
                     const char *local_abspath,
                     apr_pool_t *result_pool,
                     apr_pool_t *scratch_pool)
{
  svn_node_kind_t kind;
  const char *parent_abspath;
  svn_wc_context_t *wc_ctx = ctx->wc_ctx;

  SVN_ERR(svn_wc_read_kind(&kind, wc_ctx, local_abspath, FALSE, scratch_pool));

  if (kind == svn_node_dir)
    {
      svn_boolean_t is_deleted;

      SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted,
                                             wc_ctx, local_abspath,
                                             scratch_pool));
      if (!is_deleted)
        {
          *existing_parent_abspath = apr_pstrdup(result_pool, local_abspath);
          return SVN_NO_ERROR;
        }
    }

  if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
    return svn_error_create(SVN_ERR_CLIENT_NO_VERSIONED_PARENT, NULL, NULL);

  if (svn_wc_is_adm_dir(svn_dirent_basename(local_abspath, scratch_pool),
                        scratch_pool))
    return svn_error_createf(SVN_ERR_RESERVED_FILENAME_SPECIFIED, NULL,
                             _("'%s' ends in a reserved name"),
                             svn_dirent_local_style(local_abspath,
                                                    scratch_pool));

  parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);

  if (ctx->cancel_func)
    SVN_ERR(ctx->cancel_func(ctx->cancel_baton));

  SVN_ERR(find_existing_parent(existing_parent_abspath, ctx, parent_abspath,
                               result_pool, scratch_pool));

  return SVN_NO_ERROR;
}
示例#2
0
static svn_error_t *
fetch_kind_func(svn_kind_t *kind,
                void *baton,
                const char *path,
                svn_revnum_t base_revision,
                apr_pool_t *scratch_pool)
{
  struct shim_callbacks_baton *scb = baton;
  svn_node_kind_t node_kind;
  const char *local_abspath;

  local_abspath = apr_hash_get(scb->relpath_map, path, APR_HASH_KEY_STRING);
  if (!local_abspath)
    {
      *kind = svn_kind_unknown;
      return SVN_NO_ERROR;
    }

  SVN_ERR(svn_wc_read_kind(&node_kind, scb->wc_ctx, local_abspath, FALSE,
                           scratch_pool));
  *kind = svn__kind_from_node_kind(node_kind, FALSE);

  return SVN_NO_ERROR;
}
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;
}
示例#4
0
文件: export.c 项目: DJEX93/dsploit
/* Make an unversioned copy of the versioned file or directory tree at the
 * source path FROM_ABSPATH.  Copy it to the destination path TO_ABSPATH.
 *
 * If REVISION is svn_opt_revision_working, copy the working version,
 * otherwise copy the base version.
 *
 * See copy_one_versioned_file() for details of file copying behaviour,
 * including IGNORE_KEYWORDS and NATIVE_EOL.
 *
 * Include externals unless IGNORE_EXTERNALS is true.
 *
 * Recurse according to DEPTH.
 *

 */
static svn_error_t *
copy_versioned_files(const char *from_abspath,
                     const char *to_abspath,
                     const svn_opt_revision_t *revision,
                     svn_boolean_t force,
                     svn_boolean_t ignore_externals,
                     svn_boolean_t ignore_keywords,
                     svn_depth_t depth,
                     const char *native_eol,
                     svn_client_ctx_t *ctx,
                     apr_pool_t *pool)
{
  svn_error_t *err;
  apr_pool_t *iterpool;
  const apr_array_header_t *children;
  svn_node_kind_t from_kind;
  svn_depth_t node_depth;

  SVN_ERR_ASSERT(svn_dirent_is_absolute(from_abspath));
  SVN_ERR_ASSERT(svn_dirent_is_absolute(to_abspath));

  /* Only export 'added' and 'replaced' files when the revision is WORKING;
     when the revision is BASE (i.e. != WORKING), only export 'added' and
     'replaced' files when they are part of a copy-/move-here. Otherwise, skip
     them, since they don't have an associated text-base. This condition for
     added/replaced simply is an optimization. Added and replaced files would
     be handled similarly by svn_wc_get_pristine_contents2(), which would
     return NULL if they have no base associated.
     TODO: We may prefer not to duplicate this condition and rather use
     svn_wc_get_pristine_contents2() or a dedicated new function instead.

     Don't export 'deleted' files and directories unless it's a
     revision other than WORKING.  These files and directories
     don't really exist in WORKING. */
  if (revision->kind != svn_opt_revision_working)
    {
      svn_boolean_t is_added;
      const char *repos_relpath;

      SVN_ERR(svn_wc__node_get_origin(&is_added, NULL, &repos_relpath,
                                      NULL, NULL, NULL,
                                      ctx->wc_ctx, from_abspath, FALSE,
                                      pool, pool));

      if (is_added && !repos_relpath)
        return SVN_NO_ERROR; /* Local addition */
    }
  else
    {
      svn_boolean_t is_deleted;

      SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, ctx->wc_ctx,
                                             from_abspath, pool));
      if (is_deleted)
        return SVN_NO_ERROR;
    }

  SVN_ERR(svn_wc_read_kind(&from_kind, ctx->wc_ctx, from_abspath, FALSE,
                           pool));

  if (from_kind == svn_node_dir)
    {
      apr_fileperms_t perm = APR_OS_DEFAULT;
      int j;

      /* Try to make the new directory.  If this fails because the
         directory already exists, check our FORCE flag to see if we
         care. */

      /* Keep the source directory's permissions if applicable.
         Skip retrieving the umask on windows. Apr does not implement setting
         filesystem privileges on Windows.
         Retrieving the file permissions with APR_FINFO_PROT | APR_FINFO_OWNER
         is documented to be 'incredibly expensive' */
#ifndef WIN32
      if (revision->kind == svn_opt_revision_working)
        {
          apr_finfo_t finfo;
          SVN_ERR(svn_io_stat(&finfo, from_abspath, APR_FINFO_PROT, pool));
          perm = finfo.protection;
        }
#endif
      err = svn_io_dir_make(to_abspath, perm, pool);
      if (err)
        {
          if (! APR_STATUS_IS_EEXIST(err->apr_err))
            return svn_error_trace(err);
          if (! force)
            SVN_ERR_W(err, _("Destination directory exists, and will not be "
                             "overwritten unless forced"));
          else
            svn_error_clear(err);
        }

      SVN_ERR(svn_wc__node_get_children(&children, ctx->wc_ctx, from_abspath,
                                        FALSE, pool, pool));

      iterpool = svn_pool_create(pool);
      for (j = 0; j < children->nelts; j++)
        {
          const char *child_abspath = APR_ARRAY_IDX(children, j, const char *);
          const char *child_name = svn_dirent_basename(child_abspath, NULL);
          const char *target_abspath;
          svn_node_kind_t child_kind;

          svn_pool_clear(iterpool);

          if (ctx->cancel_func)
            SVN_ERR(ctx->cancel_func(ctx->cancel_baton));

          target_abspath = svn_dirent_join(to_abspath, child_name, iterpool);

          SVN_ERR(svn_wc_read_kind(&child_kind, ctx->wc_ctx, child_abspath,
                                   FALSE, iterpool));

          if (child_kind == svn_node_dir)
            {
              if (depth == svn_depth_infinity
                  || depth == svn_depth_immediates)
                {
                  if (ctx->notify_func2)
                    {
                      svn_wc_notify_t *notify =
                          svn_wc_create_notify(target_abspath,
                                               svn_wc_notify_update_add, pool);
                      notify->kind = svn_node_dir;
                      (*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
                    }

                  if (depth == svn_depth_infinity)
                    SVN_ERR(copy_versioned_files(child_abspath, target_abspath,
                                                 revision, force,
                                                 ignore_externals,
                                                 ignore_keywords, depth,
                                                 native_eol, ctx, iterpool));
                  else
                    SVN_ERR(svn_io_make_dir_recursively(target_abspath,
                                                        iterpool));
                }
            }
          else if (child_kind == svn_node_file
                   && depth >= svn_depth_files)
            {
              svn_node_kind_t external_kind;

              SVN_ERR(svn_wc__read_external_info(&external_kind,
                                                 NULL, NULL, NULL,
                                                 NULL, ctx->wc_ctx,
                                                 child_abspath,
                                                 child_abspath, TRUE,
                                                 pool, pool));

              if (external_kind != svn_node_file)
                SVN_ERR(copy_one_versioned_file(child_abspath, target_abspath,
                                                ctx, revision,
                                                native_eol, ignore_keywords,
                                                iterpool));
            }
        }

      SVN_ERR(svn_wc__node_get_depth(&node_depth, ctx->wc_ctx,
                                     from_abspath, pool));

      /* Handle externals. */
      if (! ignore_externals && depth == svn_depth_infinity
          && node_depth == svn_depth_infinity)
        {
          apr_array_header_t *ext_items;
          const svn_string_t *prop_val;

          SVN_ERR(svn_wc_prop_get2(&prop_val, ctx->wc_ctx, from_abspath,
                                   SVN_PROP_EXTERNALS, pool, pool));
          if (prop_val != NULL)
            {
              int i;

              SVN_ERR(svn_wc_parse_externals_description3(&ext_items,
                                                          from_abspath,
                                                          prop_val->data,
                                                          FALSE, pool));
              for (i = 0; i < ext_items->nelts; ++i)
                {
                  svn_wc_external_item2_t *ext_item;
                  const char *new_from, *new_to;

                  svn_pool_clear(iterpool);

                  ext_item = APR_ARRAY_IDX(ext_items, i,
                                           svn_wc_external_item2_t *);
                  new_from = svn_dirent_join(from_abspath,
                                             ext_item->target_dir,
                                             iterpool);
                  new_to = svn_dirent_join(to_abspath, ext_item->target_dir,
                                           iterpool);

                   /* The target dir might have parents that don't exist.
                      Guarantee the path upto the last component. */
                  if (!svn_dirent_is_root(ext_item->target_dir,
                                          strlen(ext_item->target_dir)))
                    {
                      const char *parent = svn_dirent_dirname(new_to, iterpool);
                      SVN_ERR(svn_io_make_dir_recursively(parent, iterpool));
                    }

                  SVN_ERR(copy_versioned_files(new_from, new_to,
                                               revision, force, FALSE,
                                               ignore_keywords,
                                               svn_depth_infinity, native_eol,
                                               ctx, iterpool));
                }
            }
示例#5
0
/* Note: this implementation is very similar to svn_client_proplist. */
svn_error_t *
svn_client_propget4(apr_hash_t **props,
                    const char *propname,
                    const char *target,
                    const svn_opt_revision_t *peg_revision,
                    const svn_opt_revision_t *revision,
                    svn_revnum_t *actual_revnum,
                    svn_depth_t depth,
                    const apr_array_header_t *changelists,
                    svn_client_ctx_t *ctx,
                    apr_pool_t *result_pool,
                    apr_pool_t *scratch_pool)
{
  svn_revnum_t revnum;

  SVN_ERR(error_if_wcprop_name(propname));
  if (!svn_path_is_url(target))
    SVN_ERR_ASSERT(svn_dirent_is_absolute(target));

  peg_revision = svn_cl__rev_default_to_head_or_working(peg_revision,
                                                        target);
  revision = svn_cl__rev_default_to_peg(revision, peg_revision);

  *props = apr_hash_make(result_pool);

  if (! svn_path_is_url(target)
      && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind)
      && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind))
    {
      svn_node_kind_t kind;
      svn_boolean_t pristine;
      svn_error_t *err;

      /* If FALSE, we want the working revision. */
      pristine = (revision->kind == svn_opt_revision_committed
                  || revision->kind == svn_opt_revision_base);

      SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, target, FALSE,
                               scratch_pool));

      if (kind == svn_node_unknown || kind == svn_node_none)
        {
          /* svn uses SVN_ERR_UNVERSIONED_RESOURCE as warning only
             for this function. */
          return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL,
                                   _("'%s' is not under version control"),
                                   svn_dirent_local_style(target,
                                                          scratch_pool));
        }

      err = svn_client__get_revision_number(&revnum, NULL, ctx->wc_ctx,
                                            target, NULL, revision,
                                            scratch_pool);
      if (err && err->apr_err == SVN_ERR_CLIENT_BAD_REVISION)
        {
          svn_error_clear(err);
          revnum = SVN_INVALID_REVNUM;
        }
      else if (err)
        return svn_error_trace(err);

      SVN_ERR(get_prop_from_wc(*props, propname, target,
                               pristine, kind,
                               depth, changelists, ctx, scratch_pool,
                               result_pool));
    }
  else
    {
      const char *url;
      svn_ra_session_t *ra_session;
      svn_node_kind_t kind;

      /* Get an RA plugin for this filesystem object. */
      SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum,
                                               &url, target, NULL,
                                               peg_revision,
                                               revision, ctx, scratch_pool));

      SVN_ERR(svn_ra_check_path(ra_session, "", revnum, &kind, scratch_pool));

      SVN_ERR(remote_propget(*props, propname, url, "",
                             kind, revnum, ra_session,
                             depth, result_pool, scratch_pool));
    }

  if (actual_revnum)
    *actual_revnum = revnum;
  return SVN_NO_ERROR;
}
示例#6
0
svn_error_t *
svn_client_propset_local(const char *propname,
                         const svn_string_t *propval,
                         const apr_array_header_t *targets,
                         svn_depth_t depth,
                         svn_boolean_t skip_checks,
                         const apr_array_header_t *changelists,
                         svn_client_ctx_t *ctx,
                         apr_pool_t *scratch_pool)
{
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
  svn_boolean_t targets_are_urls;
  int i;

  if (targets->nelts == 0)
    return SVN_NO_ERROR;

  /* Check for homogeneity among our targets. */
  targets_are_urls = svn_path_is_url(APR_ARRAY_IDX(targets, 0, const char *));
  SVN_ERR(svn_client__assert_homogeneous_target_type(targets));

  if (targets_are_urls)
    return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL,
                            _("Targets must be working copy paths"));

  SVN_ERR(check_prop_name(propname, propval));

  for (i = 0; i < targets->nelts; i++)
    {
      svn_node_kind_t kind;
      const char *target_abspath;
      svn_error_t *err;
      struct set_props_baton baton;
      const char *target = APR_ARRAY_IDX(targets, i, const char *);

      svn_pool_clear(iterpool);

      /* Check for cancellation */
      if (ctx->cancel_func)
        SVN_ERR(ctx->cancel_func(ctx->cancel_baton));

      SVN_ERR(svn_dirent_get_absolute(&target_abspath, target, iterpool));

      err = svn_wc_read_kind(&kind, ctx->wc_ctx, target_abspath, FALSE,
                             iterpool);

      if ((err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
          || (!err && (kind == svn_node_unknown || kind == svn_node_none)))
        {
          if (ctx->notify_func2)
            {
              svn_wc_notify_t *notify = svn_wc_create_notify(
                                          target_abspath,
                                          svn_wc_notify_path_nonexistent,
                                          iterpool);

              ctx->notify_func2(ctx->notify_baton2, notify, iterpool);
            }

          svn_error_clear(err);
        }
      else
        SVN_ERR(err);

      baton.ctx = ctx;
      baton.local_abspath = target_abspath;
      baton.depth = depth;
      baton.kind = kind;
      baton.propname = propname;
      baton.propval = propval;
      baton.skip_checks = skip_checks;
      baton.changelist_filter = changelists;

      SVN_ERR(svn_wc__call_with_write_lock(set_props_cb, &baton,
                                           ctx->wc_ctx, target_abspath,
                                           FALSE, iterpool, iterpool));
    }
  svn_pool_destroy(iterpool);

  return SVN_NO_ERROR;
}
示例#7
0
svn_error_t *
svn_client_proplist3(const char *path_or_url,
                     const svn_opt_revision_t *peg_revision,
                     const svn_opt_revision_t *revision,
                     svn_depth_t depth,
                     const apr_array_header_t *changelists,
                     svn_proplist_receiver_t receiver,
                     void *receiver_baton,
                     svn_client_ctx_t *ctx,
                     apr_pool_t *pool)
{
  const char *url;

  peg_revision = svn_cl__rev_default_to_head_or_working(peg_revision,
                                                        path_or_url);
  revision = svn_cl__rev_default_to_peg(revision, peg_revision);

  if (depth == svn_depth_unknown)
    depth = svn_depth_empty;

  if (! svn_path_is_url(path_or_url)
      && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind)
      && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind))
    {
      svn_boolean_t pristine;
      svn_node_kind_t kind;
      apr_hash_t *changelist_hash = NULL;
      const char *local_abspath;

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

      pristine = ((revision->kind == svn_opt_revision_committed)
                  || (revision->kind == svn_opt_revision_base));

      SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, local_abspath, FALSE,
                               pool));

      if (kind == svn_node_unknown || kind == svn_node_none)
        {
          /* svn uses SVN_ERR_UNVERSIONED_RESOURCE as warning only
             for this function. */
          return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL,
                                   _("'%s' is not under version control"),
                                   svn_dirent_local_style(local_abspath,
                                                          pool));
        }

      if (changelists && changelists->nelts)
        SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash,
                                           changelists, pool));

      /* Fetch, recursively or not. */
      if (kind == svn_node_dir)
        {
          struct recursive_proplist_receiver_baton rb;

          rb.wc_ctx = ctx->wc_ctx;
          rb.wrapped_receiver = receiver;
          rb.wrapped_receiver_baton = receiver_baton;

          if (strcmp(path_or_url, local_abspath) != 0)
            {
              rb.anchor = path_or_url;
              rb.anchor_abspath = local_abspath;
            }
          else
            {
              rb.anchor = NULL;
              rb.anchor_abspath = NULL;
            }

          SVN_ERR(svn_wc__prop_list_recursive(ctx->wc_ctx, local_abspath, NULL,
                                              depth,
                                              FALSE, pristine, changelists,
                                              recursive_proplist_receiver, &rb,
                                              ctx->cancel_func,
                                              ctx->cancel_baton, pool));
        }
      else if (svn_wc__changelist_match(ctx->wc_ctx, local_abspath,
                                        changelist_hash, pool))
        {
          apr_hash_t *hash;

          SVN_ERR(pristine_or_working_props(&hash, ctx->wc_ctx, local_abspath,
                                            pristine, pool, pool));
          SVN_ERR(call_receiver(path_or_url, hash,
                                receiver, receiver_baton, pool));

        }
    }
  else /* remote target */
    {
      svn_ra_session_t *ra_session;
      svn_node_kind_t kind;
      apr_pool_t *subpool = svn_pool_create(pool);
      svn_revnum_t revnum;

      /* Get an RA session for this URL. */
      SVN_ERR(svn_client__ra_session_from_path(&ra_session, &revnum,
                                               &url, path_or_url, NULL,
                                               peg_revision,
                                               revision, ctx, pool));

      SVN_ERR(svn_ra_check_path(ra_session, "", revnum, &kind, pool));

      SVN_ERR(remote_proplist(url, "", kind, revnum, ra_session, depth,
                              receiver, receiver_baton, pool, subpool));
      svn_pool_destroy(subpool);
    }

  return SVN_NO_ERROR;
}
示例#8
0
svn_error_t *
svn_client__get_normalized_stream(svn_stream_t **normal_stream,
                                  svn_wc_context_t *wc_ctx,
                                  const char *local_abspath,
                                  const svn_opt_revision_t *revision,
                                  svn_boolean_t expand_keywords,
                                  svn_boolean_t normalize_eols,
                                  svn_cancel_func_t cancel_func,
                                  void *cancel_baton,
                                  apr_pool_t *result_pool,
                                  apr_pool_t *scratch_pool)
{
  apr_hash_t *kw = NULL;
  svn_subst_eol_style_t style;
  apr_hash_t *props;
  svn_string_t *eol_style, *keywords, *special;
  const char *eol = NULL;
  svn_boolean_t local_mod = FALSE;
  apr_time_t tm;
  svn_stream_t *input;
  svn_node_kind_t kind;

  SVN_ERR_ASSERT(SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind));

  SVN_ERR(svn_wc_read_kind(&kind, wc_ctx, local_abspath, FALSE, scratch_pool));

  if (kind == svn_node_unknown || kind == svn_node_none)
    return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL,
                             _("'%s' is not under version control"),
                             svn_dirent_local_style(local_abspath,
                                                    scratch_pool));
  if (kind != svn_node_file)
    return svn_error_createf(SVN_ERR_CLIENT_IS_DIRECTORY, NULL,
                             _("'%s' refers to a directory"),
                             svn_dirent_local_style(local_abspath,
                                                    scratch_pool));

  if (revision->kind != svn_opt_revision_working)
    {
      SVN_ERR(svn_wc_get_pristine_contents2(&input, wc_ctx, local_abspath,
                                            result_pool, scratch_pool));
      if (input == NULL)
        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
                 _("'%s' has no base revision until it is committed"),
                 svn_dirent_local_style(local_abspath, scratch_pool));

      SVN_ERR(svn_wc_get_pristine_props(&props, wc_ctx, local_abspath,
                                        scratch_pool, scratch_pool));
    }
  else
    {
      svn_wc_status3_t *status;

      SVN_ERR(svn_stream_open_readonly(&input, local_abspath, scratch_pool,
                                       result_pool));

      SVN_ERR(svn_wc_prop_list2(&props, wc_ctx, local_abspath, scratch_pool,
                                scratch_pool));
      SVN_ERR(svn_wc_status3(&status, wc_ctx, local_abspath, scratch_pool,
                             scratch_pool));
      if (status->text_status != svn_wc_status_normal)
        local_mod = TRUE;
    }

  eol_style = apr_hash_get(props, SVN_PROP_EOL_STYLE,
                           APR_HASH_KEY_STRING);
  keywords = apr_hash_get(props, SVN_PROP_KEYWORDS,
                          APR_HASH_KEY_STRING);
  special = apr_hash_get(props, SVN_PROP_SPECIAL,
                         APR_HASH_KEY_STRING);

  if (eol_style)
    svn_subst_eol_style_from_value(&style, &eol, eol_style->data);

  if (local_mod && (! special))
    {
      /* Use the modified time from the working copy if
         the file */
      SVN_ERR(svn_io_file_affected_time(&tm, local_abspath, scratch_pool));
    }
  else
    {
      SVN_ERR(svn_wc__node_get_changed_info(NULL, &tm, NULL, wc_ctx,
                                            local_abspath, scratch_pool,
                                            scratch_pool));
    }

  if (keywords)
    {
      svn_revnum_t changed_rev;
      const char *rev_str;
      const char *author;
      const char *url;

      SVN_ERR(svn_wc__node_get_changed_info(&changed_rev, NULL, &author, wc_ctx,
                                            local_abspath, scratch_pool,
                                            scratch_pool));
      SVN_ERR(svn_wc__node_get_url(&url, wc_ctx, local_abspath, scratch_pool,
                                   scratch_pool));

      if (local_mod)
        {
          /* For locally modified files, we'll append an 'M'
             to the revision number, and set the author to
             "(local)" since we can't always determine the
             current user's username */
          rev_str = apr_psprintf(scratch_pool, "%ldM", changed_rev);
          author = _("(local)");
        }
      else
        {
          rev_str = apr_psprintf(scratch_pool, "%ld", changed_rev);
        }

      SVN_ERR(svn_subst_build_keywords2(&kw, keywords->data, rev_str, url, tm,
                                        author, scratch_pool));
    }

  /* Wrap the output stream if translation is needed. */
  if (eol != NULL || kw != NULL)
    input = svn_subst_stream_translated(
      input,
      (eol_style && normalize_eols) ? SVN_SUBST_NATIVE_EOL_STR : eol,
      FALSE, kw, expand_keywords, result_pool);

  *normal_stream = input;

  return SVN_NO_ERROR;
}
示例#9
0
/* This is a helper for svn_client__update_internal(), which see for
   an explanation of most of these parameters.  Some stuff that's
   unique is as follows:

   ANCHOR_ABSPATH is the local absolute path of the update anchor.
   This is typically either the same as LOCAL_ABSPATH, or the
   immediate parent of LOCAL_ABSPATH.

   If NOTIFY_SUMMARY is set (and there's a notification handler in
   CTX), transmit the final update summary upon successful
   completion of the update.
*/
static svn_error_t *
update_internal(svn_revnum_t *result_rev,
                const char *local_abspath,
                const char *anchor_abspath,
                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 adds_as_modification,
                svn_boolean_t *timestamp_sleep,
                svn_boolean_t notify_summary,
                svn_client_ctx_t *ctx,
                apr_pool_t *pool)
{
  const svn_delta_editor_t *update_editor;
  void *update_edit_baton;
  const svn_ra_reporter3_t *reporter;
  void *report_baton;
  const char *anchor_url;
  const char *corrected_url;
  const char *target;
  const char *repos_root;
  svn_error_t *err;
  svn_revnum_t revnum;
  svn_boolean_t use_commit_times;
  svn_boolean_t sleep_here = FALSE;
  svn_boolean_t *use_sleep = timestamp_sleep ? timestamp_sleep : &sleep_here;
  svn_boolean_t clean_checkout = FALSE;
  const char *diff3_cmd;
  svn_ra_session_t *ra_session;
  const char *preserved_exts_str;
  apr_array_header_t *preserved_exts;
  struct svn_client__dirent_fetcher_baton_t dfb;
  svn_boolean_t server_supports_depth;
  svn_boolean_t tree_conflicted;
  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;

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

  /* Get full URL from the ANCHOR. */
  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,
                             _("'%s' has no URL"),
                             svn_dirent_local_style(anchor_abspath, pool));

  /* Check if our anchor exists in BASE. If it doesn't we can't update.
     ### For performance reasons this should be handled with the same query
     ### as retrieving the anchor url. */
  SVN_ERR(svn_wc__node_get_base_rev(&revnum, ctx->wc_ctx, anchor_abspath,
                                    pool));

  /* It does not make sense to update tree-conflict victims. */
  err = svn_wc_conflicted_p3(NULL, NULL, &tree_conflicted,
                             ctx->wc_ctx, local_abspath, pool);
  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
    {
      svn_error_clear(err);
      tree_conflicted = FALSE;
    }
  else
    SVN_ERR(err);

  if (!SVN_IS_VALID_REVNUM(revnum) || tree_conflicted)
    {
      if (ctx->notify_func2)
        {
          svn_wc_notify_t *nt;

          nt = svn_wc_create_notify(local_abspath,
                                    tree_conflicted
                                      ? svn_wc_notify_skip_conflicted
                                      : svn_wc_notify_update_skip_working_only,
                                    pool);

          ctx->notify_func2(ctx->notify_baton2, nt, pool);
        }
      return SVN_NO_ERROR;
    }

  /* 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));
        }
    }

  /* check whether the "clean c/o" optimization is applicable */
  SVN_ERR(is_empty_wc(&clean_checkout, local_abspath, anchor_abspath, pool));

  /* 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));

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

  /* Let everyone know we're starting a real update (unless we're
     asked not to). */
  if (ctx->notify_func2 && notify_summary)
    {
      svn_wc_notify_t *notify
        = svn_wc_create_notify(local_abspath, svn_wc_notify_update_started,
                               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;
      (*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
    }

  /* Open an RA session for the URL */
  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url,
                                               anchor_url,
                                               anchor_abspath, NULL, TRUE,
                                               TRUE, ctx, pool));

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

  /* If we got a corrected URL from the RA subsystem, we'll need to
     relocate our working copy first. */
  if (corrected_url)
    {
      const char *current_repos_root;
      const char *current_uuid;

      /* To relocate everything inside our repository we need the old and new
         repos root. ### And we should only perform relocates on the wcroot */
      SVN_ERR(svn_wc__node_get_repos_info(&current_repos_root, &current_uuid,
                                          ctx->wc_ctx, anchor_abspath,
                                          pool, pool));

      /* ### Check uuid here before calling relocate? */
      SVN_ERR(svn_client_relocate2(anchor_abspath, current_repos_root,
                                   repos_root, ignore_externals, ctx, pool));
      anchor_url = corrected_url;
    }

  /* ### todo: shouldn't svn_client__get_revision_number be able
     to take a URL as easily as a local path?  */
  SVN_ERR(svn_client__get_revision_number(&revnum, NULL, ctx->wc_ctx,
                                          local_abspath, ra_session, revision,
                                          pool));

  SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
                                SVN_RA_CAPABILITY_DEPTH, pool));

  dfb.ra_session = ra_session;
  dfb.target_revision = revnum;
  dfb.anchor_url = anchor_url;

  /* Fetch the update editor.  If REVISION is invalid, that's okay;
     the RA driver will call editor->set_target_revision later on. */
  SVN_ERR(svn_wc_get_update_editor4(&update_editor, &update_edit_baton,
                                    &revnum, ctx->wc_ctx, anchor_abspath,
                                    target, use_commit_times, depth,
                                    depth_is_sticky, allow_unver_obstructions,
                                    adds_as_modification,
                                    server_supports_depth,
                                    clean_checkout,
                                    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_update2(ra_session, &reporter, &report_baton,
                            revnum, target,
                            (!server_supports_depth || depth_is_sticky
                             ? depth
                             : svn_depth_unknown),
                            FALSE, update_editor, update_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. */
  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 update 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,
                                           repos_root, local_abspath,
                                           depth, use_sleep,
                                           ctx, pool));
    }

  if (sleep_here)
    svn_io_sleep_for_timestamps(local_abspath, pool);

  /* Let everyone know we're finished here (unless we're asked not to). */
  if (ctx->notify_func2 && notify_summary)
    {
      svn_wc_notify_t *notify
        = svn_wc_create_notify(local_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;
}
示例#10
0
文件: cleanup.c 项目: DJEX93/dsploit
svn_error_t *
svn_client_upgrade(const char *path,
                   svn_client_ctx_t *ctx,
                   apr_pool_t *scratch_pool)
{
  const char *local_abspath;
  apr_hash_t *externals;
  apr_hash_index_t *hi;
  apr_pool_t *iterpool;
  apr_pool_t *iterpool2;
  svn_opt_revision_t rev = {svn_opt_revision_unspecified, {0}};
  struct repos_info_baton info_baton;

  info_baton.state_pool = scratch_pool;
  info_baton.ctx = ctx;
  info_baton.last_repos = NULL;
  info_baton.last_uuid = NULL;

  if (svn_path_is_url(path))
    return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
                             _("'%s' is not a local path"), path);

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
  SVN_ERR(svn_wc_upgrade(ctx->wc_ctx, local_abspath,
                         fetch_repos_info, &info_baton,
                         ctx->cancel_func, ctx->cancel_baton,
                         ctx->notify_func2, ctx->notify_baton2,
                         scratch_pool));

  /* Now it's time to upgrade the externals too. We do it after the wc
     upgrade to avoid that errors in the externals causes the wc upgrade to
     fail. Thanks to caching the performance penalty of walking the wc a
     second time shouldn't be too severe */
  SVN_ERR(svn_client_propget4(&externals, SVN_PROP_EXTERNALS, local_abspath,
                              &rev, &rev, NULL, svn_depth_infinity, NULL, ctx,
                              scratch_pool, scratch_pool));

  iterpool = svn_pool_create(scratch_pool);
  iterpool2 = svn_pool_create(scratch_pool);

  for (hi = apr_hash_first(scratch_pool, externals); hi;
       hi = apr_hash_next(hi))
    {
      int i;
      const char *externals_parent = svn__apr_hash_index_key(hi);
      svn_string_t *external_desc = svn__apr_hash_index_val(hi);
      apr_array_header_t *externals_p;

      svn_pool_clear(iterpool);
      externals_p = apr_array_make(iterpool, 1,
                                   sizeof(svn_wc_external_item2_t*));

      SVN_ERR(svn_wc_parse_externals_description3(
                  &externals_p, svn_dirent_dirname(path, iterpool),
                  external_desc->data, TRUE, iterpool));
      for (i = 0; i < externals_p->nelts; i++)
        {
          svn_wc_external_item2_t *item;
          const char *external_abspath;
          const char *external_path;
          const char *repos_relpath;
          const char *repos_root_url;
          const char *repos_uuid;
          svn_node_kind_t kind;
          svn_revnum_t peg_revision;
          svn_revnum_t revision;
          svn_error_t *err;

          item = APR_ARRAY_IDX(externals_p, i, svn_wc_external_item2_t*);

          svn_pool_clear(iterpool2);
          external_path = svn_dirent_join(externals_parent, item->target_dir,
                                          iterpool2);

          err = svn_dirent_get_absolute(&external_abspath, external_path,
                                        iterpool2);
          if (err)
            goto handle_error;

          /* This is hack. We can only send dirs to svn_wc_upgrade(). This
             way we will get an exception saying that the wc must be
             upgraded if it's a dir. If it's a file then the lookup is done
             in an adm_dir belonging to the real wc and since that was
             updated before the externals no error is returned. */
          err = svn_wc_read_kind(&kind, ctx->wc_ctx, external_abspath, FALSE,
                                 iterpool2);

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

              err = svn_client_upgrade(external_abspath, ctx, iterpool2);
            }

          if (err)
            goto handle_error;

          /* The upgrade of any dir should be done now, get the (supposedly
           * now reliable) kind. */
          err = svn_wc_read_kind(&kind, ctx->wc_ctx, external_abspath,
                                 FALSE, iterpool2);
          if (err)
            goto handle_error;

          /* Update the EXTERNALS table according to the root URL,
           * relpath and uuid known in the upgraded external WC. */

          /* We should probably have a function that provides all three
           * of root URL, repos relpath and uuid at once, but here goes... */

          /* First get the relpath, as that returns SVN_ERR_WC_PATH_NOT_FOUND
           * when the node is not present in the file system.
           * (svn_wc__node_get_repos_info() would try to derive the URL). */
          err = svn_wc__node_get_repos_relpath(&repos_relpath,
                                               ctx->wc_ctx,
                                               external_abspath,
                                               iterpool2, iterpool2);
          if (! err)
            {
              /* We got a repos relpath from a WC. So also get the root. */
              err = svn_wc__node_get_repos_info(&repos_root_url,
                                                &repos_uuid,
                                                ctx->wc_ctx,
                                                external_abspath,
                                                iterpool2, iterpool2);
            }
          else if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
            {
              /* The external is not currently checked out. Try to figure out
               * the URL parts via the defined URL and fetch_repos_info(). */
              svn_error_clear(err);

              /* The repos root / uuid from above get_repos_info() call, if it
               * was successful, has returned the URL as derived from the WC's
               * parent path, which is not what we want for the external. Only
               * makes sense for added/deleted/not-present files. So make sure
               * those values are not used. */
              repos_root_url = NULL;
              repos_relpath = NULL;

              err = fetch_repos_info(&repos_root_url,
                                     &repos_uuid,
                                     &info_baton,
                                     item->url,
                                     scratch_pool, scratch_pool);
              if (err)
                goto handle_error;


              repos_relpath = svn_uri_skip_ancestor(repos_root_url, item->url,
                                                    iterpool2);

              /* There's just this URL, no idea what kind it is. */
              kind = svn_node_unknown;
            }

          if (err)
            goto handle_error;

          peg_revision = (item->peg_revision.kind == svn_opt_revision_number
                          ? item->peg_revision.value.number
                          : SVN_INVALID_REVNUM);

          revision = (item->revision.kind == svn_opt_revision_number
                      ? item->revision.value.number
                      : SVN_INVALID_REVNUM);

          err = svn_wc__upgrade_add_external_info(ctx->wc_ctx,
                                                  external_abspath,
                                                  kind,
                                                  externals_parent,
                                                  repos_relpath,
                                                  repos_root_url,
                                                  repos_uuid,
                                                  peg_revision,
                                                  revision,
                                                  iterpool2);
handle_error:
          if (err)
            {
              svn_wc_notify_t *notify =
                  svn_wc_create_notify(external_abspath,
                                       svn_wc_notify_failed_external,
                                       scratch_pool);
              notify->err = err;

              ctx->notify_func2(ctx->notify_baton2,
                                notify, scratch_pool);

              svn_error_clear(err);
            }
        }
    }

  svn_pool_destroy(iterpool);
  svn_pool_destroy(iterpool2);

  return SVN_NO_ERROR;
}
示例#11
0
文件: cmdline.c 项目: DJEX93/dsploit
/* Note: This is substantially copied from svn_opt__args_to_target_array() in
 * order to move to libsvn_client while maintaining backward compatibility. */
svn_error_t *
svn_client_args_to_target_array2(apr_array_header_t **targets_p,
                                 apr_getopt_t *os,
                                 const apr_array_header_t *known_targets,
                                 svn_client_ctx_t *ctx,
                                 svn_boolean_t keep_last_origpath_on_truepath_collision,
                                 apr_pool_t *pool)
{
  int i;
  svn_boolean_t rel_url_found = FALSE;
  const char *root_url = NULL;
  svn_error_t *err = SVN_NO_ERROR;
  apr_array_header_t *input_targets =
    apr_array_make(pool, DEFAULT_ARRAY_SIZE, sizeof(const char *));
  apr_array_header_t *output_targets =
    apr_array_make(pool, DEFAULT_ARRAY_SIZE, sizeof(const char *));
  apr_array_header_t *reserved_names = NULL;

  /* Step 1:  create a master array of targets that are in UTF-8
     encoding, and come from concatenating the targets left by apr_getopt,
     plus any extra targets (e.g., from the --targets switch.)
     If any of the targets are relative urls, then set the rel_url_found
     flag.*/

  for (; os->ind < os->argc; os->ind++)
    {
      /* The apr_getopt targets are still in native encoding. */
      const char *raw_target = os->argv[os->ind];
      const char *utf8_target;

      SVN_ERR(svn_utf_cstring_to_utf8(&utf8_target,
                                      raw_target, pool));

      if (arg_is_repos_relative_url(utf8_target))
        rel_url_found = TRUE;

      APR_ARRAY_PUSH(input_targets, const char *) = utf8_target;
    }

  if (known_targets)
    {
      for (i = 0; i < known_targets->nelts; i++)
        {
          /* The --targets array have already been converted to UTF-8,
             because we needed to split up the list with svn_cstring_split. */
          const char *utf8_target = APR_ARRAY_IDX(known_targets,
                                                  i, const char *);

          if (arg_is_repos_relative_url(utf8_target))
            rel_url_found = TRUE;

          APR_ARRAY_PUSH(input_targets, const char *) = utf8_target;
        }
    }

  /* Step 2:  process each target.  */

  for (i = 0; i < input_targets->nelts; i++)
    {
      const char *utf8_target = APR_ARRAY_IDX(input_targets, i, const char *);

      /* Relative urls will be canonicalized when they are resolved later in
       * the function
       */
      if (arg_is_repos_relative_url(utf8_target))
        {
          APR_ARRAY_PUSH(output_targets, const char *) = utf8_target;
        }
      else
        {
          const char *true_target;
          const char *peg_rev;
          const char *target;

          /*
           * This is needed so that the target can be properly canonicalized,
           * otherwise the canonicalization does not treat a ".@BASE" as a "."
           * with a BASE peg revision, and it is not canonicalized to "@BASE".
           * If any peg revision exists, it is appended to the final
           * canonicalized path or URL.  Do not use svn_opt_parse_path()
           * because the resulting peg revision is a structure that would have
           * to be converted back into a string.  Converting from a string date
           * to the apr_time_t field in the svn_opt_revision_value_t and back to
           * a string would not necessarily preserve the exact bytes of the
           * input date, so its easier just to keep it in string form.
           */
          SVN_ERR(svn_opt__split_arg_at_peg_revision(&true_target, &peg_rev,
                                                     utf8_target, pool));

          /* URLs and wc-paths get treated differently. */
          if (svn_path_is_url(true_target))
            {
              SVN_ERR(svn_opt__arg_canonicalize_url(&true_target,
                                                    true_target, pool));
            }
          else  /* not a url, so treat as a path */
            {
              const char *base_name;
              const char *original_target;

              original_target = svn_dirent_internal_style(true_target, pool);
              SVN_ERR(svn_opt__arg_canonicalize_path(&true_target,
                                                     true_target, pool));

              /* There are two situations in which a 'truepath-conversion'
                 (case-canonicalization to on-disk path on case-insensitive
                 filesystem) needs to be undone:

                 1. If KEEP_LAST_ORIGPATH_ON_TRUEPATH_COLLISION is TRUE, and
                    this is the last target of a 2-element target list, and
                    both targets have the same truepath. */
              if (keep_last_origpath_on_truepath_collision
                  && input_targets->nelts == 2 && i == 1
                  && strcmp(original_target, true_target) != 0)
                {
                  const char *src_truepath = APR_ARRAY_IDX(output_targets,
                                                           0,
                                                           const char *);
                  if (strcmp(src_truepath, true_target) == 0)
                    true_target = original_target;
                }

              /* 2. If there is an exact match in the wc-db without a
                    corresponding on-disk path (e.g. a scheduled-for-delete
                    file only differing in case from an on-disk file). */
              if (strcmp(original_target, true_target) != 0)
                {
                  const char *target_abspath;
                  svn_node_kind_t kind;
                  svn_error_t *err2;

                  SVN_ERR(svn_dirent_get_absolute(&target_abspath,
                                                  original_target, pool));
                  err2 = svn_wc_read_kind(&kind, ctx->wc_ctx, target_abspath,
                                          FALSE, pool);
                  if (err2
                      && (err2->apr_err == SVN_ERR_WC_NOT_WORKING_COPY
                          || err2->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED))
                    {
                      svn_error_clear(err2);
                    }
                  else
                    {
                      SVN_ERR(err2);
                      /* We successfully did a lookup in the wc-db. Now see
                         if it's something interesting. */
                      if (kind == svn_node_file || kind == svn_node_dir)
                        true_target = original_target;
                    }
                }

              /* If the target has the same name as a Subversion
                 working copy administrative dir, skip it. */
              base_name = svn_dirent_basename(true_target, pool);

              if (svn_wc_is_adm_dir(base_name, pool))
                {
                  if (!reserved_names)
                    reserved_names = apr_array_make(pool, DEFAULT_ARRAY_SIZE,
                                                    sizeof(const char *));

                  APR_ARRAY_PUSH(reserved_names, const char *) = utf8_target;

                  continue;
                }
            }

          target = apr_pstrcat(pool, true_target, peg_rev, (char *)NULL);

          if (rel_url_found)
            {
              /* Later targets have priority over earlier target, I
                 don't know why, see basic_relative_url_multi_repo. */
              SVN_ERR(check_root_url_of_target(&root_url, target,
                                               ctx, pool));
            }

          APR_ARRAY_PUSH(output_targets, const char *) = target;
        }
    }

  /* Only resolve relative urls if there were some actually found earlier. */
  if (rel_url_found)
    {
      /*
       * Use the current directory's root url if one wasn't found using the
       * arguments.
       */
      if (root_url == NULL)
        {
          err = svn_client_root_url_from_path(&root_url, "", ctx, pool);
          if (err || root_url == NULL)
            return svn_error_create(SVN_ERR_WC_NOT_WORKING_COPY, err,
                                    _("Resolving '^/': no repository root "
                                      "found in the target arguments or "
                                      "in the current directory"));
        }

      *targets_p = apr_array_make(pool, output_targets->nelts,
                                  sizeof(const char *));

      for (i = 0; i < output_targets->nelts; i++)
        {
          const char *target = APR_ARRAY_IDX(output_targets, i,
                                             const char *);

          if (arg_is_repos_relative_url(target))
            {
              const char *abs_target;
              const char *true_target;
              const char *peg_rev;

              SVN_ERR(svn_opt__split_arg_at_peg_revision(&true_target, &peg_rev,
                                                         target, pool));

              SVN_ERR(resolve_repos_relative_url(&abs_target, true_target,
                                                 root_url, pool));

              SVN_ERR(svn_opt__arg_canonicalize_url(&true_target, abs_target,
                                                    pool));

              target = apr_pstrcat(pool, true_target, peg_rev, (char *)NULL);
            }

          APR_ARRAY_PUSH(*targets_p, const char *) = target;
        }
    }
  else
svn_error_t *
svn_client_upgrade(const char *path,
                   svn_client_ctx_t *ctx,
                   apr_pool_t *scratch_pool)
{
  const char *local_abspath;
  apr_hash_t *externals;
  apr_hash_index_t *hi;
  apr_pool_t *iterpool;
  apr_pool_t *iterpool2;
  svn_opt_revision_t rev = {svn_opt_revision_unspecified, {0}};
  struct repos_info_baton info_baton;

  info_baton.state_pool = scratch_pool;
  info_baton.ctx = ctx;
  info_baton.last_repos = NULL;
  info_baton.last_uuid = NULL;

  if (svn_path_is_url(path))
    return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
                             _("'%s' is not a local path"), path);

  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
  SVN_ERR(svn_wc_upgrade(ctx->wc_ctx, local_abspath,
                         fetch_repos_info, &info_baton,
                         ctx->cancel_func, ctx->cancel_baton,
                         ctx->notify_func2, ctx->notify_baton2,
                         scratch_pool));

  /* Now it's time to upgrade the externals too. We do it after the wc
     upgrade to avoid that errors in the externals causes the wc upgrade to
     fail. Thanks to caching the performance penalty of walking the wc a
     second time shouldn't be too severe */
  SVN_ERR(svn_client_propget4(&externals, SVN_PROP_EXTERNALS, local_abspath,
                              &rev, &rev, NULL, svn_depth_infinity, NULL, ctx,
                              scratch_pool, scratch_pool));

  iterpool = svn_pool_create(scratch_pool);
  iterpool2 = svn_pool_create(scratch_pool);

  for (hi = apr_hash_first(scratch_pool, externals); hi;
       hi = apr_hash_next(hi))
    {
      int i;
      const char *externals_parent_abspath;
      const char *externals_parent_url;
      const char *externals_parent_repos_root_url;
      const char *externals_parent = svn__apr_hash_index_key(hi);
      svn_string_t *external_desc = svn__apr_hash_index_val(hi);
      apr_array_header_t *externals_p;
      svn_error_t *err;

      svn_pool_clear(iterpool);
      externals_p = apr_array_make(iterpool, 1,
                                   sizeof(svn_wc_external_item2_t*));

      /* In this loop, an error causes the respective externals definition, or
       * the external (inner loop), to be skipped, so that upgrade carries on
       * with the other externals. */

      err = svn_dirent_get_absolute(&externals_parent_abspath,
                                    externals_parent, iterpool);

      if (!err)
        err = svn_wc__node_get_url(&externals_parent_url, ctx->wc_ctx,
                                   externals_parent_abspath,
                                   iterpool, iterpool);
      if (!err)
        err = svn_wc__node_get_repos_info(&externals_parent_repos_root_url,
                                          NULL,
                                          ctx->wc_ctx,
                                          externals_parent_abspath,
                                          iterpool, iterpool);
      if (!err)
        err = svn_wc_parse_externals_description3(
                  &externals_p, svn_dirent_dirname(path, iterpool),
                  external_desc->data, TRUE, iterpool);
      if (err)
        {
          svn_wc_notify_t *notify =
              svn_wc_create_notify(externals_parent,
                                   svn_wc_notify_failed_external,
                                   scratch_pool);
          notify->err = err;

          ctx->notify_func2(ctx->notify_baton2,
                            notify, scratch_pool);

          svn_error_clear(err);

          /* Next externals definition, please... */
          continue;
        }

      for (i = 0; i < externals_p->nelts; i++)
        {
          svn_wc_external_item2_t *item;
          const char *resolved_url;
          const char *external_abspath;
          const char *repos_relpath;
          const char *repos_root_url;
          const char *repos_uuid;
          svn_node_kind_t external_kind;
          svn_revnum_t peg_revision;
          svn_revnum_t revision;

          item = APR_ARRAY_IDX(externals_p, i, svn_wc_external_item2_t*);

          svn_pool_clear(iterpool2);
          external_abspath = svn_dirent_join(externals_parent_abspath,
                                             item->target_dir,
                                             iterpool2);

          err = svn_wc__resolve_relative_external_url(
                                              &resolved_url,
                                              item,
                                              externals_parent_repos_root_url,
                                              externals_parent_url,
                                              scratch_pool, scratch_pool);
          if (err)
            goto handle_error;

          /* This is a hack. We only need to call svn_wc_upgrade() on external
           * dirs, as file externals are upgraded along with their defining
           * WC.  Reading the kind will throw an exception on an external dir,
           * saying that the wc must be upgraded.  If it's a file, the lookup
           * is done in an adm_dir belonging to the defining wc (which has
           * already been upgraded) and no error is returned.  If it doesn't
           * exist (external that isn't checked out yet), we'll just get
           * svn_node_none. */
          err = svn_wc_read_kind(&external_kind, ctx->wc_ctx,
                                 external_abspath, FALSE, iterpool2);
          if (err && err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
            {
              svn_error_clear(err);

              err = svn_client_upgrade(external_abspath, ctx, iterpool2);
              if (err)
                goto handle_error;
            }
          else if (err)
            goto handle_error;

          /* The upgrade of any dir should be done now, get the now reliable
           * kind. */
          err = svn_wc_read_kind(&external_kind, ctx->wc_ctx, external_abspath,
                                 FALSE, iterpool2);
          if (err)
            goto handle_error;

          /* Update the EXTERNALS table according to the root URL,
           * relpath and uuid known in the upgraded external WC. */

          /* We should probably have a function that provides all three
           * of root URL, repos relpath and uuid at once, but here goes... */

          /* First get the relpath, as that returns SVN_ERR_WC_PATH_NOT_FOUND
           * when the node is not present in the file system.
           * svn_wc__node_get_repos_info() would try to derive the URL. */
          err = svn_wc__node_get_repos_relpath(&repos_relpath,
                                               ctx->wc_ctx,
                                               external_abspath,
                                               iterpool2, iterpool2);
          if (! err)
            {
              /* We got a repos relpath from a WC. So also get the root. */
              err = svn_wc__node_get_repos_info(&repos_root_url,
                                                &repos_uuid,
                                                ctx->wc_ctx,
                                                external_abspath,
                                                iterpool2, iterpool2);
              if (err)
                goto handle_error;
            }
          else if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
            {
              /* The external is not currently checked out. Try to figure out
               * the URL parts via the defined URL and fetch_repos_info(). */
              svn_error_clear(err);
              repos_relpath = NULL;
              repos_root_url = NULL;
              repos_uuid = NULL;
            }
          else if (err)
            goto handle_error;

          /* If we haven't got any information from the checked out external,
           * or if the URL information mismatches the external's definition,
           * ask fetch_repos_info() to find out the repos root. */
          if (! repos_relpath || ! repos_root_url
              || 0 != strcmp(resolved_url,
                             svn_path_url_add_component2(repos_root_url,
                                                         repos_relpath,
                                                         scratch_pool)))
            {
              err = fetch_repos_info(&repos_root_url,
                                     &repos_uuid,
                                     &info_baton,
                                     resolved_url,
                                     scratch_pool, scratch_pool);
              if (err)
                goto handle_error;

              repos_relpath = svn_uri_skip_ancestor(repos_root_url,
                                                    resolved_url,
                                                    iterpool2);

              /* There's just the URL, no idea what kind the external is.
               * That's fine, as the external isn't even checked out yet.
               * The kind will be set during the next 'update'. */
              external_kind = svn_node_unknown;
            }

          if (err)
            goto handle_error;

          peg_revision = (item->peg_revision.kind == svn_opt_revision_number
                          ? item->peg_revision.value.number
                          : SVN_INVALID_REVNUM);

          revision = (item->revision.kind == svn_opt_revision_number
                      ? item->revision.value.number
                      : SVN_INVALID_REVNUM);

          err = svn_wc__upgrade_add_external_info(ctx->wc_ctx,
                                                  external_abspath,
                                                  external_kind,
                                                  externals_parent,
                                                  repos_relpath,
                                                  repos_root_url,
                                                  repos_uuid,
                                                  peg_revision,
                                                  revision,
                                                  iterpool2);
handle_error:
          if (err)
            {
              svn_wc_notify_t *notify =
                  svn_wc_create_notify(external_abspath,
                                       svn_wc_notify_failed_external,
                                       scratch_pool);
              notify->err = err;
              ctx->notify_func2(ctx->notify_baton2,
                                notify, scratch_pool);
              svn_error_clear(err);
              /* Next external node, please... */
            }
        }
    }

  svn_pool_destroy(iterpool);
  svn_pool_destroy(iterpool2);

  return SVN_NO_ERROR;
}