Beispiel #1
0
static svn_error_t *
fetch_base_func(const char **filename,
                void *baton,
                const char *path,
                svn_revnum_t base_revision,
                apr_pool_t *result_pool,
                apr_pool_t *scratch_pool)
{
  struct edit_baton *eb = baton;
  svn_stream_t *fstream;
  svn_error_t *err;

  SVN_ERR(svn_stream_open_unique(&fstream, filename, NULL,
                                 svn_io_file_del_on_pool_cleanup,
                                 result_pool, scratch_pool));

  err = svn_ra_get_file(eb->ra_session, path, eb->revision,
                        fstream, NULL, NULL, scratch_pool);
  if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
    {
      svn_error_clear(err);
      SVN_ERR(svn_stream_close(fstream));

      *filename = NULL;
      return SVN_NO_ERROR;
    }
  else if (err)
    return svn_error_trace(err);
  
  SVN_ERR(svn_stream_close(fstream));

  return SVN_NO_ERROR;
}
Beispiel #2
0
svn_error_t*
CommitEditor::provide_props_cb(apr_hash_t **props,
                               svn_revnum_t *revision,
                               void *baton,
                               const char *repos_relpath,
                               apr_pool_t *result_pool,
                               apr_pool_t *scratch_pool)
{
  CommitEditor* editor = static_cast<CommitEditor*>(baton);
  if (editor->m_get_props_cb.get())
    {
      const Java::Env env;
      SVN_JAVAHL_CATCH(env, SVN_ERR_BASE,
                       invoke_get_props_cb(props, revision, env,
                                           editor->m_get_props_cb.get(),
                                           repos_relpath,
                                           result_pool));
    }
  else
    {
      SVN_ERR(open_callback_session(editor->m_callback_session,
                                    editor->m_callback_session_url,
                                    editor->m_callback_session_uuid,
                                    editor->m_session->m_context,
                                    editor->pool));

      svn_node_kind_t kind = svn_node_unknown;
      SVN_ERR(svn_ra_check_path(editor->m_callback_session,
                                repos_relpath, SVN_INVALID_REVNUM, &kind,
                                scratch_pool));

      // FIXME: Getting properties from the youngest revision is in
      // fact not such a bright idea, as the path may have been moved
      // or deleted in the repository. On the other hand, if that
      // happens, the commit would fail due to a conflict anyway.
      if (kind == svn_node_file)
        return svn_ra_get_file(editor->m_callback_session,
                               repos_relpath, SVN_INVALID_REVNUM,
                               NULL, revision, props, scratch_pool);
      else if (kind == svn_node_dir)
        return svn_ra_get_dir2(editor->m_callback_session, NULL, revision,
                               props, repos_relpath, SVN_INVALID_REVNUM, 0,
                               scratch_pool);
      else
        return svn_error_createf(
            SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
            _("Expected node kind '%s' or '%s' but got '%s'"),
            svn_node_kind_to_word(svn_node_file),
            svn_node_kind_to_word(svn_node_dir),
            svn_node_kind_to_word(kind));
    }
  return SVN_NO_ERROR;
}
Beispiel #3
0
/* Get revision B->base_revision of the file described by B from the
 * repository, through B->edit_baton->ra_session.
 *
 * Unless PROPS_ONLY is true:
 *   Set B->path_start_revision to the path of a new temporary file containing
 *   the file's text.
 *   Set B->start_md5_checksum to that file's MD-5 checksum.
 *   Install a pool cleanup handler on B->pool to delete the file.
 *
 * Always:
 *   Set B->pristine_props to a new hash containing the file's properties.
 *
 * Allocate all results in B->pool.
 */
static svn_error_t *
get_file_from_ra(struct file_baton *b,
                 svn_boolean_t props_only,
                 apr_pool_t *scratch_pool)
{
  if (! props_only)
    {
      svn_stream_t *fstream;

      SVN_ERR(svn_stream_open_unique(&fstream, &(b->path_start_revision), NULL,
                                     svn_io_file_del_on_pool_cleanup,
                                     b->pool, scratch_pool));

      fstream = svn_stream_checksummed2(fstream, NULL, &b->start_md5_checksum,
                                        svn_checksum_md5, TRUE, scratch_pool);

      /* Retrieve the file and its properties */
      SVN_ERR(svn_ra_get_file(b->edit_baton->ra_session,
                              b->path,
                              b->base_revision,
                              fstream, NULL,
                              &(b->pristine_props),
                              b->pool));
      SVN_ERR(svn_stream_close(fstream));
    }
  else
    {
      SVN_ERR(svn_ra_get_file(b->edit_baton->ra_session,
                              b->path,
                              b->base_revision,
                              NULL, NULL,
                              &(b->pristine_props),
                              b->pool));
    }

  return SVN_NO_ERROR;
}
Beispiel #4
0
static svn_error_t *
get_file_for_validation(const svn_string_t **mime_type,
                        svn_stream_t *stream,
                        void *baton,
                        apr_pool_t *pool)
{
  struct getter_baton *gb = baton;
  svn_ra_session_t *ra_session = gb->ra_session;
  apr_hash_t *props;

  SVN_ERR(svn_ra_get_file(ra_session, "", gb->base_revision_for_url,
                          stream, NULL,
                          (mime_type ? &props : NULL),
                          pool));

  if (mime_type)
    *mime_type = apr_hash_get(props, SVN_PROP_MIME_TYPE, APR_HASH_KEY_STRING);

  return SVN_NO_ERROR;
}
Beispiel #5
0
static svn_error_t *
fetch_props_func(apr_hash_t **props,
                 void *baton,
                 const char *path,
                 svn_revnum_t base_revision,
                 apr_pool_t *result_pool,
                 apr_pool_t *scratch_pool)
{
  struct revision_baton *rb = baton;
  svn_node_kind_t node_kind;

  if (! SVN_IS_VALID_REVNUM(base_revision))
    base_revision = rb->rev - 1;

  SVN_ERR(svn_ra_check_path(rb->pb->aux_session, path, base_revision,
                            &node_kind, scratch_pool));

  if (node_kind == svn_node_file)
    {
      SVN_ERR(svn_ra_get_file(rb->pb->aux_session, path, base_revision,
                              NULL, NULL, props, result_pool));
    }
  else if (node_kind == svn_node_dir)
    {
      apr_array_header_t *tmp_props;

      SVN_ERR(svn_ra_get_dir2(rb->pb->aux_session, NULL, NULL, props, path,
                              base_revision, 0 /* Dirent fields */,
                              result_pool));
      tmp_props = svn_prop_hash_to_array(*props, result_pool);
      SVN_ERR(svn_categorize_props(tmp_props, NULL, NULL, &tmp_props,
                                   result_pool));
      *props = svn_prop_array_to_hash(tmp_props, result_pool);
    }
  else
    {
      *props = apr_hash_make(result_pool);
    }

  return SVN_NO_ERROR;
}
Beispiel #6
0
static svn_error_t *
bench_null_export(svn_revnum_t *result_rev,
                  const char *from_path_or_url,
                  svn_opt_revision_t *peg_revision,
                  svn_opt_revision_t *revision,
                  svn_depth_t depth,
                  void *baton,
                  svn_client_ctx_t *ctx,
                  svn_boolean_t quiet,
                  apr_pool_t *pool)
{
    svn_revnum_t edit_revision = SVN_INVALID_REVNUM;
    svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url);

    SVN_ERR_ASSERT(peg_revision != NULL);
    SVN_ERR_ASSERT(revision != NULL);

    if (peg_revision->kind == svn_opt_revision_unspecified)
        peg_revision->kind = svn_path_is_url(from_path_or_url)
                             ? svn_opt_revision_head
                             : svn_opt_revision_working;

    if (revision->kind == svn_opt_revision_unspecified)
        revision = peg_revision;

    if (from_is_url || ! SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind))
    {
        svn_client__pathrev_t *loc;
        svn_ra_session_t *ra_session;
        svn_node_kind_t kind;

        /* Get the RA connection. */
        SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
                from_path_or_url, NULL,
                peg_revision,
                revision, ctx, pool));

        SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, pool));

        if (kind == svn_node_file)
        {
            apr_hash_t *props;

            /* Since you cannot actually root an editor at a file, we
             * manually drive a few functions of our editor. */

            /* Step outside the editor-likeness for a moment, to actually talk
             * to the repository. */
            /* ### note: the stream will not be closed */
            SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev,
                                    svn_stream_empty(pool),
                                    NULL, &props, pool));
        }
        else if (kind == svn_node_dir)
        {
            void *edit_baton = NULL;
            const svn_delta_editor_t *export_editor = NULL;
            const svn_ra_reporter3_t *reporter;
            void *report_baton;

            svn_delta_editor_t *editor = svn_delta_default_editor(pool);

            editor->set_target_revision = set_target_revision;
            editor->open_root = open_root;
            editor->add_directory = add_directory;
            editor->add_file = add_file;
            editor->apply_textdelta = apply_textdelta;
            editor->close_file = close_file;
            editor->change_file_prop = change_file_prop;
            editor->change_dir_prop = change_dir_prop;

            /* for ra_svn, we don't need an editior in quiet mode */
            if (!quiet || strncmp(loc->repos_root_url, "svn:", 4))
                SVN_ERR(svn_delta_get_cancellation_editor(ctx->cancel_func,
                        ctx->cancel_baton,
                        editor,
                        baton,
                        &export_editor,
                        &edit_baton,
                        pool));

            /* Manufacture a basic 'report' to the update reporter. */
            SVN_ERR(svn_ra_do_update3(ra_session,
                                      &reporter, &report_baton,
                                      loc->rev,
                                      "", /* no sub-target */
                                      depth,
                                      FALSE, /* don't want copyfrom-args */
                                      FALSE, /* don't want ignore_ancestry */
                                      export_editor, edit_baton,
                                      pool, pool));

            SVN_ERR(reporter->set_path(report_baton, "", loc->rev,
                                       /* Depth is irrelevant, as we're
                                          passing start_empty=TRUE anyway. */
                                       svn_depth_infinity,
                                       TRUE, /* "help, my dir is empty!" */
                                       NULL, pool));

            SVN_ERR(reporter->finish_report(report_baton, pool));
        }
        else if (kind == svn_node_none)
        {
            return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
                                     _("URL '%s' doesn't exist"),
                                     from_path_or_url);
        }
        /* kind == svn_node_unknown not handled */
    }


    if (result_rev)
        *result_rev = edit_revision;

    return SVN_NO_ERROR;
}
Beispiel #7
0
/* Helper for the remote case of svn_client_proplist.
 *
 * Push a new 'svn_client_proplist_item_t *' item onto PROPLIST,
 * containing the properties for "TARGET_PREFIX/TARGET_RELATIVE" in
 * REVNUM, obtained using RA_LIB and SESSION.  The item->node_name
 * will be "TARGET_PREFIX/TARGET_RELATIVE", and the value will be a
 * hash mapping 'const char *' property names onto 'svn_string_t *'
 * property values.
 *
 * Allocate the new item and its contents in POOL.
 * Do all looping, recursion, and temporary work in SCRATCHPOOL.
 *
 * KIND is the kind of the node at "TARGET_PREFIX/TARGET_RELATIVE".
 *
 * If the target is a directory, only fetch properties for the files
 * and directories at depth DEPTH.
 */
static svn_error_t *
remote_proplist(const char *target_prefix,
                const char *target_relative,
                svn_node_kind_t kind,
                svn_revnum_t revnum,
                svn_ra_session_t *ra_session,
                svn_depth_t depth,
                svn_proplist_receiver_t receiver,
                void *receiver_baton,
                apr_pool_t *pool,
                apr_pool_t *scratchpool)
{
  apr_hash_t *dirents;
  apr_hash_t *prop_hash, *final_hash;
  apr_hash_index_t *hi;
  const char *target_full_url =
    svn_path_url_add_component2(target_prefix, target_relative, scratchpool);

  if (kind == svn_node_dir)
    {
      SVN_ERR(svn_ra_get_dir2(ra_session,
                              (depth > svn_depth_empty) ? &dirents : NULL,
                              NULL, &prop_hash, target_relative, revnum,
                              SVN_DIRENT_KIND, scratchpool));
    }
  else if (kind == svn_node_file)
    {
      SVN_ERR(svn_ra_get_file(ra_session, target_relative, revnum,
                              NULL, NULL, &prop_hash, scratchpool));
    }
  else
    {
      return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
                               _("Unknown node kind for '%s'"),
                               target_full_url);
    }

  /* Filter out non-regular properties, since the RA layer returns all
     kinds.  Copy regular properties keys/vals from the prop_hash
     allocated in SCRATCHPOOL to the "final" hash allocated in POOL. */
  final_hash = apr_hash_make(pool);
  for (hi = apr_hash_first(scratchpool, prop_hash);
       hi;
       hi = apr_hash_next(hi))
    {
      const char *name = svn__apr_hash_index_key(hi);
      apr_ssize_t klen = svn__apr_hash_index_klen(hi);
      svn_string_t *value = svn__apr_hash_index_val(hi);
      svn_prop_kind_t prop_kind;

      prop_kind = svn_property_kind(NULL, name);

      if (prop_kind == svn_prop_regular_kind)
        {
          name = apr_pstrdup(pool, name);
          value = svn_string_dup(value, pool);
          apr_hash_set(final_hash, name, klen, value);
        }
    }

  SVN_ERR(call_receiver(target_full_url, final_hash, receiver, receiver_baton,
                        pool));

  if (depth > svn_depth_empty
      && (kind == svn_node_dir) && (apr_hash_count(dirents) > 0))
    {
      apr_pool_t *subpool = svn_pool_create(scratchpool);

      for (hi = apr_hash_first(scratchpool, dirents);
           hi;
           hi = apr_hash_next(hi))
        {
          const char *this_name = svn__apr_hash_index_key(hi);
          svn_dirent_t *this_ent = svn__apr_hash_index_val(hi);
          const char *new_target_relative;

          svn_pool_clear(subpool);

          new_target_relative = svn_relpath_join(target_relative,
                                                 this_name, subpool);

          if (this_ent->kind == svn_node_file
              || depth > svn_depth_files)
            {
              svn_depth_t depth_below_here = depth;

              if (depth == svn_depth_immediates)
                depth_below_here = svn_depth_empty;

              SVN_ERR(remote_proplist(target_prefix,
                                      new_target_relative,
                                      this_ent->kind,
                                      revnum,
                                      ra_session,
                                      depth_below_here,
                                      receiver,
                                      receiver_baton,
                                      pool,
                                      subpool));
            }
        }

      svn_pool_destroy(subpool);
    }

  return SVN_NO_ERROR;
}
Beispiel #8
0
/* Helper for the remote case of svn_client_propget.
 *
 * Get the value of property PROPNAME in REVNUM, using RA_LIB and
 * SESSION.  Store the value ('svn_string_t *') in PROPS, under the
 * path key "TARGET_PREFIX/TARGET_RELATIVE" ('const char *').
 *
 * Recurse according to DEPTH, similarly to svn_client_propget3().
 *
 * KIND is the kind of the node at "TARGET_PREFIX/TARGET_RELATIVE".
 * Yes, caller passes this; it makes the recursion more efficient :-).
 *
 * Allocate the keys and values in PERM_POOL, but do all temporary
 * work in WORK_POOL.  The two pools can be the same; recursive
 * calls may use a different WORK_POOL, however.
 */
static svn_error_t *
remote_propget(apr_hash_t *props,
               const char *propname,
               const char *target_prefix,
               const char *target_relative,
               svn_node_kind_t kind,
               svn_revnum_t revnum,
               svn_ra_session_t *ra_session,
               svn_depth_t depth,
               apr_pool_t *perm_pool,
               apr_pool_t *work_pool)
{
  apr_hash_t *dirents;
  apr_hash_t *prop_hash;
  const svn_string_t *val;
  const char *target_full_url =
    svn_path_url_add_component2(target_prefix, target_relative, work_pool);

  if (kind == svn_node_dir)
    {
      SVN_ERR(svn_ra_get_dir2(ra_session,
                              (depth >= svn_depth_files ? &dirents : NULL),
                              NULL, &prop_hash, target_relative, revnum,
                              SVN_DIRENT_KIND, work_pool));
    }
  else if (kind == svn_node_file)
    {
      SVN_ERR(svn_ra_get_file(ra_session, target_relative, revnum,
                              NULL, NULL, &prop_hash, work_pool));
    }
  else if (kind == svn_node_none)
    {
      return svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, NULL,
                               _("'%s' does not exist in revision %ld"),
                               target_full_url, revnum);
    }
  else
    {
      return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
                               _("Unknown node kind for '%s'"),
                               target_full_url);
    }

  if ((val = apr_hash_get(prop_hash, propname, APR_HASH_KEY_STRING)))
    {
      apr_hash_set(props, apr_pstrdup(perm_pool, target_full_url),
                   APR_HASH_KEY_STRING, svn_string_dup(val, perm_pool));
    }

  if (depth >= svn_depth_files
      && kind == svn_node_dir
      && apr_hash_count(dirents) > 0)
    {
      apr_hash_index_t *hi;
      apr_pool_t *iterpool = svn_pool_create(work_pool);

      for (hi = apr_hash_first(work_pool, dirents);
           hi;
           hi = apr_hash_next(hi))
        {
          const char *this_name = svn__apr_hash_index_key(hi);
          svn_dirent_t *this_ent = svn__apr_hash_index_val(hi);
          const char *new_target_relative;
          svn_depth_t depth_below_here = depth;

          svn_pool_clear(iterpool);

          if (depth == svn_depth_files && this_ent->kind == svn_node_dir)
            continue;

          if (depth == svn_depth_files || depth == svn_depth_immediates)
            depth_below_here = svn_depth_empty;

          new_target_relative = svn_relpath_join(target_relative, this_name,
                                                 iterpool);

          SVN_ERR(remote_propget(props,
                                 propname,
                                 target_prefix,
                                 new_target_relative,
                                 this_ent->kind,
                                 revnum,
                                 ra_session,
                                 depth_below_here,
                                 perm_pool, iterpool));
        }

      svn_pool_destroy(iterpool);
    }

  return SVN_NO_ERROR;
}
svn_error_t *
svn_client_cat2(svn_stream_t *out,
                const char *path_or_url,
                const svn_opt_revision_t *peg_revision,
                const svn_opt_revision_t *revision,
                svn_client_ctx_t *ctx,
                apr_pool_t *pool)
{
  svn_ra_session_t *ra_session;
  svn_revnum_t rev;
  svn_string_t *eol_style;
  svn_string_t *keywords;
  apr_hash_t *props;
  const char *url;
  svn_stream_t *output = out;
  svn_error_t *err;

  /* ### Inconsistent default revision logic in this command. */
  if (peg_revision->kind == svn_opt_revision_unspecified)
    {
      peg_revision = svn_cl__rev_default_to_head_or_working(peg_revision,
                                                            path_or_url);
      revision = svn_cl__rev_default_to_head_or_base(revision, path_or_url);
    }
  else
    {
      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 (! 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))
    {
      const char *local_abspath;
      svn_stream_t *normal_stream;

      SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url, pool));
      SVN_ERR(svn_client__get_normalized_stream(&normal_stream, ctx->wc_ctx,
                                            local_abspath, revision, TRUE, FALSE,
                                            ctx->cancel_func, ctx->cancel_baton,
                                            pool, pool));

      /* We don't promise to close output, so disown it to ensure we don't. */
      output = svn_stream_disown(output, pool);

      return svn_error_trace(svn_stream_copy3(normal_stream, output,
                                              ctx->cancel_func,
                                              ctx->cancel_baton, pool));
    }

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

  /* Grab some properties we need to know in order to figure out if anything
     special needs to be done with this file. */
  err = svn_ra_get_file(ra_session, "", rev, NULL, NULL, &props, pool);
  if (err)
    {
      if (err->apr_err == SVN_ERR_FS_NOT_FILE)
        {
          return svn_error_createf(SVN_ERR_CLIENT_IS_DIRECTORY, err,
                                   _("URL '%s' refers to a directory"), url);
        }
      else
        {
          return svn_error_trace(err);
        }
    }

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

  if (eol_style || keywords)
    {
      /* It's a file with no special eol style or keywords. */
      svn_subst_eol_style_t eol;
      const char *eol_str;
      apr_hash_t *kw;

      if (eol_style)
        svn_subst_eol_style_from_value(&eol, &eol_str, eol_style->data);
      else
        {
          eol = svn_subst_eol_style_none;
          eol_str = NULL;
        }


      if (keywords)
        {
          svn_string_t *cmt_rev, *cmt_date, *cmt_author;
          apr_time_t when = 0;

          cmt_rev = apr_hash_get(props, SVN_PROP_ENTRY_COMMITTED_REV,
                                 APR_HASH_KEY_STRING);
          cmt_date = apr_hash_get(props, SVN_PROP_ENTRY_COMMITTED_DATE,
                                  APR_HASH_KEY_STRING);
          cmt_author = apr_hash_get(props, SVN_PROP_ENTRY_LAST_AUTHOR,
                                    APR_HASH_KEY_STRING);
          if (cmt_date)
            SVN_ERR(svn_time_from_cstring(&when, cmt_date->data, pool));

          SVN_ERR(svn_subst_build_keywords2
                  (&kw, keywords->data,
                   cmt_rev->data,
                   url,
                   when,
                   cmt_author ? cmt_author->data : NULL,
                   pool));
        }
      else
        kw = NULL;

      /* Interject a translating stream */
      output = svn_subst_stream_translated(svn_stream_disown(out, pool),
                                           eol_str, FALSE, kw, TRUE, pool);
    }

  SVN_ERR(svn_ra_get_file(ra_session, "", rev, output, NULL, NULL, pool));

  if (out != output)
    /* Close the interjected stream */
    SVN_ERR(svn_stream_close(output));

  return SVN_NO_ERROR;
}
Beispiel #10
0
svn_error_t *
svn_client__copy_foreign(const char *url,
                         const char *dst_abspath,
                         svn_opt_revision_t *peg_revision,
                         svn_opt_revision_t *revision,
                         svn_depth_t depth,
                         svn_boolean_t make_parents,
                         svn_boolean_t already_locked,
                         svn_client_ctx_t *ctx,
                         apr_pool_t *scratch_pool)
{
  svn_ra_session_t *ra_session;
  svn_client__pathrev_t *loc;
  svn_node_kind_t kind;
  svn_node_kind_t wc_kind;
  const char *dir_abspath;

  SVN_ERR_ASSERT(svn_path_is_url(url));
  SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));

  /* Do we need to validate/update revisions? */

  SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
                                            url, NULL,
                                            peg_revision,
                                            revision, ctx,
                                            scratch_pool));

  SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, scratch_pool));

  if (kind != svn_node_file && kind != svn_node_dir)
    return svn_error_createf(
                SVN_ERR_ILLEGAL_TARGET, NULL,
                _("'%s' is not a valid location inside a repository"),
                url);

  SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dst_abspath, FALSE, TRUE,
                            scratch_pool));

  if (wc_kind != svn_node_none)
    {
      return svn_error_createf(
                SVN_ERR_ENTRY_EXISTS, NULL,
                _("'%s' is already under version control"),
                svn_dirent_local_style(dst_abspath, scratch_pool));
    }

  dir_abspath = svn_dirent_dirname(dst_abspath, scratch_pool);
  SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dir_abspath,
                            FALSE, FALSE, scratch_pool));

  if (wc_kind == svn_node_none)
    {
      if (make_parents)
        SVN_ERR(svn_client__make_local_parents(dir_abspath, make_parents, ctx,
                                               scratch_pool));

      SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dir_abspath,
                                FALSE, FALSE, scratch_pool));
    }

  if (wc_kind != svn_node_dir)
    return svn_error_createf(
                SVN_ERR_ENTRY_NOT_FOUND, NULL,
                _("Can't add '%s', because no parent directory is found"),
                svn_dirent_local_style(dst_abspath, scratch_pool));


  if (kind == svn_node_file)
    {
      svn_stream_t *target;
      apr_hash_t *props;
      apr_hash_index_t *hi;
      SVN_ERR(svn_stream_open_writable(&target, dst_abspath, scratch_pool,
                                       scratch_pool));

      SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev, target, NULL, &props,
                              scratch_pool));

      if (props != NULL)
        for (hi = apr_hash_first(scratch_pool, props); hi;
             hi = apr_hash_next(hi))
          {
            const char *name = apr_hash_this_key(hi);

            if (svn_property_kind2(name) != svn_prop_regular_kind
                || ! strcmp(name, SVN_PROP_MERGEINFO))
              {
                /* We can't handle DAV, ENTRY and merge specific props here */
                svn_hash_sets(props, name, NULL);
              }
          }

      if (!already_locked)
        SVN_WC__CALL_WITH_WRITE_LOCK(
              svn_wc_add_from_disk3(ctx->wc_ctx, dst_abspath, props,
                                    TRUE /* skip checks */,
                                    ctx->notify_func2, ctx->notify_baton2,
                                    scratch_pool),
              ctx->wc_ctx, dir_abspath, FALSE, scratch_pool);
      else
        SVN_ERR(svn_wc_add_from_disk3(ctx->wc_ctx, dst_abspath, props,
                                      TRUE /* skip checks */,
                                      ctx->notify_func2, ctx->notify_baton2,
                                      scratch_pool));
    }
  else
    {
      if (!already_locked)
        SVN_WC__CALL_WITH_WRITE_LOCK(
              copy_foreign_dir(ra_session, loc,
                               ctx->wc_ctx, dst_abspath,
                               depth,
                               ctx->notify_func2, ctx->notify_baton2,
                               ctx->cancel_func, ctx->cancel_baton,
                               scratch_pool),
              ctx->wc_ctx, dir_abspath, FALSE, scratch_pool);
      else
        SVN_ERR(copy_foreign_dir(ra_session, loc,
                                 ctx->wc_ctx, dst_abspath,
                                 depth,
                                 ctx->notify_func2, ctx->notify_baton2,
                                 ctx->cancel_func, ctx->cancel_baton,
                                 scratch_pool));
    }

  return SVN_NO_ERROR;
}
Beispiel #11
0
svn_error_t *
svn_ra__file_revs_from_log(svn_ra_session_t *ra_session,
                           const char *path,
                           svn_revnum_t start,
                           svn_revnum_t end,
                           svn_file_rev_handler_t handler,
                           void *handler_baton,
                           apr_pool_t *pool)
{
  svn_node_kind_t kind;
  const char *repos_url, *session_url, *fs_path;
  apr_array_header_t *condensed_targets;
  struct fr_log_message_baton lmb;
  struct rev *rev;
  apr_hash_t *last_props;
  svn_stream_t *last_stream;
  apr_pool_t *currpool, *lastpool;

  /* Fetch the absolute FS path associated with PATH. */
  SVN_ERR(get_fs_path(&fs_path, ra_session, path, pool));

  /* Check to make sure we're dealing with a file. */
  SVN_ERR(svn_ra_check_path(ra_session, path, end, &kind, pool));
  if (kind == svn_node_dir)
    return svn_error_createf(SVN_ERR_FS_NOT_FILE, NULL,
                             _("'%s' is not a file"), fs_path);

  condensed_targets = apr_array_make(pool, 1, sizeof(const char *));
  APR_ARRAY_PUSH(condensed_targets, const char *) = path;

  lmb.path = fs_path;
  lmb.eldest = NULL;
  lmb.pool = pool;

  /* Accumulate revision metadata by walking the revisions
     backwards; this allows us to follow moves/copies
     correctly. */
  SVN_ERR(svn_ra_get_log2(ra_session,
                          condensed_targets,
                          end, start, 0, /* no limit */
                          TRUE, FALSE, FALSE,
                          NULL, fr_log_message_receiver, &lmb,
                          pool));

  /* Reparent the session while we go back through the history. */
  SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, pool));
  SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_url, pool));
  SVN_ERR(svn_ra_reparent(ra_session, repos_url, pool));

  currpool = svn_pool_create(pool);
  lastpool = svn_pool_create(pool);

  /* We want the first txdelta to be against the empty file. */
  last_props = apr_hash_make(lastpool);
  last_stream = svn_stream_empty(lastpool);

  /* Walk the revision list in chronological order, downloading each fulltext,
     diffing it with its predecessor, and calling the file_revs handler for
     each one.  Use two iteration pools rather than one, because the diff
     routines need to look at a sliding window of revisions.  Two pools gives
     us a ring buffer of sorts. */
  for (rev = lmb.eldest; rev; rev = rev->next)
    {
      const char *temp_path;
      apr_pool_t *tmppool;
      apr_hash_t *props;
      apr_file_t *file;
      svn_stream_t *stream;
      apr_array_header_t *prop_diffs;
      svn_txdelta_stream_t *delta_stream;
      svn_txdelta_window_handler_t delta_handler = NULL;
      void *delta_baton = NULL;

      svn_pool_clear(currpool);

      /* Get the contents of the file from the repository, and put them in
         a temporary local file. */
      SVN_ERR(svn_stream_open_unique(&stream, &temp_path, NULL,
                                     svn_io_file_del_on_pool_cleanup,
                                     currpool, currpool));
      SVN_ERR(svn_ra_get_file(ra_session, rev->path + 1, rev->revision,
                              stream, NULL, &props, currpool));
      SVN_ERR(svn_stream_close(stream));

      /* Open up a stream to the local file. */
      SVN_ERR(svn_io_file_open(&file, temp_path, APR_READ, APR_OS_DEFAULT,
                               currpool));
      stream = svn_stream_from_aprfile2(file, FALSE, currpool);

      /* Calculate the property diff */
      SVN_ERR(svn_prop_diffs(&prop_diffs, props, last_props, lastpool));

      /* Call the file_rev handler */
      SVN_ERR(handler(handler_baton, rev->path, rev->revision, rev->props,
                      FALSE, /* merged revision */
                      &delta_handler, &delta_baton, prop_diffs, lastpool));

      /* Compute and send delta if client asked for it. */
      if (delta_handler)
        {
          /* Get the content delta. Don't calculate checksums as we don't
           * use them. */
          svn_txdelta2(&delta_stream, last_stream, stream, FALSE, lastpool);

          /* And send. */
          SVN_ERR(svn_txdelta_send_txstream(delta_stream, delta_handler,
                                            delta_baton, lastpool));
        }

      /* Switch the pools and data for the next iteration */
      tmppool = currpool;
      currpool = lastpool;
      lastpool = tmppool;

      SVN_ERR(svn_stream_close(last_stream));
      last_stream = stream;
      last_props = props;
    }

  SVN_ERR(svn_stream_close(last_stream));
  svn_pool_destroy(currpool);
  svn_pool_destroy(lastpool);

  /* Reparent the session back to the original URL. */
  return svn_ra_reparent(ra_session, session_url, pool);
}