Exemplo n.º 1
0
static svn_error_t *
reconcile_errors(svn_error_t *commit_err,
                 svn_error_t *unlock_err,
                 svn_error_t *bump_err,
                 apr_pool_t *pool)
{
  svn_error_t *err;

  /* Early release (for good behavior). */
  if (! (commit_err || unlock_err || bump_err))
    return SVN_NO_ERROR;

  /* If there was a commit error, start off our error chain with
     that. */
  if (commit_err)
    {
      commit_err = svn_error_quick_wrap
        (commit_err, _("Commit failed (details follow):"));
      err = commit_err;
    }

  /* Else, create a new "general" error that will lead off the errors
     that follow. */
  else
    err = svn_error_create(SVN_ERR_BASE, NULL,
                           _("Commit succeeded, but other errors follow:"));

  /* If there was an unlock error... */
  if (unlock_err)
    {
      /* Wrap the error with some headers. */
      unlock_err = svn_error_quick_wrap
        (unlock_err, _("Error unlocking locked dirs (details follow):"));

      /* Append this error to the chain. */
      svn_error_compose(err, unlock_err);
    }

  /* If there was a bumping error... */
  if (bump_err)
    {
      /* Wrap the error with some headers. */
      bump_err = svn_error_quick_wrap
        (bump_err, _("Error bumping revisions post-commit (details follow):"));

      /* Append this error to the chain. */
      svn_error_compose(err, bump_err);
    }

  return err;
}
Exemplo n.º 2
0
/* Wrap read_rep_offsets_body(), extracting its TXN_ID from our NODEREV_ID,
   and adding an error message. */
static svn_error_t *
read_rep_offsets(svn_fs_x__representation_t **rep_p,
                 char *string,
                 const svn_fs_x__id_t *noderev_id,
                 apr_pool_t *result_pool,
                 apr_pool_t *scratch_pool)
{
  svn_error_t *err
    = svn_fs_x__parse_representation(rep_p,
                                     svn_stringbuf_create_wrap(string,
                                                               scratch_pool),
                                     result_pool,
                                     scratch_pool);
  if (err)
    {
      const svn_string_t *id_unparsed;
      const char *where;

      id_unparsed = svn_fs_x__id_unparse(noderev_id, scratch_pool);
      where = apr_psprintf(scratch_pool,
                           _("While reading representation offsets "
                             "for node-revision '%s':"),
                           id_unparsed->data);

      return svn_error_quick_wrap(err, where);
    }

  return SVN_NO_ERROR;
}
Exemplo n.º 3
0
/* Wrap svn_fs_fs__parse_representation(), extracting its TXN_ID from our
   NODEREV_ID, and adding an error message. */
static svn_error_t *
read_rep_offsets(representation_t **rep_p,
                 char *string,
                 const svn_fs_id_t *noderev_id,
                 apr_pool_t *result_pool,
                 apr_pool_t *scratch_pool)
{
  svn_error_t *err
    = svn_fs_fs__parse_representation(rep_p,
                                      svn_stringbuf_create_wrap(string,
                                                                scratch_pool),
                                      result_pool,
                                      scratch_pool);
  if (err)
    {
      const svn_string_t *id_unparsed;
      const char *where;

      id_unparsed = svn_fs_fs__id_unparse(noderev_id, scratch_pool);
      where = apr_psprintf(scratch_pool,
                           _("While reading representation offsets "
                             "for node-revision '%s':"),
                           noderev_id ? id_unparsed->data : "(null)");

      return svn_error_quick_wrap(err, where);
    }

  if ((*rep_p)->revision == SVN_INVALID_REVNUM)
    if (noderev_id)
      (*rep_p)->txn_id = *svn_fs_fs__id_txn_id(noderev_id);

  return SVN_NO_ERROR;
}
Exemplo n.º 4
0
/* Open a file somewhere in the adm area for directory PATH.
 * First, add the adm subdir as the next component of PATH, then add
 * each of the varargs (they are char *'s), then add EXTENSION if it
 * is non-null, then open the resulting file as *STREAM.
 *
 * If FLAGS indicates writing, open the file in the adm tmp area.
 * This means the file will probably need to be renamed from there,
 * either by passing the sync flag to close_adm_file() later, or with
 * an explicit call to sync_adm_file().
 */
static svn_error_t *
open_adm_file(svn_stream_t **stream,
              const char **selected_path,
              const char *path,
              const char *extension,
              svn_boolean_t for_writing,
              apr_pool_t *result_pool,
              apr_pool_t *scratch_pool,
              ...)
{
  svn_error_t *err;
  va_list ap;

  /* If we're writing, always do it to a tmp file. */
  if (for_writing)
    {
      /* Extend with tmp name. */
      va_start(ap, scratch_pool);
      path = v_extend_with_adm_name(path, extension, TRUE, result_pool, ap);
      va_end(ap);

      err = svn_stream_open_writable(stream, path, result_pool, scratch_pool);
    }
  else
    {
      /* Extend with regular adm name. */
      va_start(ap, scratch_pool);
      path = v_extend_with_adm_name(path, extension, FALSE, result_pool, ap);
      va_end(ap);

      err = svn_stream_open_readonly(stream, path, result_pool, scratch_pool);
    }

  if (selected_path)
    *selected_path = path;  /* note: built in result_pool */

  if (for_writing && err && APR_STATUS_IS_EEXIST(err->apr_err))
    {
      /* Exclusive open failed, delete and retry */
      svn_error_clear(err);
      SVN_ERR(svn_io_remove_file(path, scratch_pool));
      err = svn_stream_open_writable(stream, path, result_pool, scratch_pool);
    }

  /* Examine the error from the first and/or second attempt at opening. */
  if (for_writing && err && APR_STATUS_IS_ENOENT(err->apr_err))
    {
      /* If we receive a failure to open a file in our temporary directory,
       * it may be because our temporary directories aren't created.
       * Older SVN clients did not create these directories.
       * 'svn cleanup' will fix this problem.
       */
      err = svn_error_quick_wrap(err,
                                 _("Your .svn/tmp directory may be missing or "
                                   "corrupt; run 'svn cleanup' and try again"));
    }

  return err;
}
svn_error_t *
svn_fs_fs__open_rep_cache(svn_fs_t *fs,
                          apr_pool_t *pool)
{
  fs_fs_data_t *ffd = fs->fsap_data;
  svn_error_t *err = svn_atomic__init_once(&ffd->rep_cache_db_opened,
                                           open_rep_cache, fs, pool);
  return svn_error_quick_wrap(err, _("Couldn't open rep-cache database"));
}
Exemplo n.º 6
0
static svn_error_t *
set_node_property(void *baton,
                  const char *name,
                  const svn_string_t *value)
{
  struct node_baton *nb = baton;
  struct revision_baton *rb = nb->rb;
  struct parse_baton *pb = rb->pb;

  /* If we're skipping this revision, we're done here. */
  if (rb->skipped)
    return SVN_NO_ERROR;

  /* Adjust mergeinfo. If this fails, presumably because the mergeinfo
     property has an ill-formed value, then we must not fail to load
     the repository (at least if it's a simple load with no revision
     offset adjustments, path changes, etc.) so just warn and leave it
     as it is. */
  if (strcmp(name, SVN_PROP_MERGEINFO) == 0)
    {
      svn_string_t *new_value;
      svn_error_t *err;

      err = adjust_mergeinfo_property(rb, &new_value, value, nb->pool);
      if (err)
        {
          if (pb->validate_props)
            {
              return svn_error_quick_wrap(
                       err,
                       _("Invalid svn:mergeinfo value"));
            }
          if (pb->notify_func)
            {
              svn_repos_notify_t *notify
                = svn_repos_notify_create(svn_repos_notify_warning,
                                          pb->notify_pool);

              notify->warning = svn_repos__notify_warning_invalid_mergeinfo;
              notify->warning_str = _("Invalid svn:mergeinfo value; "
                                      "leaving unchanged");
              pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
              svn_pool_clear(pb->notify_pool);
            }
          svn_error_clear(err);
        }
      else
        {
          value = new_value;
        }
    }

  return change_node_prop(rb->txn_root, nb->path, name, value,
                          pb->validate_props, nb->pool);
}
Exemplo n.º 7
0
/* ### The way our error wrapping currently works, the error returned
 * from here will look as though it originates in this source file,
 * instead of in the caller's source file.  This can be a bit
 * misleading, until one starts debugging.  Ideally, there'd be a way
 * to wrap an error while preserving its FILE/LINE info.
 */
svn_error_t *
svn_cl__may_need_force(svn_error_t *err)
{
  if (err
      && (err->apr_err == SVN_ERR_UNVERSIONED_RESOURCE ||
          err->apr_err == SVN_ERR_CLIENT_MODIFIED))
    {
      /* Should this svn_error_compose a new error number? Probably not,
         the error hasn't changed. */
      err = svn_error_quick_wrap
        (err, _("Use --force to override this restriction (local modifications "
         "may be lost)"));
    }

  return svn_error_trace(err);
}
Exemplo n.º 8
0
static svn_error_t *initialize(void *baton, apr_pool_t *pool)
{
  int result;
  SVN_ERR(svn_ra_svn__sasl_common_init(pool));

  /* The second parameter tells SASL to look for a configuration file
     named subversion.conf. */
  result = sasl_server_init(callbacks, SVN_RA_SVN_SASL_NAME);
  if (result != SASL_OK)
    {
      svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                          sasl_errstring(result, NULL, NULL));
      return svn_error_quick_wrap(err,
                                  _("Could not initialize the SASL library"));
    }
  return SVN_NO_ERROR;
}
Exemplo n.º 9
0
svn_error_t *
svn_error__trace(const char *file, long line, svn_error_t *err)
{
#ifndef SVN_DEBUG

  /* We shouldn't even be here, but whatever. Just return the error as-is.  */
  return err;

#else

  /* Only do the work when an error occurs.  */
  if (err)
    {
      svn_error__locate(file, line);
      return svn_error_quick_wrap(err, SVN_ERR__TRACED);
    }
  return SVN_NO_ERROR;

#endif
}
Exemplo n.º 10
0
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__revert(apr_getopt_t *os,
               void *baton,
               apr_pool_t *scratch_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 = NULL;
  svn_error_t *err;

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

  /* Revert has no implicit dot-target `.', so don't you put that code here! */
  if (! targets->nelts)
    return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);

  /* Revert is especially conservative, by default it is as
     nonrecursive as possible. */
  if (opt_state->depth == svn_depth_unknown)
    opt_state->depth = svn_depth_empty;

  SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool));

  SVN_ERR(svn_cl__check_targets_are_local_paths(targets));

  err = svn_client_revert2(targets, opt_state->depth,
                           opt_state->changelists, ctx, scratch_pool);
  if (err
      && (err->apr_err == SVN_ERR_WC_INVALID_OPERATION_DEPTH)
      && (! SVN_DEPTH_IS_RECURSIVE(opt_state->depth)))
    {
      err = svn_error_quick_wrap
        (err, _("Try 'svn revert --depth infinity' instead?"));
    }

  return svn_error_trace(err);
}
Exemplo n.º 11
0
dav_error *
dav_svn__store_activity(const dav_svn_repos *repos,
                        const char *activity_id,
                        const char *txn_name)
{
  const char *final_path;
  const char *activity_contents;
  svn_error_t *err;

  /* Create activities directory if it does not yet exist. */
  err = svn_io_make_dir_recursively(repos->activities_db, repos->pool);
  if (err != NULL)
    return dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR,
                                "could not initialize activity db.",
                                repos->pool);

  final_path = activity_pathname(repos, activity_id);

  activity_contents = apr_psprintf(repos->pool, "%s\n%s\n",
                                   txn_name, activity_id);

  err = svn_io_write_atomic2(final_path,
                             activity_contents, strlen(activity_contents),
                             NULL /* copy_perms path */, TRUE, repos->pool);
  if (err)
    {
      svn_error_t *serr = svn_error_quick_wrap(err,
                                               "Can't write activity db");

      /* Try to remove the tmp file, but we already have an error... */
      return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                  "could not write files.",
                                  repos->pool);
    }

  return NULL;
}
Exemplo n.º 12
0
static svn_error_t *
close_revision(void *baton)
{
  struct revision_baton *rb = baton;
  struct parse_baton *pb = rb->pb;
  const char *conflict_msg = NULL;
  svn_revnum_t committed_rev;
  svn_error_t *err;
  const char *txn_name = NULL;
  apr_hash_t *hooks_env;

  /* If we're skipping this revision we're done here. */
  if (rb->skipped)
    return SVN_NO_ERROR;

  if (rb->rev == 0)
    {
      /* Special case: set revision 0 properties when loading into an
         'empty' filesystem. */
      svn_revnum_t youngest_rev;

      SVN_ERR(svn_fs_youngest_rev(&youngest_rev, pb->fs, rb->pool));

      if (youngest_rev == 0)
        {
          apr_hash_t *orig_props;
          apr_hash_t *new_props;
          apr_array_header_t *diff;
          int i;

          SVN_ERR(svn_fs_revision_proplist(&orig_props, pb->fs, 0, rb->pool));
          new_props = svn_prop_array_to_hash(rb->revprops, rb->pool);
          SVN_ERR(svn_prop_diffs(&diff, new_props, orig_props, rb->pool));

          for (i = 0; i < diff->nelts; i++)
          {
              const svn_prop_t *prop = &APR_ARRAY_IDX(diff, i, svn_prop_t);

              SVN_ERR(change_rev_prop(pb->repos, 0, prop->name, prop->value,
                                      pb->validate_props, rb->pool));
          }
        }

      return SVN_NO_ERROR;
    }

  /* If the dumpstream doesn't have an 'svn:date' property and we
     aren't ignoring the dates in the dumpstream altogether, remove
     any 'svn:date' revision property that was set by FS layer when
     the TXN was created.  */
  if (! (pb->ignore_dates || rb->datestamp))
    {
      svn_prop_t *prop = &APR_ARRAY_PUSH(rb->revprops, svn_prop_t);
      prop->name = SVN_PROP_REVISION_DATE;
      prop->value = NULL;
    }

  /* Apply revision property changes. */
  if (rb->pb->validate_props)
    SVN_ERR(svn_repos_fs_change_txn_props(rb->txn, rb->revprops, rb->pool));
  else
    SVN_ERR(svn_fs_change_txn_props(rb->txn, rb->revprops, rb->pool));

  /* Get the txn name and hooks environment if they will be needed. */
  if (pb->use_pre_commit_hook || pb->use_post_commit_hook)
    {
      SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, pb->repos->hooks_env_path,
                                         rb->pool, rb->pool));

      err = svn_fs_txn_name(&txn_name, rb->txn, rb->pool);
      if (err)
        {
          svn_error_clear(svn_fs_abort_txn(rb->txn, rb->pool));
          return svn_error_trace(err);
        }
    }

  /* Run the pre-commit hook, if so commanded. */
  if (pb->use_pre_commit_hook)
    {
      err = svn_repos__hooks_pre_commit(pb->repos, hooks_env,
                                        txn_name, rb->pool);
      if (err)
        {
          svn_error_clear(svn_fs_abort_txn(rb->txn, rb->pool));
          return svn_error_trace(err);
        }
    }

  /* Commit. */
  err = svn_fs_commit_txn(&conflict_msg, &committed_rev, rb->txn, rb->pool);
  if (SVN_IS_VALID_REVNUM(committed_rev))
    {
      if (err)
        {
          /* ### Log any error, but better yet is to rev
             ### close_revision()'s API to allow both committed_rev and err
             ### to be returned, see #3768. */
          svn_error_clear(err);
        }
    }
  else
    {
      svn_error_clear(svn_fs_abort_txn(rb->txn, rb->pool));
      if (conflict_msg)
        return svn_error_quick_wrap(err, conflict_msg);
      else
        return svn_error_trace(err);
    }

  /* Run post-commit hook, if so commanded.  */
  if (pb->use_post_commit_hook)
    {
      if ((err = svn_repos__hooks_post_commit(pb->repos, hooks_env,
                                              committed_rev, txn_name,
                                              rb->pool)))
        return svn_error_create
          (SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err,
           _("Commit succeeded, but post-commit hook failed"));
    }

  /* After a successful commit, must record the dump-rev -> in-repos-rev
     mapping, so that copyfrom instructions in the dump file can look up the
     correct repository revision to copy from. */
  set_revision_mapping(pb->rev_map, rb->rev, committed_rev);

  /* If the incoming dump stream has non-contiguous revisions (e.g. from
     using svndumpfilter --drop-empty-revs without --renumber-revs) then
     we must account for the missing gaps in PB->REV_MAP.  Otherwise we
     might not be able to map all mergeinfo source revisions to the correct
     revisions in the target repos. */
  if ((pb->last_rev_mapped != SVN_INVALID_REVNUM)
      && (rb->rev != pb->last_rev_mapped + 1))
    {
      svn_revnum_t i;

      for (i = pb->last_rev_mapped + 1; i < rb->rev; i++)
        {
          set_revision_mapping(pb->rev_map, i, pb->last_rev_mapped);
        }
    }

  /* Update our "last revision mapped". */
  pb->last_rev_mapped = rb->rev;

  /* Deltify the predecessors of paths changed in this revision. */
  SVN_ERR(svn_fs_deltify_revision(pb->fs, committed_rev, rb->pool));

  if (pb->notify_func)
    {
      /* ### TODO: Use proper scratch pool instead of pb->notify_pool */
      svn_repos_notify_t *notify = svn_repos_notify_create(
                                        svn_repos_notify_load_txn_committed,
                                        pb->notify_pool);

      notify->new_revision = committed_rev;
      notify->old_revision = ((committed_rev == rb->rev)
                                    ? SVN_INVALID_REVNUM
                                    : rb->rev);
      pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
      svn_pool_clear(pb->notify_pool);
    }

  return SVN_NO_ERROR;
}
Exemplo n.º 13
0
svn_error_t *
svn_cl__get_log_message(const char **log_msg,
                        const char **tmp_file,
                        const apr_array_header_t *commit_items,
                        void *baton,
                        apr_pool_t *pool)
{
  svn_stringbuf_t *default_msg = NULL;
  struct log_msg_baton *lmb = baton;
  svn_stringbuf_t *message = NULL;
  svn_config_t *cfg;
  const char *mfc_after, *sponsored_by;

  cfg = lmb->config ? svn_hash_gets(lmb->config, SVN_CONFIG_CATEGORY_CONFIG) : NULL;

  /* Set default message.  */
  default_msg = svn_stringbuf_create(APR_EOL_STR, pool);
  svn_stringbuf_appendcstr(default_msg, APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "PR:\t\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Submitted by:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Reported by:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Reviewed by:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Approved by:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Obtained from:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "MFC after:\t");
  svn_config_get(cfg, &mfc_after, SVN_CONFIG_SECTION_MISCELLANY, "freebsd-mfc-after", NULL);
  if (mfc_after != NULL)
	  svn_stringbuf_appendcstr(default_msg, mfc_after);
  svn_stringbuf_appendcstr(default_msg, APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "MFH:\t\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Relnotes:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Security:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Sponsored by:\t");
  svn_config_get(cfg, &sponsored_by, SVN_CONFIG_SECTION_MISCELLANY, "freebsd-sponsored-by",
#ifdef HAS_ORGANIZATION_NAME
  	ORGANIZATION_NAME);
#else
	NULL);
#endif
  if (sponsored_by != NULL)
	  svn_stringbuf_appendcstr(default_msg, sponsored_by);
  svn_stringbuf_appendcstr(default_msg, APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "Differential Revision:\t" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, EDITOR_EOF_PREFIX);
  svn_stringbuf_appendcstr(default_msg, APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Description of fields to fill in above:                     76 columns --|" APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> PR:                       If and which Problem Report is related." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Submitted by:             If someone else sent in the change." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Reported by:              If someone else reported the issue." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Reviewed by:              If someone else reviewed your modification." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Approved by:              If you needed approval for this commit." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Obtained from:            If the change is from a third party." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> MFC after:                N [day[s]|week[s]|month[s]].  Request a reminder email." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> MFH:                      Ports tree branch name.  Request approval for merge." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Relnotes:                 Set to 'yes' for mention in release notes." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Security:                 Vulnerability reference (one per line) or description." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Sponsored by:             If the change was sponsored by an organization." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Differential Revision:    https://reviews.freebsd.org/D### (*full* phabric URL needed)." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, "> Empty fields above will be automatically removed." APR_EOL_STR);
  svn_stringbuf_appendcstr(default_msg, APR_EOL_STR);

  *tmp_file = NULL;
  if (lmb->message)
    {
      svn_string_t *log_msg_str = svn_string_create(lmb->message, pool);

      SVN_ERR_W(svn_subst_translate_string2(&log_msg_str, NULL, NULL,
                                            log_msg_str, lmb->message_encoding,
                                            FALSE, pool, pool),
                _("Error normalizing log message to internal format"));

      /* Strip off the EOF marker text and the junk that follows it. */
      truncate_buffer_at_prefix(&(log_msg_str->len), (char *)log_msg_str->data,
                                EDITOR_EOF_PREFIX);

      cleanmsg(&(log_msg_str->len), (char*)log_msg_str->data);

      *log_msg = log_msg_str->data;
      return SVN_NO_ERROR;
    }

  if (! commit_items->nelts)
    {
      *log_msg = "";
      return SVN_NO_ERROR;
    }

  while (! message)
    {
      /* We still don't have a valid commit message.  Use $EDITOR to
         get one.  Note that svn_cl__edit_string_externally will still
         return a UTF-8'ized log message. */
      int i;
      svn_stringbuf_t *tmp_message = svn_stringbuf_dup(default_msg, pool);
      svn_error_t *err = SVN_NO_ERROR;
      svn_string_t *msg_string = svn_string_create_empty(pool);

      for (i = 0; i < commit_items->nelts; i++)
        {
          svn_client_commit_item3_t *item
            = APR_ARRAY_IDX(commit_items, i, svn_client_commit_item3_t *);
          const char *path = item->path;
          char text_mod = '_', prop_mod = ' ', unlock = ' ';

          if (! path)
            path = item->url;
          else if (lmb->base_dir)
            path = svn_dirent_is_child(lmb->base_dir, path, pool);

          /* If still no path, then just use current directory. */
          if (! path || !*path)
            path = ".";

          if ((item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
              && (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
            text_mod = 'R';
          else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)
            text_mod = 'A';
          else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
            text_mod = 'D';
          else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_TEXT_MODS)
            text_mod = 'M';

          if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_PROP_MODS)
            prop_mod = 'M';

          if (! lmb->keep_locks
              && item->state_flags & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN)
            unlock = 'U';

          svn_stringbuf_appendbyte(tmp_message, text_mod);
          svn_stringbuf_appendbyte(tmp_message, prop_mod);
          svn_stringbuf_appendbyte(tmp_message, unlock);
          if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_IS_COPY)
            /* History included via copy/move. */
            svn_stringbuf_appendcstr(tmp_message, "+ ");
          else
            svn_stringbuf_appendcstr(tmp_message, "  ");
          svn_stringbuf_appendcstr(tmp_message, path);
          svn_stringbuf_appendcstr(tmp_message, APR_EOL_STR);
        }

      msg_string->data = tmp_message->data;
      msg_string->len = tmp_message->len;

      /* Use the external edit to get a log message. */
      if (! lmb->non_interactive)
        {
          err = svn_cmdline__edit_string_externally(&msg_string, &lmb->tmpfile_left,
                                                    lmb->editor_cmd,
                                                    lmb->base_dir ? lmb->base_dir : "",
                                                    msg_string, "svn-commit",
                                                    lmb->config, TRUE,
                                                    lmb->message_encoding,
                                                    pool);
        }
      else /* non_interactive flag says we can't pop up an editor, so error */
        {
          return svn_error_create
            (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
             _("Cannot invoke editor to get log message "
               "when non-interactive"));
        }

      /* Dup the tmpfile path into its baton's pool. */
      *tmp_file = lmb->tmpfile_left = apr_pstrdup(lmb->pool,
                                                  lmb->tmpfile_left);

      /* If the edit returned an error, handle it. */
      if (err)
        {
          if (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR)
            err = svn_error_quick_wrap
              (err, _("Could not use external editor to fetch log message; "
                      "consider setting the $SVN_EDITOR environment variable "
                      "or using the --message (-m) or --file (-F) options"));
          return svn_error_trace(err);
        }

      if (msg_string)
        message = svn_stringbuf_create_from_string(msg_string, pool);

      /* Strip off the EOF marker text and the junk that follows it. */
      if (message)
        truncate_buffer_at_prefix(&message->len, message->data,
                                  EDITOR_EOF_PREFIX);
      /*
       * Since we're adding freebsd-specific tokens to the log message,
       * clean out any leftovers to avoid accidently sending them to other
       * projects that won't be expecting them.
       */
      if (message)
	cleanmsg(&message->len, message->data);

      if (message)
        {
          /* We did get message, now check if it is anything more than just
             white space as we will consider white space only as empty */
          apr_size_t len;

          for (len = 0; len < message->len; len++)
            {
              /* FIXME: should really use an UTF-8 whitespace test
                 rather than svn_ctype_isspace, which is ASCII only */
              if (! svn_ctype_isspace(message->data[len]))
                break;
            }
          if (len == message->len)
            message = NULL;
        }

      if (! message)
        {
          const char *reply;
          SVN_ERR(svn_cmdline_prompt_user2
                  (&reply,
                   _("\nLog message unchanged or not specified\n"
                     "(a)bort, (c)ontinue, (e)dit:\n"), NULL, pool));
          if (reply)
            {
              int letter = apr_tolower(reply[0]);

              /* If the user chooses to abort, we cleanup the
                 temporary file and exit the loop with a NULL
                 message. */
              if ('a' == letter)
                {
                  SVN_ERR(svn_io_remove_file2(lmb->tmpfile_left, FALSE, pool));
                  *tmp_file = lmb->tmpfile_left = NULL;
                  break;
                }

              /* If the user chooses to continue, we make an empty
                 message, which will cause us to exit the loop.  We
                 also cleanup the temporary file. */
              if ('c' == letter)
                {
                  SVN_ERR(svn_io_remove_file2(lmb->tmpfile_left, FALSE, pool));
                  *tmp_file = lmb->tmpfile_left = NULL;
                  message = svn_stringbuf_create_empty(pool);
                }

              /* If the user chooses anything else, the loop will
                 continue on the NULL message. */
            }
        }
    }

  *log_msg = message ? message->data : NULL;
  return SVN_NO_ERROR;
}
Exemplo n.º 14
0
svn_error_t *
svn_cl__check_svn_prop_name(const char *propname,
                            svn_boolean_t revprop,
                            svn_cl__prop_use_t prop_use,
                            apr_pool_t *scratch_pool)
{
  static const char *const nodeprops[] =
    {
      SVN_PROP_NODE_ALL_PROPS
    };
  static const apr_size_t nodeprops_len = sizeof(nodeprops)/sizeof(*nodeprops);

  static const char *const revprops[] =
    {
      SVN_PROP_REVISION_ALL_PROPS
    };
  static const apr_size_t revprops_len = sizeof(revprops)/sizeof(*revprops);

  const char *const *const proplist = (revprop ? revprops : nodeprops);
  const apr_size_t numprops = (revprop ? revprops_len : nodeprops_len);

  svn_cl__simcheck_t **propkeys;
  svn_cl__simcheck_t *propbuf;
  apr_size_t i;

  svn_string_t propstring;
  svn_string_t prefix;
  svn_membuf_t buffer;

  propstring.data = propname;
  propstring.len = strlen(propname);
  prefix.data = SVN_PROP_PREFIX;
  prefix.len = strlen(SVN_PROP_PREFIX);

  svn_membuf__create(&buffer, 0, scratch_pool);

  /* First, check if the name is even close to being in the svn: namespace.
     It must contain a colon in the right place, and we only allow
     one-char typos or a single transposition. */
  if (propstring.len < prefix.len
      || propstring.data[prefix.len - 1] != prefix.data[prefix.len - 1])
    return SVN_NO_ERROR;        /* Wrong prefix, ignore */
  else
    {
      apr_size_t lcs;
      const apr_size_t name_len = propstring.len;
      propstring.len = prefix.len; /* Only check up to the prefix length */
      svn_string__similarity(&propstring, &prefix, &buffer, &lcs);
      propstring.len = name_len; /* Restore the original propname length */
      if (lcs < prefix.len - 1)
        return SVN_NO_ERROR;    /* Wrong prefix, ignore */

      /* If the prefix is slightly different, the rest must be
         identical in order to trigger the error. */
      if (lcs == prefix.len - 1)
        {
          for (i = 0; i < numprops; ++i)
            {
              if (0 == strcmp(proplist[i] + prefix.len, propname + prefix.len))
                return svn_error_quick_wrap(svn_error_createf(
                  SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
                  _("'%s' is not a valid %s property name;"
                    " did you mean '%s'?"),
                  propname, SVN_PROP_PREFIX, proplist[i]),
                  force_prop_option_message(prop_use, propname, scratch_pool));
            }
          return SVN_NO_ERROR;
        }
    }

  /* Now find the closest match from amongst the set of reserved
     node or revision property names. Skip the prefix while matching,
     we already know that it's the same and looking at it would only
     skew the results. */
  propkeys = apr_palloc(scratch_pool,
                        numprops * sizeof(svn_cl__simcheck_t*));
  propbuf = apr_palloc(scratch_pool,
                       numprops * sizeof(svn_cl__simcheck_t));
  propstring.data += prefix.len;
  propstring.len -= prefix.len;
  for (i = 0; i < numprops; ++i)
    {
      propkeys[i] = &propbuf[i];
      propbuf[i].token.data = proplist[i] + prefix.len;
      propbuf[i].token.len = strlen(propbuf[i].token.data);
      propbuf[i].data = proplist[i];
    }

  switch (svn_cl__similarity_check(
              propstring.data, propkeys, numprops, scratch_pool))
    {
    case 0:
      return SVN_NO_ERROR;      /* We found an exact match. */

    case 1:
      /* The best alternative isn't good enough */
      return svn_error_create(
        SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
        wrong_prop_error_message(prop_use, propname, scratch_pool));

    case 2:
      /* There is only one good candidate */
      return svn_error_quick_wrap(svn_error_createf(
        SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
        _("'%s' is not a valid %s property name; did you mean '%s'?"),
        propname, SVN_PROP_PREFIX,
        (const char *)propkeys[0]->data),
        force_prop_option_message(prop_use, propname, scratch_pool));

    case 3:
      /* Suggest a list of the most likely candidates */
      return svn_error_quick_wrap(svn_error_createf(
        SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
        _("'%s' is not a valid %s property name; "
          "did you mean '%s' or '%s'?"),
        propname, SVN_PROP_PREFIX,
        (const char *)propkeys[0]->data, (const char *)propkeys[1]->data),
        force_prop_option_message(prop_use, propname, scratch_pool));

    default:
      /* Never suggest more than three candidates */
      return svn_error_quick_wrap(svn_error_createf(
        SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
        _("'%s' is not a valid %s property name; "
          "did you mean '%s', '%s' or '%s'?"),
        propname, SVN_PROP_PREFIX,
        (const char *)propkeys[0]->data,
        (const char *)propkeys[1]->data, (const char *)propkeys[2]->data),
        force_prop_option_message(prop_use, propname, scratch_pool));
    }
}
Exemplo n.º 15
0
svn_error_t *
svn_wc__db_pdh_create_wcroot(svn_wc__db_wcroot_t **wcroot,
                             const char *wcroot_abspath,
                             svn_sqlite__db_t *sdb,
                             apr_int64_t wc_id,
                             int format,
                             svn_boolean_t verify_format,
                             apr_pool_t *result_pool,
                             apr_pool_t *scratch_pool)
{
  if (sdb && format == FORMAT_FROM_SDB)
    SVN_ERR(svn_sqlite__read_schema_version(&format, sdb, scratch_pool));

  /* If we construct a wcroot, then we better have a format.  */
  SVN_ERR_ASSERT(format >= 1);

  /* If this working copy is PRE-1.0, then simply bail out.  */
  if (format < 4)
    {
      return svn_error_createf(
        SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
        _("Working copy format of '%s' is too old (%d); "
          "please check out your working copy again"),
        svn_dirent_local_style(wcroot_abspath, scratch_pool), format);
    }

  /* If this working copy is from a future version, then bail out.  */
  if (format > SVN_WC__VERSION)
    {
      return svn_error_createf(
        SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
        _("This client is too old to work with the working copy at\n"
          "'%s' (format %d).\n"
          "You need to get a newer Subversion client. For more details, see\n"
          "  http://subversion.apache.org/faq.html#working-copy-format-change\n"
          ),
        svn_dirent_local_style(wcroot_abspath, scratch_pool),
        format);
    }

  /* Verify that no work items exists. If they do, then our integrity is
     suspect and, thus, we cannot upgrade this database.  */
  if (format >= SVN_WC__HAS_WORK_QUEUE &&
      format < SVN_WC__VERSION && verify_format)
    {
      svn_error_t *err = svn_wc__db_verify_no_work(sdb);
      if (err)
        {
          /* Special message for attempts to upgrade a 1.7-dev wc with
             outstanding workqueue items. */
          if (err->apr_err == SVN_ERR_WC_CLEANUP_REQUIRED
              && format < SVN_WC__VERSION && verify_format)
            err = svn_error_quick_wrap(err, _("Cleanup with an older 1.7 "
                                              "client before upgrading with "
                                              "this client"));
          return svn_error_trace(err);
        }
    }

  /* Auto-upgrade the SDB if possible.  */
  if (format < SVN_WC__VERSION && verify_format)
    {
      return svn_error_createf(SVN_ERR_WC_UPGRADE_REQUIRED, NULL,
                               _("The working copy at '%s'\nis too old "
                                 "(format %d) to work with client version "
                                 "'%s' (expects format %d). You need to "
                                 "upgrade the working copy first.\n"),
                               svn_dirent_local_style(wcroot_abspath,
                                                      scratch_pool),
                               format, SVN_VERSION, SVN_WC__VERSION);
    }

  *wcroot = apr_palloc(result_pool, sizeof(**wcroot));

  (*wcroot)->abspath = wcroot_abspath;
  (*wcroot)->sdb = sdb;
  (*wcroot)->wc_id = wc_id;
  (*wcroot)->format = format;
  /* 8 concurrent locks is probably more than a typical wc_ng based svn client
     uses. */
  (*wcroot)->owned_locks = apr_array_make(result_pool, 8,
                                          sizeof(svn_wc__db_wclock_t));
  (*wcroot)->access_cache = apr_hash_make(result_pool);

  /* SDB will be NULL for pre-NG working copies. We only need to run a
     cleanup when the SDB is present.  */
  if (sdb != NULL)
    apr_pool_cleanup_register(result_pool, *wcroot, close_wcroot,
                              apr_pool_cleanup_null);
  return SVN_NO_ERROR;
}
Exemplo n.º 16
0
svn_error_t *
svn_cl__get_log_message(const char **log_msg,
                        const char **tmp_file,
                        const apr_array_header_t *commit_items,
                        void *baton,
                        apr_pool_t *pool)
{
  svn_stringbuf_t *default_msg = NULL;
  struct log_msg_baton *lmb = baton;
  svn_stringbuf_t *message = NULL;

  /* Set default message.  */
  default_msg = svn_stringbuf_create(APR_EOL_STR, pool);
  svn_stringbuf_appendcstr(default_msg, EDITOR_EOF_PREFIX);
  svn_stringbuf_appendcstr(default_msg, APR_EOL_STR APR_EOL_STR);

  *tmp_file = NULL;
  if (lmb->message)
    {
      svn_stringbuf_t *log_msg_buf = svn_stringbuf_create(lmb->message, pool);
      svn_string_t *log_msg_str = apr_pcalloc(pool, sizeof(*log_msg_str));

      /* Trim incoming messages of the EOF marker text and the junk
         that follows it.  */
      truncate_buffer_at_prefix(&(log_msg_buf->len), log_msg_buf->data,
                                EDITOR_EOF_PREFIX);

      /* Make a string from a stringbuf, sharing the data allocation. */
      log_msg_str->data = log_msg_buf->data;
      log_msg_str->len = log_msg_buf->len;
      SVN_ERR_W(svn_subst_translate_string2(&log_msg_str, FALSE, FALSE,
                                            log_msg_str, lmb->message_encoding,
                                            FALSE, pool, pool),
                _("Error normalizing log message to internal format"));

      *log_msg = log_msg_str->data;
      return SVN_NO_ERROR;
    }

  if (! commit_items->nelts)
    {
      *log_msg = "";
      return SVN_NO_ERROR;
    }

  while (! message)
    {
      /* We still don't have a valid commit message.  Use $EDITOR to
         get one.  Note that svn_cl__edit_externally will still return
         a UTF-8'ized log message. */
      int i;
      svn_stringbuf_t *tmp_message = svn_stringbuf_dup(default_msg, pool);
      svn_error_t *err = SVN_NO_ERROR;
      svn_string_t *msg_string = svn_string_create("", pool);

      for (i = 0; i < commit_items->nelts; i++)
        {
          svn_client_commit_item3_t *item
            = APR_ARRAY_IDX(commit_items, i, svn_client_commit_item3_t *);
          const char *path = item->path;
          char text_mod = '_', prop_mod = ' ', unlock = ' ';

          if (! path)
            path = item->url;
          else if (! *path)
            path = ".";

          if (! svn_path_is_url(path) && lmb->base_dir)
            path = svn_dirent_is_child(lmb->base_dir, path, pool);

          /* If still no path, then just use current directory. */
          if (! path)
            path = ".";

          if ((item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
              && (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD))
            text_mod = 'R';
          else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)
            text_mod = 'A';
          else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
            text_mod = 'D';
          else if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_TEXT_MODS)
            text_mod = 'M';

          if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_PROP_MODS)
            prop_mod = 'M';

          if (! lmb->keep_locks
              && item->state_flags & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN)
            unlock = 'U';

          svn_stringbuf_appendbyte(tmp_message, text_mod);
          svn_stringbuf_appendbyte(tmp_message, prop_mod);
          svn_stringbuf_appendbyte(tmp_message, unlock);
          if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_IS_COPY)
            /* History included via copy/move. */
            svn_stringbuf_appendcstr(tmp_message, "+ ");
          else
            svn_stringbuf_appendcstr(tmp_message, "  ");
          svn_stringbuf_appendcstr(tmp_message, path);
          svn_stringbuf_appendcstr(tmp_message, APR_EOL_STR);
        }

      msg_string->data = tmp_message->data;
      msg_string->len = tmp_message->len;

      /* Use the external edit to get a log message. */
      if (! lmb->non_interactive)
        {
          err = svn_cl__edit_string_externally(&msg_string, &lmb->tmpfile_left,
                                               lmb->editor_cmd, lmb->base_dir,
                                               msg_string, "svn-commit",
                                               lmb->config, TRUE,
                                               lmb->message_encoding,
                                               pool);
        }
      else /* non_interactive flag says we can't pop up an editor, so error */
        {
          return svn_error_create
            (SVN_ERR_CL_INSUFFICIENT_ARGS, NULL,
             _("Cannot invoke editor to get log message "
               "when non-interactive"));
        }

      /* Dup the tmpfile path into its baton's pool. */
      *tmp_file = lmb->tmpfile_left = apr_pstrdup(lmb->pool,
                                                  lmb->tmpfile_left);

      /* If the edit returned an error, handle it. */
      if (err)
        {
          if (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR)
            err = svn_error_quick_wrap
              (err, _("Could not use external editor to fetch log message; "
                      "consider setting the $SVN_EDITOR environment variable "
                      "or using the --message (-m) or --file (-F) options"));
          return svn_error_trace(err);
        }

      if (msg_string)
        message = svn_stringbuf_create_from_string(msg_string, pool);

      /* Strip the prefix from the buffer. */
      if (message)
        truncate_buffer_at_prefix(&message->len, message->data,
                                  EDITOR_EOF_PREFIX);

      if (message)
        {
          /* We did get message, now check if it is anything more than just
             white space as we will consider white space only as empty */
          apr_size_t len;

          for (len = 0; len < message->len; len++)
            {
              /* FIXME: should really use an UTF-8 whitespace test
                 rather than svn_ctype_isspace, which is ASCII only */
              if (! svn_ctype_isspace(message->data[len]))
                break;
            }
          if (len == message->len)
            message = NULL;
        }

      if (! message)
        {
          const char *reply;
          SVN_ERR(svn_cmdline_prompt_user2
                  (&reply,
                   _("\nLog message unchanged or not specified\n"
                     "(a)bort, (c)ontinue, (e)dit:\n"), NULL, pool));
          if (reply)
            {
              int letter = apr_tolower(reply[0]);

              /* If the user chooses to abort, we cleanup the
                 temporary file and exit the loop with a NULL
                 message. */
              if ('a' == letter)
                {
                  SVN_ERR(svn_io_remove_file2(lmb->tmpfile_left, FALSE, pool));
                  *tmp_file = lmb->tmpfile_left = NULL;
                  break;
                }

              /* If the user chooses to continue, we make an empty
                 message, which will cause us to exit the loop.  We
                 also cleanup the temporary file. */
              if ('c' == letter)
                {
                  SVN_ERR(svn_io_remove_file2(lmb->tmpfile_left, FALSE, pool));
                  *tmp_file = lmb->tmpfile_left = NULL;
                  message = svn_stringbuf_create("", pool);
                }

              /* If the user chooses anything else, the loop will
                 continue on the NULL message. */
            }
        }
    }

  *log_msg = message ? message->data : NULL;
  return SVN_NO_ERROR;
}
Exemplo n.º 17
0
svn_error_t *
svn_cl__edit_string_externally(svn_string_t **edited_contents /* UTF-8! */,
                               const char **tmpfile_left /* UTF-8! */,
                               const char *editor_cmd,
                               const char *base_dir /* UTF-8! */,
                               const svn_string_t *contents /* UTF-8! */,
                               const char *filename,
                               apr_hash_t *config,
                               svn_boolean_t as_text,
                               const char *encoding,
                               apr_pool_t *pool)
{
  const char *editor;
  const char *cmd;
  apr_file_t *tmp_file;
  const char *tmpfile_name;
  const char *tmpfile_native;
  const char *tmpfile_apr, *base_dir_apr;
  svn_string_t *translated_contents;
  apr_status_t apr_err, apr_err2;
  apr_size_t written;
  apr_finfo_t finfo_before, finfo_after;
  svn_error_t *err = SVN_NO_ERROR, *err2;
  char *old_cwd;
  int sys_err;
  svn_boolean_t remove_file = TRUE;

  SVN_ERR(find_editor_binary(&editor, editor_cmd, config));

  /* Convert file contents from UTF-8/LF if desired. */
  if (as_text)
    {
      const char *translated;
      SVN_ERR(svn_subst_translate_cstring2(contents->data, &translated,
                                           APR_EOL_STR, FALSE,
                                           NULL, FALSE, pool));
      translated_contents = svn_string_create("", pool);
      if (encoding)
        SVN_ERR(svn_utf_cstring_from_utf8_ex2(&translated_contents->data,
                                              translated, encoding, pool));
      else
        SVN_ERR(svn_utf_cstring_from_utf8(&translated_contents->data,
                                          translated, pool));
      translated_contents->len = strlen(translated_contents->data);
    }
  else
    translated_contents = svn_string_dup(contents, pool);

  /* Move to BASE_DIR to avoid getting characters that need quoting
     into tmpfile_name */
  apr_err = apr_filepath_get(&old_cwd, APR_FILEPATH_NATIVE, pool);
  if (apr_err)
    return svn_error_wrap_apr(apr_err, _("Can't get working directory"));

  /* APR doesn't like "" directories */
  if (base_dir[0] == '\0')
    base_dir_apr = ".";
  else
    SVN_ERR(svn_path_cstring_from_utf8(&base_dir_apr, base_dir, pool));
  apr_err = apr_filepath_set(base_dir_apr, pool);
  if (apr_err)
    {
      return svn_error_wrap_apr
        (apr_err, _("Can't change working directory to '%s'"), base_dir);
    }

  /*** From here on, any problems that occur require us to cd back!! ***/

  /* Ask the working copy for a temporary file named FILENAME-something. */
  err = svn_io_open_uniquely_named(&tmp_file, &tmpfile_name,
                                   "" /* dirpath */,
                                   filename,
                                   ".tmp",
                                   svn_io_file_del_none, pool, pool);

  if (err && (APR_STATUS_IS_EACCES(err->apr_err) || err->apr_err == EROFS))
    {
      const char *temp_dir_apr;

      svn_error_clear(err);

      SVN_ERR(svn_io_temp_dir(&base_dir, pool));

      SVN_ERR(svn_path_cstring_from_utf8(&temp_dir_apr, base_dir, pool));
      apr_err = apr_filepath_set(temp_dir_apr, pool);
      if (apr_err)
        {
          return svn_error_wrap_apr
            (apr_err, _("Can't change working directory to '%s'"), base_dir);
        }

      err = svn_io_open_uniquely_named(&tmp_file, &tmpfile_name,
                                       "" /* dirpath */,
                                       filename,
                                       ".tmp",
                                       svn_io_file_del_none, pool, pool);
    }

  if (err)
    goto cleanup2;

  /*** From here on, any problems that occur require us to cleanup
       the file we just created!! ***/

  /* Dump initial CONTENTS to TMP_FILE. */
  apr_err = apr_file_write_full(tmp_file, translated_contents->data,
                                translated_contents->len, &written);

  apr_err2 = apr_file_close(tmp_file);
  if (! apr_err)
    apr_err = apr_err2;

  /* Make sure the whole CONTENTS were written, else return an error. */
  if (apr_err)
    {
      err = svn_error_wrap_apr(apr_err, _("Can't write to '%s'"),
                               tmpfile_name);
      goto cleanup;
    }

  err = svn_path_cstring_from_utf8(&tmpfile_apr, tmpfile_name, pool);
  if (err)
    goto cleanup;

  /* Get information about the temporary file before the user has
     been allowed to edit its contents. */
  apr_err = apr_stat(&finfo_before, tmpfile_apr,
                     APR_FINFO_MTIME, pool);
  if (apr_err)
    {
      err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name);
      goto cleanup;
    }

  /* Backdate the file a little bit in case the editor is very fast
     and doesn't change the size.  (Use two seconds, since some
     filesystems have coarse granularity.)  It's OK if this call
     fails, so we don't check its return value.*/
  apr_file_mtime_set(tmpfile_apr, finfo_before.mtime - 2000, pool);

  /* Stat it again to get the mtime we actually set. */
  apr_err = apr_stat(&finfo_before, tmpfile_apr,
                     APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
  if (apr_err)
    {
      err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name);
      goto cleanup;
    }

  /* Prepare the editor command line.  */
  err = svn_utf_cstring_from_utf8(&tmpfile_native, tmpfile_name, pool);
  if (err)
    goto cleanup;
  cmd = apr_psprintf(pool, "%s %s", editor, tmpfile_native);

  /* If the caller wants us to leave the file around, return the path
     of the file we'll use, and make a note not to destroy it.  */
  if (tmpfile_left)
    {
      *tmpfile_left = svn_dirent_join(base_dir, tmpfile_name, pool);
      remove_file = FALSE;
    }

  /* Now, run the editor command line.  */
  sys_err = system(cmd);
  if (sys_err != 0)
    {
      /* Extracting any meaning from sys_err is platform specific, so just
         use the raw value. */
      err =  svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
                               _("system('%s') returned %d"), cmd, sys_err);
      goto cleanup;
    }

  /* Get information about the temporary file after the assumed editing. */
  apr_err = apr_stat(&finfo_after, tmpfile_apr,
                     APR_FINFO_MTIME | APR_FINFO_SIZE, pool);
  if (apr_err)
    {
      err = svn_error_wrap_apr(apr_err, _("Can't stat '%s'"), tmpfile_name);
      goto cleanup;
    }

  /* If the file looks changed... */
  if ((finfo_before.mtime != finfo_after.mtime) ||
      (finfo_before.size != finfo_after.size))
    {
      svn_stringbuf_t *edited_contents_s;
      err = svn_stringbuf_from_file2(&edited_contents_s, tmpfile_name, pool);
      if (err)
        goto cleanup;

      *edited_contents = svn_stringbuf__morph_into_string(edited_contents_s);

      /* Translate back to UTF8/LF if desired. */
      if (as_text)
        {
          err = svn_subst_translate_string2(edited_contents, FALSE, FALSE,
                                            *edited_contents, encoding, FALSE,
                                            pool, pool);
          if (err)
            {
              err = svn_error_quick_wrap
                (err,
                 _("Error normalizing edited contents to internal format"));
              goto cleanup;
            }
        }
    }
  else
    {
      /* No edits seem to have been made */
      *edited_contents = NULL;
    }

 cleanup:
  if (remove_file)
    {
      /* Remove the file from disk.  */
      err2 = svn_io_remove_file2(tmpfile_name, FALSE, pool);

      /* Only report remove error if there was no previous error. */
      if (! err && err2)
        err = err2;
      else
        svn_error_clear(err2);
    }

 cleanup2:
  /* If we against all probability can't cd back, all further relative
     file references would be screwed up, so we have to abort. */
  apr_err = apr_filepath_set(old_cwd, pool);
  if (apr_err)
    {
      svn_handle_error2(svn_error_wrap_apr
                        (apr_err, _("Can't restore working directory")),
                        stderr, TRUE /* fatal */, "svn: ");
    }

  return svn_error_trace(err);
}
Exemplo n.º 18
0
static svn_error_t *wrap_spotify_error(sp_error error) {
  return svn_error_quick_wrap(NULL, sp_error_message(error));
}
Exemplo n.º 19
0
Arquivo: fs.c Projeto: Alkzndr/freebsd
static svn_error_t *
base_hotcopy(svn_fs_t *src_fs,
             svn_fs_t *dst_fs,
             const char *src_path,
             const char *dest_path,
             svn_boolean_t clean_logs,
             svn_boolean_t incremental,
             svn_cancel_func_t cancel_func,
             void *cancel_baton,
             apr_pool_t *pool)
{
  svn_error_t *err;
  u_int32_t pagesize;
  svn_boolean_t log_autoremove = FALSE;
  int format;

  if (incremental)
    return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                             _("BDB repositories do not support incremental "
                               "hotcopy"));

  /* Check the FS format number to be certain that we know how to
     hotcopy this FS.  Pre-1.2 filesystems did not have a format file (you
     could say they were format "0"), so we will error here.  This is not
     optimal, but since this has been the case since 1.2.0, and no one has
     complained, it apparently isn't much of a concern.  (We did not check
     the 'format' file in 1.2.x, but we did blindly try to copy 'locks',
     which would have errored just the same.)  */
  SVN_ERR(svn_io_read_version_file(
          &format, svn_dirent_join(src_path, FORMAT_FILE, pool), pool));
  SVN_ERR(check_format(format));

  /* If using Berkeley DB 4.2 or later, note whether the DB_LOG_AUTO_REMOVE
     feature is on.  If it is, we have a potential race condition:
     another process might delete a logfile while we're in the middle
     of copying all the logfiles.  (This is not a huge deal; at worst,
     the hotcopy fails with a file-not-found error.) */
#if SVN_BDB_VERSION_AT_LEAST(4, 2)
  err = check_env_flags(&log_autoremove,
#if SVN_BDB_VERSION_AT_LEAST(4, 7)
                          DB_LOG_AUTO_REMOVE,
 /* DB_LOG_AUTO_REMOVE was named DB_LOG_AUTOREMOVE before Berkeley DB 4.7. */
#else
                          DB_LOG_AUTOREMOVE,
#endif
                          src_path, pool);
#endif
  SVN_ERR(err);

  /* Copy the DB_CONFIG file. */
  SVN_ERR(svn_io_dir_file_copy(src_path, dest_path, "DB_CONFIG", pool));

  /* In order to copy the database files safely and atomically, we
     must copy them in chunks which are multiples of the page-size
     used by BDB.  See sleepycat docs for details, or svn issue #1818. */
#if SVN_BDB_VERSION_AT_LEAST(4, 2)
  SVN_ERR(get_db_pagesize(&pagesize, src_path, pool));
  if (pagesize < SVN__STREAM_CHUNK_SIZE)
    {
      /* use the largest multiple of BDB pagesize we can. */
      int multiple = SVN__STREAM_CHUNK_SIZE / pagesize;
      pagesize *= multiple;
    }
#else
  /* default to 128K chunks, which should be safe.
     BDB almost certainly uses a power-of-2 pagesize. */
  pagesize = (4096 * 32);
#endif

  /* Copy the databases.  */
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "nodes", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "transactions", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "revisions", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "copies", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "changes", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "representations", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "strings", pagesize, FALSE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "uuids", pagesize, TRUE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "locks", pagesize, TRUE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "lock-tokens", pagesize, TRUE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "node-origins", pagesize, TRUE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "checksum-reps", pagesize, TRUE, pool));
  SVN_ERR(copy_db_file_safely(src_path, dest_path,
                              "miscellaneous", pagesize, TRUE, pool));

  {
    apr_array_header_t *logfiles;
    int idx;
    apr_pool_t *subpool;

    SVN_ERR(base_bdb_logfiles(&logfiles,
                              src_path,
                              FALSE,   /* All logs */
                              pool));

    /* Process log files. */
    subpool = svn_pool_create(pool);
    for (idx = 0; idx < logfiles->nelts; idx++)
      {
        svn_pool_clear(subpool);
        err = svn_io_dir_file_copy(src_path, dest_path,
                                   APR_ARRAY_IDX(logfiles, idx,
                                                 const char *),
                                   subpool);
        if (err)
          {
            if (log_autoremove)
              return
                svn_error_quick_wrap
                (err,
                 _("Error copying logfile;  the DB_LOG_AUTOREMOVE feature\n"
                   "may be interfering with the hotcopy algorithm.  If\n"
                   "the problem persists, try deactivating this feature\n"
                   "in DB_CONFIG"));
            else
              return svn_error_trace(err);
          }
      }
    svn_pool_destroy(subpool);
  }

  /* Since this is a copy we will have exclusive access to the repository. */
  err = bdb_recover(dest_path, TRUE, pool);
  if (err)
    {
      if (log_autoremove)
        return
          svn_error_quick_wrap
          (err,
           _("Error running catastrophic recovery on hotcopy;  the\n"
             "DB_LOG_AUTOREMOVE feature may be interfering with the\n"
             "hotcopy algorithm.  If the problem persists, try deactivating\n"
             "this feature in DB_CONFIG"));
      else
        return svn_error_trace(err);
    }

  /* Only now that the hotcopied filesystem is complete,
     stamp it with a format file. */
  SVN_ERR(svn_io_write_version_file(
             svn_dirent_join(dest_path, FORMAT_FILE, pool), format, pool));

  if (clean_logs)
    SVN_ERR(svn_fs_base__clean_logs(src_path, dest_path, pool));

  return SVN_NO_ERROR;
}
Exemplo n.º 20
0
/*
 * On success, leave *EXIT_CODE untouched and return SVN_NO_ERROR. On error,
 * either return an error to be displayed, or set *EXIT_CODE to non-zero and
 * return SVN_NO_ERROR.
 */
static svn_error_t *
sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
{
  svn_error_t *err;

  const svn_opt_subcommand_desc2_t *subcommand = NULL;
  struct svnauthz_opt_state opt_state = { 0 };
  apr_getopt_t *os;
  apr_array_header_t *received_opts;
  int i;

  /* Initialize the FS library. */
  SVN_ERR(svn_fs_initialize(pool));

  received_opts = apr_array_make(pool, SVN_OPT_MAX_OPTIONS, sizeof(int));

  /* Initialize opt_state */
  opt_state.username = opt_state.fspath = opt_state.repos_name = NULL;
  opt_state.txn = opt_state.repos_path = opt_state.groups_file = NULL;

  /* Parse options. */
  SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
  os->interleave = 1;

  if (!use_compat_mode(argv[0], pool))
    {
      while (1)
        {
          int opt;
          const char *arg;
          apr_status_t status = apr_getopt_long(os, options_table, &opt, &arg);

          if (APR_STATUS_IS_EOF(status))
            break;
          if (status != APR_SUCCESS)
            {
              SVN_ERR(subcommand_help(NULL, NULL, pool));
              *exit_code = EXIT_FAILURE;
              return SVN_NO_ERROR;
            }

          /* Stash the option code in an array before parsing it. */
          APR_ARRAY_PUSH(received_opts, int) = opt;

          switch (opt)
            {
            case 'h':
            case '?':
              opt_state.help = TRUE;
              break;
            case 't':
              SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.txn, arg, pool));
              break;
            case 'R':
              opt_state.recursive = TRUE;
              break;
            case svnauthz__version:
              opt_state.version = TRUE;
              break;
            case svnauthz__username:
              SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.username, arg, pool));
              break;
            case svnauthz__path:
              SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.fspath, arg, pool));
              opt_state.fspath = svn_fspath__canonicalize(opt_state.fspath,
                                                          pool);
              break;
            case svnauthz__repos:
              SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.repos_name, arg, pool));
              break;
            case svnauthz__is:
              SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.is, arg, pool));
              break;
            case svnauthz__groups_file:
              SVN_ERR(
                  svn_utf_cstring_to_utf8(&opt_state.groups_file,
                                          arg, pool));
              break;
            default:
                {
                  SVN_ERR(subcommand_help(NULL, NULL, pool));
                  *exit_code = EXIT_FAILURE;
                  return SVN_NO_ERROR;
                }
            }
        }
    }
  else
    {
      /* Pre 1.8 compatibility mode. */
      if (argc == 1) /* No path argument */
        subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "help");
      else
        subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "validate");
    }

  /* If the user asked for help, then the rest of the arguments are
     the names of subcommands to get help on (if any), or else they're
     just typos/mistakes.  Whatever the case, the subcommand to
     actually run is subcommand_help(). */
  if (opt_state.help)
    subcommand = svn_opt_get_canonical_subcommand2(cmd_table, "help");

  if (subcommand == NULL)
    {
      if (os->ind >= os->argc)
        {
          if (opt_state.version)
            {
              /* Use the "help" subcommand to handle the "--version" option. */
              static const svn_opt_subcommand_desc2_t pseudo_cmd =
                { "--version", subcommand_help, {0}, "",
                  {svnauthz__version /* must accept its own option */ } };

              subcommand = &pseudo_cmd;
            }
          else
            {
              svn_error_clear(svn_cmdline_fprintf(stderr, pool,
                                        ("subcommand argument required\n")));
              SVN_ERR(subcommand_help(NULL, NULL, pool));
              *exit_code = EXIT_FAILURE;
              return SVN_NO_ERROR;
            }
        }
      else
        {
          const char *first_arg = os->argv[os->ind++];
          subcommand = svn_opt_get_canonical_subcommand2(cmd_table, first_arg);
          if (subcommand == NULL)
            {
              const char *first_arg_utf8;

              os->ind++;
              SVN_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8,
                                                  first_arg, pool));
              svn_error_clear(
                svn_cmdline_fprintf(stderr, pool,
                                    ("Unknown subcommand: '%s'\n"),
                                    first_arg_utf8));
              SVN_ERR(subcommand_help(NULL, NULL, pool));
              *exit_code = EXIT_FAILURE;
              return SVN_NO_ERROR;
            }
        }
    }

  /* Every subcommand except `help' requires one or two non-option arguments.
     Parse them and store them in opt_state.*/
  if (subcommand->cmd_func != subcommand_help)
    {
      /* Consume a non-option argument (repos_path) if --transaction */
      if (opt_state.txn)
        {
          if (os->ind +2 != argc)
            {
              return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                      ("Repository and authz file arguments "
                                       "required"));
            }

          SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.repos_path, os->argv[os->ind],
                                              pool));
          os->ind++;

          opt_state.repos_path = svn_dirent_internal_style(opt_state.repos_path, pool);
        }

      /* Exactly 1 non-option argument */
      if (os->ind + 1 != argc)
        {
          return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                  ("Authz file argument required"));
        }

      /* Grab AUTHZ_FILE from argv. */
      SVN_ERR(svn_utf_cstring_to_utf8(&opt_state.authz_file, os->argv[os->ind],
                                          pool));

      /* Canonicalize opt_state.authz_file appropriately. */
      SVN_ERR(canonicalize_access_file(&opt_state.authz_file,
                                           opt_state.authz_file,
                                           opt_state.txn != NULL, pool));

      /* Same for opt_state.groups_file if it is present. */
      if (opt_state.groups_file)
        {
          SVN_ERR(canonicalize_access_file(&opt_state.groups_file,
                                               opt_state.groups_file,
                                               opt_state.txn != NULL, pool));
        }
    }

  /* Check that the subcommand wasn't passed any inappropriate options. */
  for (i = 0; i < received_opts->nelts; i++)
    {
      int opt_id = APR_ARRAY_IDX(received_opts, i, int);

      /* All commands implicitly accept --help, so just skip over this
         when we see it. Note that we don't want to include this option
         in their "accepted options" list because it would be awfully
         redundant to display it in every commands' help text. */
      if (opt_id == 'h' || opt_id == '?')
        continue;

      if (! svn_opt_subcommand_takes_option3(subcommand, opt_id, NULL))
        {
          const char *optstr;
          const apr_getopt_option_t *badopt =
            svn_opt_get_option_from_code2(opt_id, options_table, subcommand,
                                          pool);
          svn_opt_format_option(&optstr, badopt, FALSE, pool);
          if (subcommand->name[0] == '-')
            SVN_ERR(subcommand_help(NULL, NULL, pool));
          else
            svn_error_clear(svn_cmdline_fprintf(stderr, pool,
                            ("Subcommand '%s' doesn't accept option '%s'\n"
                             "Type 'svnauthz help %s' for usage.\n"),
                            subcommand->name, optstr, subcommand->name));
          *exit_code = EXIT_FAILURE;
          return SVN_NO_ERROR;
        }
    }

  /* Run the subcommand. */
  err = (*subcommand->cmd_func)(os, &opt_state, pool);

  if (err)
    {
      if (err->apr_err == SVN_ERR_CL_INSUFFICIENT_ARGS
          || err->apr_err == SVN_ERR_CL_ARG_PARSING_ERROR)
        {
          /* For argument-related problems, suggest using the 'help'
             subcommand. */
          err = svn_error_quick_wrap(err,
                                     ("Try 'svnauthz help' for more info"));
        }
      else if (err->apr_err == SVN_ERR_AUTHZ_INVALID_CONFIG
               || err->apr_err == SVN_ERR_MALFORMED_FILE)
        {
          /* Follow our contract that says we exit with 1 if the file does not
             validate. */
          *exit_code = 1;
          return err;
        }
      else if (err->apr_err == SVN_ERR_AUTHZ_UNREADABLE
               || err->apr_err == SVN_ERR_AUTHZ_UNWRITABLE
               || err->apr_err == SVN_ERR_AUTHZ_PARTIALLY_READABLE)
        {
          /* Follow our contract that says we exit with 3 if --is does not
           * match. */
          *exit_code = 3;
          return err;
        }

      return err;
    }

  return SVN_NO_ERROR;
}
Exemplo n.º 21
0
static svn_error_t *
close_revision(void *baton)
{
  struct revision_baton *rb = baton;
  struct parse_baton *pb = rb->pb;
  const char *conflict_msg = NULL;
  svn_revnum_t committed_rev;
  svn_error_t *err;
  const char *txn_name = NULL;
  apr_hash_t *hooks_env;

  /* If we're skipping this revision or it has an invalid revision
     number, we're done here. */
  if (rb->skipped || (rb->rev <= 0))
    return SVN_NO_ERROR;

  /* Get the txn name and hooks environment if they will be needed. */
  if (pb->use_pre_commit_hook || pb->use_post_commit_hook)
    {
      SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, pb->repos->hooks_env_path,
                                         rb->pool, rb->pool));

      err = svn_fs_txn_name(&txn_name, rb->txn, rb->pool);
      if (err)
        {
          svn_error_clear(svn_fs_abort_txn(rb->txn, rb->pool));
          return svn_error_trace(err);
        }
    }

  /* Run the pre-commit hook, if so commanded. */
  if (pb->use_pre_commit_hook)
    {
      err = svn_repos__hooks_pre_commit(pb->repos, hooks_env,
                                        txn_name, rb->pool);
      if (err)
        {
          svn_error_clear(svn_fs_abort_txn(rb->txn, rb->pool));
          return svn_error_trace(err);
        }
    }

  /* Commit. */
  err = svn_fs_commit_txn(&conflict_msg, &committed_rev, rb->txn, rb->pool);
  if (SVN_IS_VALID_REVNUM(committed_rev))
    {
      if (err)
        {
          /* ### Log any error, but better yet is to rev
             ### close_revision()'s API to allow both committed_rev and err
             ### to be returned, see #3768. */
          svn_error_clear(err);
        }
    }
  else
    {
      svn_error_clear(svn_fs_abort_txn(rb->txn, rb->pool));
      if (conflict_msg)
        return svn_error_quick_wrap(err, conflict_msg);
      else
        return svn_error_trace(err);
    }

  /* Run post-commit hook, if so commanded.  */
  if (pb->use_post_commit_hook)
    {
      if ((err = svn_repos__hooks_post_commit(pb->repos, hooks_env,
                                              committed_rev, txn_name,
                                              rb->pool)))
        return svn_error_create
          (SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err,
           _("Commit succeeded, but post-commit hook failed"));
    }

  /* After a successful commit, must record the dump-rev -> in-repos-rev
     mapping, so that copyfrom instructions in the dump file can look up the
     correct repository revision to copy from. */
  set_revision_mapping(pb->rev_map, rb->rev, committed_rev);

  /* If the incoming dump stream has non-contiguous revisions (e.g. from
     using svndumpfilter --drop-empty-revs without --renumber-revs) then
     we must account for the missing gaps in PB->REV_MAP.  Otherwise we
     might not be able to map all mergeinfo source revisions to the correct
     revisions in the target repos. */
  if ((pb->last_rev_mapped != SVN_INVALID_REVNUM)
      && (rb->rev != pb->last_rev_mapped + 1))
    {
      svn_revnum_t i;

      for (i = pb->last_rev_mapped + 1; i < rb->rev; i++)
        {
          set_revision_mapping(pb->rev_map, i, pb->last_rev_mapped);
        }
    }

  /* Update our "last revision mapped". */
  pb->last_rev_mapped = rb->rev;

  /* Deltify the predecessors of paths changed in this revision. */
  SVN_ERR(svn_fs_deltify_revision(pb->fs, committed_rev, rb->pool));

  /* Grrr, svn_fs_commit_txn rewrites the datestamp property to the
     current clock-time.  We don't want that, we want to preserve
     history exactly.  Good thing revision props aren't versioned!
     Note that if rb->datestamp is NULL, that's fine -- if the dump
     data doesn't carry a datestamp, we want to preserve that fact in
     the load. */
  SVN_ERR(change_rev_prop(pb->repos, committed_rev, SVN_PROP_REVISION_DATE,
                          rb->datestamp, pb->validate_props, rb->pool));

  if (pb->notify_func)
    {
      /* ### TODO: Use proper scratch pool instead of pb->notify_pool */
      svn_repos_notify_t *notify = svn_repos_notify_create(
                                        svn_repos_notify_load_txn_committed,
                                        pb->notify_pool);

      notify->new_revision = committed_rev;
      notify->old_revision = ((committed_rev == rb->rev)
                                    ? SVN_INVALID_REVNUM
                                    : rb->rev);
      pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
      svn_pool_clear(pb->notify_pool);
    }

  return SVN_NO_ERROR;
}
Exemplo n.º 22
0
dav_error *
dav_svn__store_activity(const dav_svn_repos *repos,
                        const char *activity_id,
                        const char *txn_name)
{
  const char *final_path, *tmp_path, *activity_contents;
  svn_error_t *err;
  apr_file_t *activity_file;

  /* Create activities directory if it does not yet exist. */
  err = svn_io_make_dir_recursively(repos->activities_db, repos->pool);
  if (err != NULL)
    return dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR,
                                "could not initialize activity db.",
                                repos->pool);

  final_path = activity_pathname(repos, activity_id);
  err = svn_io_open_unique_file2(&activity_file, &tmp_path, final_path,
                                 ".tmp", svn_io_file_del_none, repos->pool);
  if (err)
    {
      svn_error_t *serr = svn_error_quick_wrap(err, "Can't open activity db");
      return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                  "could not open files.",
                                  repos->pool);
    }

  activity_contents = apr_psprintf(repos->pool, "%s\n%s\n",
                                   txn_name, activity_id);
  err = svn_io_file_write_full(activity_file, activity_contents,
                               strlen(activity_contents), NULL, repos->pool);
  if (err)
    {
      svn_error_t *serr = svn_error_quick_wrap(err,
                                               "Can't write to activity db");

      /* Try to remove the tmp file, but we already have an error... */
      svn_error_clear(svn_io_file_close(activity_file, repos->pool));
      svn_error_clear(svn_io_remove_file(tmp_path, repos->pool));
      return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                  "could not write files.",
                                  repos->pool);
    }

  err = svn_io_file_close(activity_file, repos->pool);
  if (err)
    {
      svn_error_clear(svn_io_remove_file(tmp_path, repos->pool));
      return dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR,
                                  "could not close files.",
                                  repos->pool);
    }

  err = svn_io_file_rename(tmp_path, final_path, repos->pool);
  if (err)
    {
      svn_error_clear(svn_io_remove_file(tmp_path, repos->pool));
      return dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR,
                                  "could not replace files.",
                                  repos->pool);
    }

  return NULL;
}
Exemplo n.º 23
0
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__add(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;
  int i;
  apr_pool_t *iterpool;
  apr_array_header_t *errors = apr_array_make(pool, 0, sizeof(apr_status_t));

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

  if (! targets->nelts)
    return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);

  if (opt_state->depth == svn_depth_unknown)
    opt_state->depth = svn_depth_infinity;

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

  SVN_ERR(svn_cl__check_targets_are_local_paths(targets));

  iterpool = svn_pool_create(pool);
  for (i = 0; i < targets->nelts; i++)
    {
      const char *target = APR_ARRAY_IDX(targets, i, const char *);

      svn_pool_clear(iterpool);
      SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
      SVN_ERR(svn_cl__try
              (svn_client_add5(target,
                               opt_state->depth,
                               opt_state->force, opt_state->no_ignore,
                               opt_state->no_autoprops, opt_state->parents,
                               ctx, iterpool),
               errors, opt_state->quiet,
               SVN_ERR_ENTRY_EXISTS,
               SVN_ERR_WC_PATH_NOT_FOUND,
               0));
    }

  svn_pool_destroy(iterpool);

  if (errors->nelts > 0)
    {
      svn_error_t *err;

      err = svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, NULL);
      for (i = 0; i < errors->nelts; i++)
        {
          apr_status_t status = APR_ARRAY_IDX(errors, i, apr_status_t);
          if (status == SVN_ERR_WC_PATH_NOT_FOUND)
            err = svn_error_quick_wrap(err,
                                       _("Could not add all targets because "
                                         "some targets don't exist"));
          else if (status == SVN_ERR_ENTRY_EXISTS)
            err = svn_error_quick_wrap(err,
                                       _("Could not add all targets because "
                                         "some targets are already versioned"));
        }

      return svn_error_trace(err);
    }

  return SVN_NO_ERROR;
}
Exemplo n.º 24
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;
}