Example #1
0
static svn_error_t *
file_change_prop(void *file_baton,
                 const char *name,
                 const svn_string_t *value,
                 apr_pool_t *scratch_pool)
{
  struct file_baton_t *fb = file_baton;
  svn_prop_kind_t prop_kind;

  prop_kind = svn_property_kind2(name);

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

  /* We store all properties in the hash for immediate addition
      with the svn_wc_add_from_disk3() call */
  if (! fb->properties)
    fb->properties = apr_hash_make(fb->pool);

  if (value != NULL)
    svn_hash_sets(fb->properties, apr_pstrdup(fb->pool, name),
                  svn_string_dup(value, fb->pool));

  return SVN_NO_ERROR;
}
Example #2
0
svn_error_t *
svn_repos__validate_prop(const char *name,
                         const svn_string_t *value,
                         apr_pool_t *pool)
{
    svn_prop_kind_t kind = svn_property_kind2(name);

    /* Allow deleting any property, even a property we don't allow to set. */
    if (value == NULL)
        return SVN_NO_ERROR;

    /* Disallow setting non-regular properties. */
    if (kind != svn_prop_regular_kind)
        return svn_error_createf
               (SVN_ERR_REPOS_BAD_ARGS, NULL,
                _("Storage of non-regular property '%s' is disallowed through the "
                  "repository interface, and could indicate a bug in your client"),
                name);

    /* Validate "svn:" properties. */
    if (svn_prop_is_svn_prop(name) && value != NULL)
    {
        /* Validate that translated props (e.g., svn:log) are UTF-8 with
         * LF line endings. */
        if (svn_prop_needs_translation(name))
        {
            if (!svn_utf__is_valid(value->data, value->len))
            {
                return svn_error_createf
                       (SVN_ERR_BAD_PROPERTY_VALUE, NULL,
                        _("Cannot accept '%s' property because it is not encoded in "
                          "UTF-8"), name);
            }

            /* Disallow inconsistent line ending style, by simply looking for
             * carriage return characters ('\r'). */
            if (strchr(value->data, '\r') != NULL)
            {
                return svn_error_createf
                       (SVN_ERR_BAD_PROPERTY_VALUE, NULL,
                        _("Cannot accept non-LF line endings in '%s' property"),
                        name);
            }
        }

        /* "svn:date" should be a valid date. */
        if (strcmp(name, SVN_PROP_REVISION_DATE) == 0)
        {
            apr_time_t temp;
            svn_error_t *err;

            err = svn_time_from_cstring(&temp, value->data, pool);
            if (err)
                return svn_error_create(SVN_ERR_BAD_PROPERTY_VALUE,
                                        err, NULL);
        }
    }

    return SVN_NO_ERROR;
}
Example #3
0
static svn_error_t *
change_file_prop(void *file_baton,
                 const char *name,
                 const svn_string_t *value,
                 apr_pool_t *pool)
{
  node_baton_t *fb = file_baton;
  edit_baton_t *eb = fb->edit_baton;

  /* only regular properties can pass over libsvn_ra */
  if (svn_property_kind2(name) != svn_prop_regular_kind)
    return SVN_NO_ERROR;

  /* Maybe drop svn:mergeinfo.  */
  if (eb->strip_mergeinfo && (strcmp(name, SVN_PROP_MERGEINFO) == 0))
    {
      eb->mergeinfo_stripped = TRUE;
      return SVN_NO_ERROR;
    }

  /* Maybe drop (errantly set, as this is a file) svnmerge.py properties. */
  if (eb->migrate_svnmerge && (strcmp(name, "svnmerge-integrated") == 0))
    {
      eb->svnmerge_migrated = TRUE;
      return SVN_NO_ERROR;
    }

  /* Remember if we see any svnmerge-blocked properties.  (They really
     shouldn't be here, as this is a file, but whatever...)  */
  if (eb->migrate_svnmerge && (strcmp(name, "svnmerge-blocked") == 0))
    {
      eb->svnmerge_blocked = TRUE;
    }

  /* Normalize svn:* properties as necessary. */
  if (svn_prop_needs_translation(name))
    {
      svn_boolean_t was_normalized;
      svn_boolean_t mergeinfo_tweaked = FALSE;

      /* Normalize encoding to UTF-8, and EOL style to LF. */
      SVN_ERR(normalize_string(&value, &was_normalized,
                               eb->source_prop_encoding, pool, pool));
      /* Correct malformed mergeinfo. */
      if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0)
        {
          SVN_ERR(remove_r0_mergeinfo(&value, &mergeinfo_tweaked,
                                      pool, pool));
          if (mergeinfo_tweaked)
            eb->mergeinfo_tweaked = TRUE;
        }
      if (was_normalized)
        (*(eb->normalized_node_props_counter))++;
    }

  return eb->wrapped_editor->change_file_prop(fb->wrapped_node_baton,
                                              name, value, pool);
}
Example #4
0
svn_error_t *
svn_categorize_props(const apr_array_header_t *proplist,
                     apr_array_header_t **entry_props,
                     apr_array_header_t **wc_props,
                     apr_array_header_t **regular_props,
                     apr_pool_t *pool)
{
  int i;
  if (entry_props)
    *entry_props = apr_array_make(pool, 1, sizeof(svn_prop_t));
  if (wc_props)
    *wc_props = apr_array_make(pool, 1, sizeof(svn_prop_t));
  if (regular_props)
    *regular_props = apr_array_make(pool, 1, sizeof(svn_prop_t));

  for (i = 0; i < proplist->nelts; i++)
    {
      svn_prop_t *prop, *newprop;
      enum svn_prop_kind kind;

      prop = &APR_ARRAY_IDX(proplist, i, svn_prop_t);
      kind = svn_property_kind2(prop->name);
      newprop = NULL;

      if (kind == svn_prop_regular_kind)
        {
          if (regular_props)
            newprop = apr_array_push(*regular_props);
        }
      else if (kind == svn_prop_wc_kind)
        {
          if (wc_props)
            newprop = apr_array_push(*wc_props);
        }
      else if (kind == svn_prop_entry_kind)
        {
          if (entry_props)
            newprop = apr_array_push(*entry_props);
        }
      else
        /* Technically this can't happen, but might as well have the
           code ready in case that ever changes. */
        return svn_error_createf(SVN_ERR_BAD_PROP_KIND, NULL,
                                 "Bad property kind for property '%s'",
                                 prop->name);

      if (newprop)
        {
          newprop->name = prop->name;
          newprop->value = prop->value;
        }
    }

  return SVN_NO_ERROR;
}
Example #5
0
/* Removes all non regular properties from PROPS */
void
svn_ra_serf__keep_only_regular_props(apr_hash_t *props,
                                     apr_pool_t *scratch_pool)
{
  apr_hash_index_t *hi;

  for (hi = apr_hash_first(scratch_pool, props); hi; hi = apr_hash_next(hi))
    {
      const char *propname = apr_hash_this_key(hi);

      if (svn_property_kind2(propname) != svn_prop_regular_kind)
        svn_hash_sets(props, propname, NULL);
    }
}
Example #6
0
/* NOTE: this function is deprecated, but we cannot move it to deprecated.c
   because we need the SIZEOF_*_PREFIX constant symbols defined above.  */
svn_prop_kind_t
svn_property_kind(int *prefix_len,
                  const char *prop_name)
{
  svn_prop_kind_t kind = svn_property_kind2(prop_name);

  if (prefix_len)
    {
      if (kind == svn_prop_wc_kind)
        *prefix_len = SIZEOF_WC_PREFIX;
      else if (kind == svn_prop_entry_kind)
        *prefix_len = SIZEOF_ENTRY_PREFIX;
      else
        *prefix_len = 0;
    }

  return kind;
}
Example #7
0
static svn_error_t *
dir_change_prop(void *dir_baton,
                const char *name,
                const svn_string_t *value,
                apr_pool_t *scratch_pool)
{
  struct dir_baton_t *db = dir_baton;
  struct edit_baton_t *eb = db->eb;
  svn_prop_kind_t prop_kind;

  prop_kind = svn_property_kind2(name);

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

  if (! db->created)
    {
      /* We can still store them in the hash for immediate addition
         with the svn_wc_add_from_disk3() call */
      if (! db->properties)
        db->properties = apr_hash_make(db->pool);

      if (value != NULL)
        svn_hash_sets(db->properties, apr_pstrdup(db->pool, name),
                      svn_string_dup(value, db->pool));
    }
  else
    {
      /* We have already notified for this directory, so don't do that again */
      SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, db->local_abspath, name, value,
                               svn_depth_empty, FALSE, NULL,
                               NULL, NULL, /* Cancellation */
                               NULL, NULL, /* Notification */
                               scratch_pool));
    }

  return SVN_NO_ERROR;
}
Example #8
0
/* Are there any changes to relevant (normal) props in PROPS? */
static svn_boolean_t
props_changed_hash(apr_hash_t *props,
                   apr_pool_t *scratch_pool)
{
  apr_hash_index_t *hi;

  if (!props)
    return FALSE;

  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)
        {
          return TRUE;
        }
    }

  return FALSE;
}
Example #9
0
static svn_error_t *
file_change_prop(void *file_baton,
                 const char *name,
                 const svn_string_t *value,
                 apr_pool_t *scratch_pool)
{
  struct file_baton_t *fb = file_baton;
  struct edit_baton_t *eb = fb->eb;
  svn_prop_kind_t prop_kind;

  prop_kind = svn_property_kind2(name);

  if (prop_kind != svn_prop_regular_kind
      || (eb->ignore_mergeinfo_changes && ! strcmp(name, SVN_PROP_MERGEINFO)))
    {
      /* We can't handle DAV, ENTRY and merge specific props here */
      return SVN_NO_ERROR;
    }

  if (! fb->created)
    {
      /* Store properties to be added later in svn_wc_add_from_disk3() */
      if (! fb->properties)
        fb->properties = apr_hash_make(fb->pool);

      if (value != NULL)
        svn_hash_sets(fb->properties, apr_pstrdup(fb->pool, name),
                      svn_string_dup(value, fb->pool));
    }
  else
    {
      SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, fb->local_abspath, name, value,
                               svn_depth_empty, FALSE, NULL,
                               NULL, NULL, /* Cancellation */
                               NULL, NULL, /* Notification */
                               scratch_pool));
    }

  return SVN_NO_ERROR;
}
Example #10
0
static svn_error_t *
change_dir_prop(void *dir_baton,
                const char *name,
                const svn_string_t *value,
                apr_pool_t *pool)
{
  node_baton_t *db = dir_baton;
  edit_baton_t *eb = db->edit_baton;

  /* Only regular properties can pass over libsvn_ra */
  if (svn_property_kind2(name) != svn_prop_regular_kind)
    return SVN_NO_ERROR;

  /* Maybe drop svn:mergeinfo.  */
  if (eb->strip_mergeinfo && (strcmp(name, SVN_PROP_MERGEINFO) == 0))
    {
      eb->mergeinfo_stripped = TRUE;
      return SVN_NO_ERROR;
    }

  /* Maybe convert svnmerge-integrated data into svn:mergeinfo.  (We
     ignore svnmerge-blocked for now.) */
  /* ### FIXME: Consult the mirror repository's HEAD prop values and
     ### merge svn:mergeinfo, svnmerge-integrated, and svnmerge-blocked. */
  if (eb->migrate_svnmerge && (strcmp(name, "svnmerge-integrated") == 0))
    {
      if (value)
        {
          /* svnmerge-integrated differs from svn:mergeinfo in a pair
             of ways.  First, it can use tabs, newlines, or spaces to
             delimit source information.  Secondly, the source paths
             are relative URLs, whereas svn:mergeinfo uses relative
             paths (not URI-encoded). */
          svn_error_t *err;
          svn_stringbuf_t *mergeinfo_buf = svn_stringbuf_create_empty(pool);
          svn_mergeinfo_t mergeinfo;
          int i;
          apr_array_header_t *sources =
            svn_cstring_split(value->data, " \t\n", TRUE, pool);
          svn_string_t *new_value;

          for (i = 0; i < sources->nelts; i++)
            {
              const char *rel_path;
              apr_array_header_t *path_revs =
                svn_cstring_split(APR_ARRAY_IDX(sources, i, const char *),
                                  ":", TRUE, pool);

              /* ### TODO: Warn? */
              if (path_revs->nelts != 2)
                continue;

              /* Append this source's mergeinfo data. */
              rel_path = APR_ARRAY_IDX(path_revs, 0, const char *);
              rel_path = svn_path_uri_decode(rel_path, pool);
              svn_stringbuf_appendcstr(mergeinfo_buf, rel_path);
              svn_stringbuf_appendcstr(mergeinfo_buf, ":");
              svn_stringbuf_appendcstr(mergeinfo_buf,
                                       APR_ARRAY_IDX(path_revs, 1,
                                                     const char *));
              svn_stringbuf_appendcstr(mergeinfo_buf, "\n");
            }

          /* Try to parse the mergeinfo string we've created, just to
             check for bogosity.  If all goes well, we'll unparse it
             again and use that as our property value.  */
          err = svn_mergeinfo_parse(&mergeinfo, mergeinfo_buf->data, pool);
          if (err)
            {
              svn_error_clear(err);
              return SVN_NO_ERROR;
            }
          SVN_ERR(svn_mergeinfo_to_string(&new_value, mergeinfo, pool));
          value = new_value;
        }
      name = SVN_PROP_MERGEINFO;
      eb->svnmerge_migrated = TRUE;
    }

  /* Remember if we see any svnmerge-blocked properties. */
  if (eb->migrate_svnmerge && (strcmp(name, "svnmerge-blocked") == 0))
    {
      eb->svnmerge_blocked = TRUE;
    }

  /* Normalize svn:* properties as necessary. */
  if (svn_prop_needs_translation(name))
    {
      svn_boolean_t was_normalized;
      svn_boolean_t mergeinfo_tweaked = FALSE;

      /* Normalize encoding to UTF-8, and EOL style to LF. */
      SVN_ERR(normalize_string(&value, &was_normalized, eb->source_prop_encoding,
                               pool, pool));
      /* Maybe adjust svn:mergeinfo. */
      if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0)
        {
          SVN_ERR(remove_r0_mergeinfo(&value, &mergeinfo_tweaked,
                                      pool, pool));
          if (mergeinfo_tweaked)
            eb->mergeinfo_tweaked = TRUE;
        }
      if (was_normalized)
        (*(eb->normalized_node_props_counter))++;
    }

  return eb->wrapped_editor->change_dir_prop(db->wrapped_node_baton,
                                             name, value, pool);
}
Example #11
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;
}
Example #12
0
svn_error_t *
svn_ra__get_inherited_props_walk(svn_ra_session_t *session,
                                 const char *path,
                                 svn_revnum_t revision,
                                 apr_array_header_t **inherited_props,
                                 apr_pool_t *result_pool,
                                 apr_pool_t *scratch_pool)
{
  const char *repos_root_url;
  const char *session_url;
  const char *parent_url;
  apr_pool_t *iterpool = svn_pool_create(scratch_pool);

  *inherited_props =
    apr_array_make(result_pool, 1, sizeof(svn_prop_inherited_item_t *));

  /* Walk to the root of the repository getting inherited
     props for PATH. */
  SVN_ERR(svn_ra_get_repos_root2(session, &repos_root_url, scratch_pool));
  SVN_ERR(svn_ra_get_session_url(session, &session_url, scratch_pool));
  parent_url = session_url;

  while (strcmp(repos_root_url, parent_url))
    {
      apr_hash_index_t *hi;
      apr_hash_t *parent_props;
      apr_hash_t *final_hash = apr_hash_make(result_pool);
      svn_error_t *err;

      svn_pool_clear(iterpool);
      parent_url = svn_uri_dirname(parent_url, scratch_pool);
      SVN_ERR(svn_ra_reparent(session, parent_url, iterpool));
      err = session->vtable->get_dir(session, NULL, NULL,
                                     &parent_props, "",
                                     revision, SVN_DIRENT_ALL,
                                     iterpool);

      /* If the user doesn't have read access to a parent path then
         skip, but allow them to inherit from further up. */
      if (err)
        {
          if ((err->apr_err == SVN_ERR_RA_NOT_AUTHORIZED)
              || (err->apr_err == SVN_ERR_RA_DAV_FORBIDDEN))
            {
              svn_error_clear(err);
              continue;
            }
          else
            {
              return svn_error_trace(err);
            }
        }

      for (hi = apr_hash_first(scratch_pool, parent_props);
           hi;
           hi = apr_hash_next(hi))
        {
          const char *name = apr_hash_this_key(hi);
          apr_ssize_t klen = apr_hash_this_key_len(hi);
          svn_string_t *value = apr_hash_this_val(hi);

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

      if (apr_hash_count(final_hash))
        {
          svn_prop_inherited_item_t *new_iprop =
            apr_palloc(result_pool, sizeof(*new_iprop));
          new_iprop->path_or_url = svn_uri_skip_ancestor(repos_root_url,
                                                         parent_url,
                                                         result_pool);
          new_iprop->prop_hash = final_hash;
          svn_sort__array_insert(*inherited_props, &new_iprop, 0);
        }
    }

  /* Reparent session back to original URL. */
  SVN_ERR(svn_ra_reparent(session, session_url, scratch_pool));

  svn_pool_destroy(iterpool);
  return SVN_NO_ERROR;
}