Beispiel #1
0
/* Implements svn_ra_neon__startelm_cb_t. */
static svn_error_t *
start_207_element(int *elem, void *baton, int parent,
                  const char *nspace, const char *name, const char **atts)
{
  multistatus_baton_t *b = baton;
  const svn_ra_neon__xml_elm_t *elm =
    svn_ra_neon__lookup_xml_elem(multistatus_elements, nspace, name);
  *elem = elm ? validate_element(parent, elm->id) : SVN_RA_NEON__XML_DECLINE;


  if (parent == ELEM_prop)
    {
      svn_stringbuf_setempty(b->propname);
      if (strcmp(nspace, SVN_DAV_PROP_NS_SVN) == 0)
        svn_stringbuf_set(b->propname, SVN_PROP_PREFIX);
      else if (strcmp(nspace, "DAV:") == 0)
        svn_stringbuf_set(b->propname, "DAV:");

      svn_stringbuf_appendcstr(b->propname, name);
    }

  if (*elem < 1) /* ! > 0 */
    return SVN_NO_ERROR;

  switch (*elem)
    {
    case ELEM_propstat:
      b->in_propstat = TRUE;
      b->propstat_has_error = FALSE;
      break;

    default:
      break;
    }

  /* We're guaranteed to have ELM now: SVN_RA_NEON__XML_DECLINE < 1 */
  if (elm->flags & SVN_RA_NEON__XML_CDATA)
    {
      svn_stringbuf_setempty(b->cdata);
      b->want_cdata = b->cdata;
    }

  return SVN_NO_ERROR;
}
Beispiel #2
0
/* Return a pointer to an option in CFG, or NULL if it doesn't exist.
   if SECTIONP is non-null, return a pointer to the option's section.
   OPTION may be NULL. */
static cfg_option_t *
find_option(svn_config_t *cfg, const char *section, const char *option,
            cfg_section_t **sectionp)
{
  void *sec_ptr;

  /* Canonicalize the hash key */
  svn_stringbuf_set(cfg->tmp_key, section);
  make_hash_key(cfg->tmp_key->data);

  sec_ptr = apr_hash_get(cfg->sections, cfg->tmp_key->data,
                         cfg->tmp_key->len);
  if (sectionp != NULL)
    *sectionp = sec_ptr;

  if (sec_ptr != NULL && option != NULL)
    {
      cfg_section_t *sec = sec_ptr;
      cfg_option_t *opt;

      /* Canonicalize the option key */
      svn_stringbuf_set(cfg->tmp_key, option);
      make_hash_key(cfg->tmp_key->data);

      opt = apr_hash_get(sec->options, cfg->tmp_key->data,
                         cfg->tmp_key->len);
      /* NOTE: ConfigParser's sections are case sensitive. */
      if (opt == NULL
          && apr_strnatcasecmp(section, SVN_CONFIG__DEFAULT_SECTION) != 0)
        /* Options which aren't found in the requested section are
           also sought after in the default section. */
        opt = find_option(cfg, SVN_CONFIG__DEFAULT_SECTION, option, &sec);
      return opt;
    }

  return NULL;
}
Beispiel #3
0
/* construct the repos-local name for the given DAV property name */
static void
get_repos_propname(dav_db *db,
                   const dav_prop_name *name,
                   const char **repos_propname)
{
  if (strcmp(name->ns, SVN_DAV_PROP_NS_SVN) == 0)
    {
      /* recombine the namespace ("svn:") and the name. */
      svn_stringbuf_set(db->work, SVN_PROP_PREFIX);
      svn_stringbuf_appendcstr(db->work, name->name);
      *repos_propname = db->work->data;
    }
  else if (strcmp(name->ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
    {
      /* the name of a custom prop is just the name -- no ns URI */
      *repos_propname = name->name;
    }
  else
    {
      *repos_propname = NULL;
    }
}
Beispiel #4
0
/* A helper function to parse_local_abspath() which returns the on-disk KIND
   of LOCAL_ABSPATH, using DB and SCRATCH_POOL as needed.

   This function may do strange things, but at long as it comes up with the
   Right Answer, we should be happy. */
static svn_error_t *
get_path_kind(svn_node_kind_t *kind,
              svn_wc__db_t *db,
              const char *local_abspath,
              apr_pool_t *scratch_pool)
{
  svn_boolean_t special;
  svn_node_kind_t node_kind;

  /* This implements a *really* simple LRU cache, where "simple" is defined
     as "only one element".  In other words, we remember the most recently
     queried path, and nothing else.  This gives >80% cache hits. */

  if (db->parse_cache.abspath
        && strcmp(db->parse_cache.abspath->data, local_abspath) == 0)
    {
      /* Cache hit! */
      *kind = db->parse_cache.kind;
      return SVN_NO_ERROR;
    }

  if (!db->parse_cache.abspath)
    {
      db->parse_cache.abspath = svn_stringbuf_create(local_abspath,
                                                     db->state_pool);
    }
  else
    {
      svn_stringbuf_set(db->parse_cache.abspath, local_abspath);
    }

  SVN_ERR(svn_io_check_special_path(local_abspath, &node_kind,
                                    &special, scratch_pool));

  db->parse_cache.kind = (special ? svn_node_symlink : node_kind);
  *kind = db->parse_cache.kind;

  return SVN_NO_ERROR;
}
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__status(apr_getopt_t *os,
               void *baton,
               apr_pool_t *pool)
{
    svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
    svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
    apr_array_header_t *targets;
    apr_pool_t *subpool;
    apr_hash_t *master_cl_hash = apr_hash_make(pool);
    int i;
    svn_opt_revision_t rev;
    struct status_baton sb;

    SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
            opt_state->targets,
            ctx, pool));

    /* Add "." if user passed 0 arguments */
    svn_opt_push_implicit_dot_target(targets, pool);

    /* We want our -u statuses to be against HEAD. */
    rev.kind = svn_opt_revision_head;

    /* The notification callback, leave the notifier as NULL in XML mode */
    if (! opt_state->xml)
        svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, FALSE,
                             FALSE, FALSE, pool);

    subpool = svn_pool_create(pool);

    sb.had_print_error = FALSE;

    if (opt_state->xml)
    {
        /* If output is not incremental, output the XML header and wrap
           everything in a top-level element. This makes the output in
           its entirety a well-formed XML document. */
        if (! opt_state->incremental)
            SVN_ERR(svn_cl__xml_print_header("status", pool));
    }
    else
    {
        if (opt_state->incremental)
            return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                    _("'incremental' option only valid in XML "
                                      "mode"));
    }

    sb.detailed = (opt_state->verbose || opt_state->update);
    sb.show_last_committed = opt_state->verbose;
    sb.skip_unrecognized = opt_state->quiet;
    sb.repos_locks = opt_state->update;
    sb.xml_mode = opt_state->xml;
    sb.cached_changelists = master_cl_hash;
    sb.cl_pool = pool;

    SVN_ERR(svn_opt__eat_peg_revisions(&targets, targets, pool));

    for (i = 0; i < targets->nelts; i++)
    {
        const char *target = APR_ARRAY_IDX(targets, i, const char *);
        svn_revnum_t repos_rev = SVN_INVALID_REVNUM;

        svn_pool_clear(subpool);

        SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));

        if (opt_state->xml)
            SVN_ERR(print_start_target_xml(svn_path_local_style(target, subpool),
                                           subpool));

        /* Retrieve a hash of status structures with the information
           requested by the user. */
        SVN_ERR(svn_cl__try(svn_client_status4(&repos_rev, target, &rev,
                                               print_status, &sb,
                                               opt_state->depth,
                                               opt_state->verbose,
                                               opt_state->update,
                                               opt_state->no_ignore,
                                               opt_state->ignore_externals,
                                               opt_state->changelists,
                                               ctx, subpool),
                            NULL, opt_state->quiet,
                            /* not versioned: */
                            SVN_ERR_WC_NOT_DIRECTORY,
                            SVN_NO_ERROR));

        if (opt_state->xml)
            SVN_ERR(print_finish_target_xml(repos_rev, subpool));
    }

    /* If any paths were cached because they were associatied with
       changelists, we can now display them as grouped changelists. */
    if (apr_hash_count(master_cl_hash) > 0)
    {
        apr_hash_index_t *hi;
        svn_stringbuf_t *buf;

        if (opt_state->xml)
            buf = svn_stringbuf_create("", pool);

        for (hi = apr_hash_first(pool, master_cl_hash); hi;
                hi = apr_hash_next(hi))
        {
            const char *changelist_name;
            apr_array_header_t *path_array;
            const void *key;
            void *val;
            int j;

            apr_hash_this(hi, &key, NULL, &val);
            changelist_name = key;
            path_array = val;

            /* ### TODO: For non-XML output, we shouldn't print the
               ### leading \n on the first changelist if there were no
               ### non-changelist entries. */
            if (opt_state->xml)
            {
                svn_stringbuf_set(buf, "");
                svn_xml_make_open_tag(&buf, pool, svn_xml_normal, "changelist",
                                      "name", changelist_name, NULL);
                SVN_ERR(svn_cl__error_checked_fputs(buf->data, stdout));
            }
            else
                SVN_ERR(svn_cmdline_printf(pool, _("\n--- Changelist '%s':\n"),
                                           changelist_name));

            for (j = 0; j < path_array->nelts; j++)
            {
                struct status_cache *scache =
                    APR_ARRAY_IDX(path_array, j, struct status_cache *);
                SVN_ERR(print_status_normal_or_xml(&sb, scache->path,
                                                   scache->status, pool));
            }

            if (opt_state->xml)
            {
                svn_stringbuf_set(buf, "");
                svn_xml_make_close_tag(&buf, pool, "changelist");
                SVN_ERR(svn_cl__error_checked_fputs(buf->data, stdout));
            }
        }
    }
Beispiel #6
0
/* Implements svn_ra_neon__endelm_cb_t . */
static svn_error_t *
end_207_element(void *baton, int state,
                const char *nspace, const char *name)
{
  multistatus_baton_t *b = baton;

  switch (state)
    {
    case ELEM_multistatus:
      if (b->contains_error)
        {
          if (svn_stringbuf_isempty(b->description))
            return svn_error_create(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
                                    _("The request response contained at least "
                                      "one error"));
          else if (b->contains_precondition_error)
            return svn_error_create(SVN_ERR_FS_PROP_BASEVALUE_MISMATCH, NULL,
                                    b->description->data);
          else
            return svn_error_create(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
                                    b->description->data);
        }
      break;

    case ELEM_responsedescription:
      if (b->in_propstat)
        svn_stringbuf_set(b->propstat_description, b->cdata->data);
      else
        {
          if (! svn_stringbuf_isempty(b->description))
            svn_stringbuf_appendcstr(b->description, "\n");
          svn_stringbuf_appendstr(b->description, b->cdata);
        }
      break;

    case ELEM_status:
      {
        ne_status status;

        if (ne_parse_statusline(b->cdata->data, &status) == 0)
          {
            /*### I wanted ||=, but I guess the end result is the same */
            if (! b->in_propstat)
              b->contains_error |= (status.klass != 2);
            else
              b->propstat_has_error = (status.klass != 2);

            /* Handle "412 Precondition Failed" specially */
            if (status.code == 412)
              b->contains_precondition_error = TRUE;

            free(status.reason_phrase);
          }
        else
          return svn_error_create(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
                                  _("The response contains a non-conforming "
                                    "HTTP status line"));
      }
      break;

    case ELEM_propstat:
      b->in_propstat = FALSE;
      b->contains_error |= b->propstat_has_error;
      svn_stringbuf_appendcstr(b->description,
                               apr_psprintf(b->req->pool,
                                            _("Error setting property '%s': "),
                                            b->propname->data));
      svn_stringbuf_appendstr(b->description,
                              b->propstat_description);

    default:
      /* do nothing */
      break;
    }

  /* When we have an element which wants cdata,
     we'll set it all up in start_207_element() again */
  b->want_cdata = NULL;

  return SVN_NO_ERROR;
}
Beispiel #7
0
/* Conforms to svn_ra_serf__xml_closed_t  */
static svn_error_t *
item_closed(svn_ra_serf__xml_estate_t *xes,
            void *baton,
            int leaving_state,
            const svn_string_t *cdata,
            apr_hash_t *attrs,
            apr_pool_t *scratch_pool)
{
  list_context_t *list_ctx = baton;

  if (leaving_state == AUTHOR)
    {
      /* For compatibility with liveprops, current servers will not use
       * base64-encoding for "binary" user names bu simply drop the
       * offending control chars.
       *
       * We might want to switch to revprop-style encoding, though,
       * and this is the code to do that. */
      const char *encoding = svn_hash_gets(attrs, "encoding");
      if (encoding)
        {
          /* Check for a known encoding type.  This is easy -- there's
             only one.  */
          if (strcmp(encoding, "base64") != 0)
            {
              return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
                                       _("Unsupported encoding '%s'"),
                                       encoding);
            }

          cdata = svn_base64_decode_string(cdata, scratch_pool);
        }

      /* Remember until the next ITEM closing tag. */
      svn_stringbuf_set(list_ctx->author_buf, cdata->data);
      list_ctx->author = list_ctx->author_buf->data;
    }
  else if (leaving_state == ITEM)
    {
      const char *dirent_path = cdata->data;
      const char *kind_word, *date, *crev, *size;
      svn_dirent_t dirent = { 0 };

      kind_word = svn_hash_gets(attrs, "node-kind");
      size = svn_hash_gets(attrs, "size");

      dirent.has_props = svn_hash__get_bool(attrs, "has-props", FALSE);
      crev = svn_hash_gets(attrs, "created-rev");
      date = svn_hash_gets(attrs, "date");

      /* Convert data. */
      dirent.kind = svn_node_kind_from_word(kind_word);

      if (size)
        SVN_ERR(svn_cstring_atoi64(&dirent.size, size));
      else
        dirent.size = SVN_INVALID_FILESIZE;

      if (crev)
        SVN_ERR(svn_revnum_parse(&dirent.created_rev, crev, NULL));
      else
        dirent.created_rev = SVN_INVALID_REVNUM;

      if (date)
        SVN_ERR(svn_time_from_cstring(&dirent.time, date, scratch_pool));

      if (list_ctx->author)
        dirent.last_author = list_ctx->author;

      /* Invoke RECEIVER */
      SVN_ERR(list_ctx->receiver(dirent_path, &dirent,
                                 list_ctx->receiver_baton, scratch_pool));

      /* Reset buffered info. */
      list_ctx->author = NULL;
    }

  return SVN_NO_ERROR;
}
Beispiel #8
0
svn_error_t *
svn_ra_neon__search_for_starting_props(svn_ra_neon__resource_t **rsrc,
                                       const char **missing_path,
                                       svn_ra_neon__session_t *sess,
                                       const char *url,
                                       apr_pool_t *pool)
{
  svn_error_t *err = SVN_NO_ERROR;
  apr_size_t len;
  svn_stringbuf_t *path_s;
  ne_uri parsed_url;
  svn_stringbuf_t *lopped_path =
    svn_stringbuf_create(url, pool); /* initialize to make sure it'll fit
                                        without reallocating */
  apr_pool_t *iterpool = svn_pool_create(pool);

  /* Split the url into its component pieces (scheme, host, path,
     etc).  We want the path part. */
  ne_uri_parse(url, &parsed_url);
  if (parsed_url.path == NULL)
    {
      ne_uri_free(&parsed_url);
      return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
                               _("Neon was unable to parse URL '%s'"), url);
    }

  svn_stringbuf_setempty(lopped_path);
  path_s = svn_stringbuf_create(parsed_url.path, pool);
  ne_uri_free(&parsed_url);

  /* Try to get the starting_props from the public url.  If the
     resource no longer exists in HEAD, we'll get a failure.  That's
     fine: just keep removing components and trying to get the
     starting_props from parent directories. */
  while (! svn_path_is_empty(path_s->data))
    {
      svn_pool_clear(iterpool);
      err = svn_ra_neon__get_starting_props(rsrc, sess, path_s->data,
                                            NULL, iterpool);
      if (! err)
        break;   /* found an existing parent! */

      if (err->apr_err != SVN_ERR_FS_NOT_FOUND)
        return err;  /* found a _real_ error */

      /* else... lop off the basename and try again. */
      svn_stringbuf_set(lopped_path,
                        svn_path_join(svn_path_basename(path_s->data, iterpool),
                                      lopped_path->data, iterpool));

      len = path_s->len;
      svn_path_remove_component(path_s);

      /* if we detect an infinite loop, get out. */
      if (path_s->len == len)
        return svn_error_quick_wrap
          (err, _("The path was not part of a repository"));

      svn_error_clear(err);
    }

  /* error out if entire URL was bogus (not a single part of it exists
     in the repository!)  */
  if (svn_path_is_empty(path_s->data))
    return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
                             _("No part of path '%s' was found in "
                               "repository HEAD"), parsed_url.path);

  /* Duplicate rsrc out of iterpool into pool */
  {
    apr_hash_index_t *hi;
    svn_ra_neon__resource_t *tmp = apr_pcalloc(pool, sizeof(*tmp));
    tmp->url = apr_pstrdup(pool, (*rsrc)->url);
    tmp->is_collection = (*rsrc)->is_collection;
    tmp->pool = pool;
    tmp->propset = apr_hash_make(pool);

    for (hi = apr_hash_first(iterpool, (*rsrc)->propset);
         hi; hi = apr_hash_next(hi))
      {
        const void *key;
        void *val;

        apr_hash_this(hi, &key, NULL, &val);
        apr_hash_set(tmp->propset, apr_pstrdup(pool, key), APR_HASH_KEY_STRING,
                     svn_string_dup(val, pool));
      }

    *rsrc = tmp;
  }
  *missing_path = lopped_path->data;
  svn_pool_destroy(iterpool);
  return SVN_NO_ERROR;
}