Example #1
0
/* Dumps the contents of a file to stdout */
static svn_error_t *delta_cat_file(apr_pool_t *pool, const char *path)
{
	svn_error_t *err;
	apr_status_t status;
	apr_file_t *in_file = NULL;
	svn_stream_t *in, *out;

	status = apr_file_open(&in_file, path, APR_READ, 0600, pool);
	if (status) {
		apr_pool_t *epool = svn_pool_create(NULL);
		char *errbuf = apr_palloc(epool, ERRBUFFER_SIZE);
		return svn_error_create(status, NULL, apr_strerror(status, errbuf, ERRBUFFER_SIZE));
	}
	in = svn_stream_from_aprfile2(in_file, FALSE, pool);
	if ((err = svn_stream_for_stdout(&out, pool))) {
		svn_stream_close(in);
		return err;
	}

	/* Write contents */
	if ((err = svn_stream_copy(in, out, pool))) {
		svn_stream_close(in);
		return err;
	}

	err = svn_stream_close(in);
	return SVN_NO_ERROR;
}
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__cat(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;
  svn_stream_t *out;
  apr_pool_t *subpool = svn_pool_create(pool);
  svn_boolean_t seen_nonexistent_target = FALSE;

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

  /* Cat cannot operate on an implicit '.' so a filename is required */
  if (! targets->nelts)
    return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);

  SVN_ERR(svn_stream_for_stdout(&out, pool));

  for (i = 0; i < targets->nelts; i++)
    {
      const char *target = APR_ARRAY_IDX(targets, i, const char *);
      const char *truepath;
      svn_opt_revision_t peg_revision;
      svn_boolean_t success;

      svn_pool_clear(subpool);
      SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));

      /* Get peg revisions. */
      SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target,
                                 subpool));

      SVN_ERR(svn_cl__try(svn_client_cat2(out, truepath, &peg_revision,
                                          &(opt_state->start_revision),
                                          ctx, subpool),
                           &success, opt_state->quiet,
                           SVN_ERR_UNVERSIONED_RESOURCE,
                           SVN_ERR_ENTRY_NOT_FOUND,
                           SVN_ERR_CLIENT_IS_DIRECTORY,
                           SVN_ERR_FS_NOT_FOUND,
                           SVN_NO_ERROR));
      if (! success)
        seen_nonexistent_target = TRUE;
    }
  svn_pool_destroy(subpool);

  if (seen_nonexistent_target)
    return svn_error_create(
      SVN_ERR_ILLEGAL_TARGET, NULL,
      _("Could not cat all targets because some targets don't exist"));
  else
    return SVN_NO_ERROR;
}
Example #3
0
/* Print dumpstream-formatted information about REVISION.
 * Implements the `svn_ra_replay_revstart_callback_t' interface.
 */
static svn_error_t *
replay_revstart(svn_revnum_t revision,
                void *replay_baton,
                const svn_delta_editor_t **editor,
                void **edit_baton,
                apr_hash_t *rev_props,
                apr_pool_t *pool)
{
    struct replay_baton *rb = replay_baton;
    apr_hash_t *normal_props;
    svn_stringbuf_t *propstring;
    svn_stream_t *stdout_stream;
    svn_stream_t *revprop_stream;

    SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));

    /* Revision-number: 19 */
    SVN_ERR(svn_stream_printf(stdout_stream, pool,
                              SVN_REPOS_DUMPFILE_REVISION_NUMBER
                              ": %ld\n", revision));
    SVN_ERR(svn_rdump__normalize_props(&normal_props, rev_props, pool));
    propstring = svn_stringbuf_create_ensure(0, pool);
    revprop_stream = svn_stream_from_stringbuf(propstring, pool);
    SVN_ERR(svn_hash_write2(normal_props, revprop_stream, "PROPS-END", pool));
    SVN_ERR(svn_stream_close(revprop_stream));

    /* Prop-content-length: 13 */
    SVN_ERR(svn_stream_printf(stdout_stream, pool,
                              SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
                              ": %" APR_SIZE_T_FMT "\n", propstring->len));

    /* Content-length: 29 */
    SVN_ERR(svn_stream_printf(stdout_stream, pool,
                              SVN_REPOS_DUMPFILE_CONTENT_LENGTH
                              ": %" APR_SIZE_T_FMT "\n\n", propstring->len));

    /* Property data. */
    SVN_ERR(svn_stream_write(stdout_stream, propstring->data,
                             &(propstring->len)));

    SVN_ERR(svn_stream_printf(stdout_stream, pool, "\n"));
    SVN_ERR(svn_stream_close(stdout_stream));

    SVN_ERR(svn_rdump__get_dump_editor(editor, edit_baton, revision,
                                       rb->stdout_stream, rb->extra_ra_session,
                                       check_cancel, NULL, pool));

    return SVN_NO_ERROR;
}
Example #4
0
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__cat(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;
  svn_stream_t *out;
  apr_pool_t *subpool = svn_pool_create(pool);

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

  /* Cat cannot operate on an implicit '.' so a filename is required */
  if (! targets->nelts)
    return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);

  SVN_ERR(svn_stream_for_stdout(&out, pool));

  for (i = 0; i < targets->nelts; i++)
    {
      const char *target = ((const char **) (targets->elts))[i];
      const char *truepath;
      svn_opt_revision_t peg_revision;

      svn_pool_clear(subpool);
      SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));

      /* Get peg revisions. */
      SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target,
                                 subpool));
      
      SVN_ERR(svn_cl__try( svn_client_cat2(out, truepath, &peg_revision,
                                           &(opt_state->start_revision),
                                           ctx, subpool),
                           NULL, opt_state->quiet,
                           SVN_ERR_UNVERSIONED_RESOURCE,
                           SVN_ERR_ENTRY_NOT_FOUND,
                           SVN_ERR_CLIENT_IS_DIRECTORY,
                           SVN_NO_ERROR));
    }
  svn_pool_destroy(subpool);

  return SVN_NO_ERROR;
}
Example #5
0
int main(int argc, char *argv[])
{
    apr_pool_t *pool;
    svn_stream_t *ostream;
    int rc = 0;
    svn_error_t *svn_err;

    apr_initialize();

    pool = svn_pool_create(NULL);

    svn_err = svn_stream_for_stdout(&ostream, pool);
    if (svn_err)
    {
        svn_handle_error2(svn_err, stdout, FALSE, "diff4-test: ");
        rc = 2;
    }
    else if (argc == 5)
    {
        svn_err = do_diff4(ostream,
                           argv[2], argv[1], argv[3], argv[4],
                           pool);
        if (svn_err != NULL)
        {
            svn_handle_error2(svn_err, stdout, FALSE, "diff4-test: ");
            rc = 2;
        }
    }
    else
    {
        svn_error_clear(svn_stream_printf
                        (ostream, pool, "Usage: %s <mine> <older> <yours> <ancestor>\n",
                         argv[0]));
        rc = 2;
    }

    apr_terminate();

    return rc;
}
Example #6
0
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__propget(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;
  const char *pname, *pname_utf8;
  apr_array_header_t *args, *targets;
  svn_stream_t *out;

  if (opt_state->verbose && (opt_state->revprop || opt_state->strict
                             || opt_state->xml))
    return svn_error_create(SVN_ERR_CL_MUTUALLY_EXCLUSIVE_ARGS, NULL,
                            _("--verbose cannot be used with --revprop or "
                              "--strict or --xml"));

  /* PNAME is first argument (and PNAME_UTF8 will be a UTF-8 version
     thereof) */
  SVN_ERR(svn_opt_parse_num_args(&args, os, 1, pool));
  pname = APR_ARRAY_IDX(args, 0, const char *);
  SVN_ERR(svn_utf_cstring_to_utf8(&pname_utf8, pname, pool));
  if (! svn_prop_name_is_valid(pname_utf8))
    return svn_error_createf(SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
                             _("'%s' is not a valid Subversion property name"),
                             pname_utf8);

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

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

  /* Open a stream to stdout. */
  SVN_ERR(svn_stream_for_stdout(&out, pool));

  if (opt_state->revprop)  /* operate on a revprop */
    {
      svn_revnum_t rev;
      const char *URL;
      svn_string_t *propval;

      SVN_ERR(svn_cl__revprop_prepare(&opt_state->start_revision, targets,
                                      &URL, ctx, pool));

      /* Let libsvn_client do the real work. */
      SVN_ERR(svn_client_revprop_get(pname_utf8, &propval,
                                     URL, &(opt_state->start_revision),
                                     &rev, ctx, pool));

      if (propval != NULL)
        {
          if (opt_state->xml)
            {
              svn_stringbuf_t *sb = NULL;
              char *revstr = apr_psprintf(pool, "%ld", rev);

              SVN_ERR(svn_cl__xml_print_header("properties", pool));

              svn_xml_make_open_tag(&sb, pool, svn_xml_normal,
                                    "revprops",
                                    "rev", revstr, NULL);

              svn_cmdline__print_xml_prop(&sb, pname_utf8, propval, pool);

              svn_xml_make_close_tag(&sb, pool, "revprops");

              SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
              SVN_ERR(svn_cl__xml_print_footer("properties", pool));
            }
          else
            {
              svn_string_t *printable_val = propval;

              /* If this is a special Subversion property, it is stored as
                 UTF8 and LF, so convert to the native locale and eol-style. */

              if (svn_prop_needs_translation(pname_utf8))
                SVN_ERR(svn_subst_detranslate_string(&printable_val, propval,
                                                     TRUE, pool));

              SVN_ERR(stream_write(out, printable_val->data,
                                   printable_val->len));
              if (! opt_state->strict)
                SVN_ERR(stream_write(out, APR_EOL_STR, strlen(APR_EOL_STR)));
            }
        }
    }
  else  /* operate on a normal, versioned property (not a revprop) */
    {
      apr_pool_t *subpool = svn_pool_create(pool);
      int i;

      if (opt_state->xml)
        SVN_ERR(svn_cl__xml_print_header("properties", subpool));

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

      /* Strict mode only makes sense for a single target.  So make
         sure we have only a single target, and that we're not being
         asked to recurse on that target. */
      if (opt_state->strict
          && ((targets->nelts > 1) || (opt_state->depth != svn_depth_empty)))
        return svn_error_create
          (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
           _("Strict output of property values only available for single-"
             "target, non-recursive propget operations"));

      for (i = 0; i < targets->nelts; i++)
        {
          const char *target = APR_ARRAY_IDX(targets, i, const char *);
          apr_hash_t *props;
          svn_boolean_t print_filenames;
          svn_boolean_t omit_newline;
          svn_boolean_t like_proplist;
          const char *truepath;
          svn_opt_revision_t peg_revision;

          svn_pool_clear(subpool);
          SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));

          /* Check for a peg revision. */
          SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target,
                                     subpool));

          if (!svn_path_is_url(truepath))
            SVN_ERR(svn_dirent_get_absolute(&truepath, truepath, subpool));

          SVN_ERR(svn_client_propget4(&props, pname_utf8, truepath,
                                      &peg_revision,
                                      &(opt_state->start_revision),
                                      NULL, opt_state->depth,
                                      opt_state->changelists, ctx, subpool,
                                      subpool));

          /* Any time there is more than one thing to print, or where
             the path associated with a printed thing is not obvious,
             we'll print filenames.  That is, unless we've been told
             not to do so with the --strict option. */
          print_filenames = ((opt_state->depth > svn_depth_empty
                              || targets->nelts > 1
                              || apr_hash_count(props) > 1
                              || opt_state->verbose)
                             && (! opt_state->strict));
          omit_newline = opt_state->strict;
          like_proplist = opt_state->verbose && !opt_state->strict;

          if (opt_state->xml)
            SVN_ERR(print_properties_xml(pname_utf8, props, subpool));
          else
            SVN_ERR(print_properties(out, svn_path_is_url(target), pname_utf8,
                                     props, print_filenames, omit_newline,
                                     like_proplist, subpool));
        }

      if (opt_state->xml)
        SVN_ERR(svn_cl__xml_print_footer("properties", subpool));

      svn_pool_destroy(subpool);
    }

  return SVN_NO_ERROR;
}
Example #7
0
File: diff.c Project: lysine/wasp
int main(int argc, const char *argv[])
{
  apr_pool_t *pool;
  svn_stream_t *ostream;
  svn_error_t *svn_err;
  svn_boolean_t has_changes;
  svn_diff_file_options_t *diff_options;
  apr_array_header_t *options_array;
  int i;
  const char *from = NULL;
  const char *to = NULL;
  svn_boolean_t show_c_function = FALSE;
  svn_boolean_t no_more_options = FALSE;

  apr_initialize();
  atexit(apr_terminate);

  pool = svn_pool_create(NULL);

  svn_err = svn_stream_for_stdout(&ostream, pool);
  if (svn_err)
    {
      svn_handle_error2(svn_err, stdout, FALSE, "diff: ");
      return 2;
    }

  options_array = apr_array_make(pool, 0, sizeof(const char *));

  diff_options = svn_diff_file_options_create(pool);

  for (i = 1 ; i < argc ; i++)
    {
      if (!no_more_options && (argv[i][0] == '-'))
        {
          /* Special case: '--' means "no more options follow" */
          if (argv[i][1] == '-' && !argv[i][2])
            {
              no_more_options = TRUE;
              continue;
            }
          /* Special case: we need to detect '-p' and handle it specially */
          if (argv[i][1] == 'p' && !argv[i][2])
            {
              show_c_function = TRUE;
              continue;
            }
          if (argv[i][1] == 'w' && !argv[i][2])
            {
              diff_options->ignore_space = svn_diff_file_ignore_space_all;
              continue;
            }

          APR_ARRAY_PUSH(options_array, const char *) = argv[i];

          /* Special case: '-U' takes an argument, so capture the
           * next argument in the array. */
          if (argv[i][1] == 'U' && !argv[i][2])
            {
              i++;
              APR_ARRAY_PUSH(options_array, const char *) = argv[i];
            }
        }
      else
        {
          if (from == NULL)
            from = argv[i];
          else if (to == NULL)
            to = argv[i];
          else
            {
              print_usage(ostream, argv[0], pool);
              return 2;
            }
        }
    }

  if (!from || !to)
    {
      print_usage(ostream, argv[0], pool);
      return 2;
    }

  svn_err = svn_diff_file_options_parse(diff_options, options_array, pool);
  if (svn_err)
    {
      svn_handle_error2(svn_err, stdout, FALSE, "diff: ");
      return 2;
    }

  svn_err = do_diff(ostream, from, to, &has_changes,
                    diff_options, show_c_function, pool);
  if (svn_err)
    {
      svn_handle_error2(svn_err, stdout, FALSE, "diff: ");
      return 2;
    }

  return has_changes ? 1 : 0;
}
Example #8
0
/* Replay revisions START_REVISION thru END_REVISION (inclusive) of
 * the repository located at URL, using callbacks which generate
 * Subversion repository dumpstreams describing the changes made in
 * those revisions.  If QUIET is set, don't generate progress
 * messages.
 */
static svn_error_t *
replay_revisions(svn_ra_session_t *session,
                 svn_ra_session_t *extra_ra_session,
                 const char *url,
                 svn_revnum_t start_revision,
                 svn_revnum_t end_revision,
                 svn_boolean_t quiet,
                 svn_boolean_t incremental,
                 apr_pool_t *pool)
{
    struct replay_baton *replay_baton;
    const char *uuid;
    svn_stream_t *stdout_stream;

    SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));

    replay_baton = apr_pcalloc(pool, sizeof(*replay_baton));
    replay_baton->stdout_stream = stdout_stream;
    replay_baton->extra_ra_session = extra_ra_session;
    replay_baton->quiet = quiet;

    /* Write the magic header and UUID */
    SVN_ERR(svn_stream_printf(stdout_stream, pool,
                              SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n\n",
                              SVN_REPOS_DUMPFILE_FORMAT_VERSION));
    SVN_ERR(svn_ra_get_uuid2(session, &uuid, pool));
    SVN_ERR(svn_stream_printf(stdout_stream, pool,
                              SVN_REPOS_DUMPFILE_UUID ": %s\n\n", uuid));

    /* Fake revision 0 if necessary */
    if (start_revision == 0)
    {
        SVN_ERR(dump_revision_header(session, stdout_stream,
                                     start_revision, pool));

        /* Revision 0 has no tree changes, so we're done. */
        if (! quiet)
            SVN_ERR(svn_cmdline_fprintf(stderr, pool, "* Dumped revision %lu.\n",
                                        start_revision));
        start_revision++;

        /* If our first revision is 0, we can treat this as an
           incremental dump. */
        incremental = TRUE;
    }

    if (incremental)
    {
        SVN_ERR(svn_ra_replay_range(session, start_revision, end_revision,
                                    0, TRUE, replay_revstart, replay_revend,
                                    replay_baton, pool));
    }
    else
    {
        const svn_ra_reporter3_t *reporter;
        void *report_baton;
        const svn_delta_editor_t *dump_editor;
        void *dump_baton;

        /* First, we need to dump the start_revision in full.  We'll
           start with a revision record header. */
        SVN_ERR(dump_revision_header(session, stdout_stream,
                                     start_revision, pool));

        /* Then, we'll drive the dump editor with what would look like a
           full checkout of the repository as it looked in
           START_REVISION.  We do this by manufacturing a basic 'report'
           to the update reporter, telling it that we have nothing to
           start with.  The delta between nothing and everything-at-REV
           is, effectively, a full dump of REV. */
        SVN_ERR(svn_rdump__get_dump_editor(&dump_editor, &dump_baton,
                                           start_revision,
                                           stdout_stream, extra_ra_session,
                                           check_cancel, NULL, pool));
        SVN_ERR(svn_ra_do_update2(session, &reporter, &report_baton,
                                  start_revision, "", svn_depth_infinity,
                                  FALSE, dump_editor, dump_baton, pool));
        SVN_ERR(reporter->set_path(report_baton, "", start_revision,
                                   svn_depth_infinity, TRUE, NULL, pool));
        SVN_ERR(reporter->finish_report(report_baton, pool));

        /* All finished with START_REVISION! */
        if (! quiet)
            SVN_ERR(svn_cmdline_fprintf(stderr, pool, "* Dumped revision %lu.\n",
                                        start_revision));
        start_revision++;

        /* Now go pick up additional revisions in the range, if any. */
        if (start_revision <= end_revision)
            SVN_ERR(svn_ra_replay_range(session, start_revision, end_revision,
                                        0, TRUE, replay_revstart, replay_revend,
                                        replay_baton, pool));
    }

    SVN_ERR(svn_stream_close(stdout_stream));
    return SVN_NO_ERROR;
}
Example #9
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)
{
  enum run_mode run_mode = run_mode_unspecified;
  svn_boolean_t foreground = FALSE;
  apr_socket_t *sock;
  apr_sockaddr_t *sa;
  svn_error_t *err;
  apr_getopt_t *os;
  int opt;
  serve_params_t params;
  const char *arg;
  apr_status_t status;
#ifndef WIN32
  apr_proc_t proc;
#endif
  svn_boolean_t is_multi_threaded;
  enum connection_handling_mode handling_mode = CONNECTION_DEFAULT;
  svn_boolean_t cache_fulltexts = TRUE;
  svn_boolean_t cache_txdeltas = TRUE;
  svn_boolean_t cache_revprops = FALSE;
  svn_boolean_t use_block_read = FALSE;
  apr_uint16_t port = SVN_RA_SVN_PORT;
  const char *host = NULL;
  int family = APR_INET;
  apr_int32_t sockaddr_info_flags = 0;
#if APR_HAVE_IPV6
  svn_boolean_t prefer_v6 = FALSE;
#endif
  svn_boolean_t quiet = FALSE;
  svn_boolean_t is_version = FALSE;
  int mode_opt_count = 0;
  int handling_opt_count = 0;
  const char *config_filename = NULL;
  const char *pid_filename = NULL;
  const char *log_filename = NULL;
  svn_node_kind_t kind;
  apr_size_t min_thread_count = THREADPOOL_MIN_SIZE;
  apr_size_t max_thread_count = THREADPOOL_MAX_SIZE;
#ifdef SVN_HAVE_SASL
  SVN_ERR(cyrus_init(pool));
#endif

  /* Check library versions */
  SVN_ERR(check_lib_versions());

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

  SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));

  params.root = "/";
  params.tunnel = FALSE;
  params.tunnel_user = NULL;
  params.read_only = FALSE;
  params.base = NULL;
  params.cfg = NULL;
  params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
  params.logger = NULL;
  params.config_pool = NULL;
  params.authz_pool = NULL;
  params.fs_config = NULL;
  params.vhost = FALSE;
  params.username_case = CASE_ASIS;
  params.memory_cache_size = (apr_uint64_t)-1;
  params.zero_copy_limit = 0;
  params.error_check_interval = 4096;

  while (1)
    {
      status = apr_getopt_long(os, svnserve__options, &opt, &arg);
      if (APR_STATUS_IS_EOF(status))
        break;
      if (status != APR_SUCCESS)
        {
          usage(argv[0], pool);
          *exit_code = EXIT_FAILURE;
          return SVN_NO_ERROR;
        }
      switch (opt)
        {
        case '6':
#if APR_HAVE_IPV6
          prefer_v6 = TRUE;
#endif
          /* ### Maybe error here if we don't have IPV6 support? */
          break;

        case 'h':
          help(pool);
          return SVN_NO_ERROR;

        case 'q':
          quiet = TRUE;
          break;

        case SVNSERVE_OPT_VERSION:
          is_version = TRUE;
          break;

        case 'd':
          if (run_mode != run_mode_daemon)
            {
              run_mode = run_mode_daemon;
              mode_opt_count++;
            }
          break;

        case SVNSERVE_OPT_FOREGROUND:
          foreground = TRUE;
          break;

        case SVNSERVE_OPT_SINGLE_CONN:
          handling_mode = connection_mode_single;
          handling_opt_count++;
          break;

        case 'i':
          if (run_mode != run_mode_inetd)
            {
              run_mode = run_mode_inetd;
              mode_opt_count++;
            }
          break;

        case SVNSERVE_OPT_LISTEN_PORT:
          {
            apr_uint64_t val;

            err = svn_cstring_strtoui64(&val, arg, 0, APR_UINT16_MAX, 10);
            if (err)
              return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, err,
                                       _("Invalid port '%s'"), arg);
            port = (apr_uint16_t)val;
          }
          break;

        case SVNSERVE_OPT_LISTEN_HOST:
          host = arg;
          break;

        case 't':
          if (run_mode != run_mode_tunnel)
            {
              run_mode = run_mode_tunnel;
              mode_opt_count++;
            }
          break;

        case SVNSERVE_OPT_TUNNEL_USER:
          params.tunnel_user = arg;
          break;

        case 'X':
          if (run_mode != run_mode_listen_once)
            {
              run_mode = run_mode_listen_once;
              mode_opt_count++;
            }
          break;

        case 'r':
          SVN_ERR(svn_utf_cstring_to_utf8(&params.root, arg, pool));

          SVN_ERR(svn_io_check_resolved_path(params.root, &kind, pool));
          if (kind != svn_node_dir)
            {
              return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
                       _("Root path '%s' does not exist "
                         "or is not a directory"), params.root);
            }

          params.root = svn_dirent_internal_style(params.root, pool);
          SVN_ERR(svn_dirent_get_absolute(&params.root, params.root, pool));
          break;

        case 'R':
          params.read_only = TRUE;
          break;

        case 'T':
          handling_mode = connection_mode_thread;
          handling_opt_count++;
          break;

        case 'c':
          params.compression_level = atoi(arg);
          if (params.compression_level < SVN_DELTA_COMPRESSION_LEVEL_NONE)
            params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_NONE;
          if (params.compression_level > SVN_DELTA_COMPRESSION_LEVEL_MAX)
            params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_MAX;
          break;

        case 'M':
          params.memory_cache_size = 0x100000 * apr_strtoi64(arg, NULL, 0);
          break;

        case SVNSERVE_OPT_CACHE_TXDELTAS:
          cache_txdeltas = svn_tristate__from_word(arg) == svn_tristate_true;
          break;

        case SVNSERVE_OPT_CACHE_FULLTEXTS:
          cache_fulltexts = svn_tristate__from_word(arg) == svn_tristate_true;
          break;

        case SVNSERVE_OPT_CACHE_REVPROPS:
          cache_revprops = svn_tristate__from_word(arg) == svn_tristate_true;
          break;

        case SVNSERVE_OPT_BLOCK_READ:
          use_block_read = svn_tristate__from_word(arg) == svn_tristate_true;
          break;

        case SVNSERVE_OPT_CLIENT_SPEED:
          {
            apr_size_t bandwidth = (apr_size_t)apr_strtoi64(arg, NULL, 0);

            /* for slower clients, don't try anything fancy */
            if (bandwidth >= 1000)
              {
                /* block other clients for at most 1 ms (at full bandwidth).
                   Note that the send buffer is 16kB anyways. */
                params.zero_copy_limit = bandwidth * 120;

                /* check for aborted connections at the same rate */
                params.error_check_interval = bandwidth * 120;
              }
          }
          break;

        case SVNSERVE_OPT_MIN_THREADS:
          min_thread_count = (apr_size_t)apr_strtoi64(arg, NULL, 0);
          break;

        case SVNSERVE_OPT_MAX_THREADS:
          max_thread_count = (apr_size_t)apr_strtoi64(arg, NULL, 0);
          break;

#ifdef WIN32
        case SVNSERVE_OPT_SERVICE:
          if (run_mode != run_mode_service)
            {
              run_mode = run_mode_service;
              mode_opt_count++;
            }
          break;
#endif

        case SVNSERVE_OPT_CONFIG_FILE:
          SVN_ERR(svn_utf_cstring_to_utf8(&config_filename, arg, pool));
          config_filename = svn_dirent_internal_style(config_filename, pool);
          SVN_ERR(svn_dirent_get_absolute(&config_filename, config_filename,
                                          pool));
          break;

        case SVNSERVE_OPT_PID_FILE:
          SVN_ERR(svn_utf_cstring_to_utf8(&pid_filename, arg, pool));
          pid_filename = svn_dirent_internal_style(pid_filename, pool);
          SVN_ERR(svn_dirent_get_absolute(&pid_filename, pid_filename, pool));
          break;

         case SVNSERVE_OPT_VIRTUAL_HOST:
           params.vhost = TRUE;
           break;

         case SVNSERVE_OPT_LOG_FILE:
          SVN_ERR(svn_utf_cstring_to_utf8(&log_filename, arg, pool));
          log_filename = svn_dirent_internal_style(log_filename, pool);
          SVN_ERR(svn_dirent_get_absolute(&log_filename, log_filename, pool));
          break;

        }
    }

  if (is_version)
    {
      SVN_ERR(version(quiet, pool));
      return SVN_NO_ERROR;
    }

  if (os->ind != argc)
    {
      usage(argv[0], pool);
      *exit_code = EXIT_FAILURE;
      return SVN_NO_ERROR;
    }

  if (mode_opt_count != 1)
    {
      svn_error_clear(svn_cmdline_fputs(
#ifdef WIN32
                      _("You must specify exactly one of -d, -i, -t, "
                        "--service or -X.\n"),
#else
                      _("You must specify exactly one of -d, -i, -t or -X.\n"),
#endif
                       stderr, pool));
      usage(argv[0], pool);
      *exit_code = EXIT_FAILURE;
      return SVN_NO_ERROR;
    }

  if (handling_opt_count > 1)
    {
      svn_error_clear(svn_cmdline_fputs(
                      _("You may only specify one of -T or --single-thread\n"),
                      stderr, pool));
      usage(argv[0], pool);
      *exit_code = EXIT_FAILURE;
      return SVN_NO_ERROR;
    }

  /* construct object pools */
  is_multi_threaded = handling_mode == connection_mode_thread;
  params.fs_config = apr_hash_make(pool);
  svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_CACHE_DELTAS,
                cache_txdeltas ? "1" :"0");
  svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
                cache_fulltexts ? "1" :"0");
  svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
                cache_revprops ? "2" :"0");
  svn_hash_sets(params.fs_config, SVN_FS_CONFIG_FSFS_BLOCK_READ,
                use_block_read ? "1" :"0");

  SVN_ERR(svn_repos__config_pool_create(&params.config_pool,
                                        is_multi_threaded,
                                        pool));
  SVN_ERR(svn_repos__authz_pool_create(&params.authz_pool,
                                       params.config_pool,
                                       is_multi_threaded,
                                       pool));

  /* If a configuration file is specified, load it and any referenced
   * password and authorization files. */
  if (config_filename)
    {
      params.base = svn_dirent_dirname(config_filename, pool);

      SVN_ERR(svn_repos__config_pool_get(&params.cfg, NULL,
                                         params.config_pool,
                                         config_filename,
                                         TRUE, /* must_exist */
                                         FALSE, /* names_case_sensitive */
                                         NULL,
                                         pool));
    }

  if (log_filename)
    SVN_ERR(logger__create(&params.logger, log_filename, pool));
  else if (run_mode == run_mode_listen_once)
    SVN_ERR(logger__create_for_stderr(&params.logger, pool));

  if (params.tunnel_user && run_mode != run_mode_tunnel)
    {
      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
               _("Option --tunnel-user is only valid in tunnel mode"));
    }

  if (run_mode == run_mode_inetd || run_mode == run_mode_tunnel)
    {
      apr_pool_t *connection_pool;
      svn_ra_svn_conn_t *conn;
      svn_stream_t *stdin_stream;
      svn_stream_t *stdout_stream;

      params.tunnel = (run_mode == run_mode_tunnel);
      apr_pool_cleanup_register(pool, pool, apr_pool_cleanup_null,
                                redirect_stdout);

      SVN_ERR(svn_stream_for_stdin(&stdin_stream, pool));
      SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));

      /* Use a subpool for the connection to ensure that if SASL is used
       * the pool cleanup handlers that call sasl_dispose() (connection_pool)
       * and sasl_done() (pool) are run in the right order. See issue #3664. */
      connection_pool = svn_pool_create(pool);
      conn = svn_ra_svn_create_conn4(NULL, stdin_stream, stdout_stream,
                                     params.compression_level,
                                     params.zero_copy_limit,
                                     params.error_check_interval,
                                     connection_pool);
      err = serve(conn, &params, connection_pool);
      svn_pool_destroy(connection_pool);

      return err;
    }

#ifdef WIN32
  /* If svnserve needs to run as a Win32 service, then we need to
     coordinate with the Service Control Manager (SCM) before
     continuing.  This function call registers the svnserve.exe
     process with the SCM, waits for the "start" command from the SCM
     (which will come very quickly), and confirms that those steps
     succeeded.

     After this call succeeds, the service is free to run.  At some
     point in the future, the SCM will send a message to the service,
     requesting that it stop.  This is translated into a call to
     winservice_notify_stop().  The service is then responsible for
     cleanly terminating.

     We need to do this before actually starting the service logic
     (opening files, sockets, etc.) because the SCM wants you to
     connect *first*, then do your service-specific logic.  If the
     service process takes too long to connect to the SCM, then the
     SCM will decide that the service is busted, and will give up on
     it.
     */
  if (run_mode == run_mode_service)
    {
      err = winservice_start();
      if (err)
        {
          svn_handle_error2(err, stderr, FALSE, "svnserve: ");

          /* This is the most common error.  It means the user started
             svnserve from a shell, and specified the --service
             argument.  svnserve cannot be started, as a service, in
             this way.  The --service argument is valid only valid if
             svnserve is started by the SCM. */
          if (err->apr_err ==
              APR_FROM_OS_ERROR(ERROR_FAILED_SERVICE_CONTROLLER_CONNECT))
            {
              svn_error_clear(svn_cmdline_fprintf(stderr, pool,
                  _("svnserve: The --service flag is only valid if the"
                    " process is started by the Service Control Manager.\n")));
            }

          svn_error_clear(err);
          *exit_code = EXIT_FAILURE;
          return SVN_NO_ERROR;
        }

      /* The service is now in the "starting" state.  Before the SCM will
         consider the service "started", this thread must call the
         winservice_running() function. */
    }
#endif /* WIN32 */

  /* Make sure we have IPV6 support first before giving apr_sockaddr_info_get
     APR_UNSPEC, because it may give us back an IPV6 address even if we can't
     create IPV6 sockets. */

#if APR_HAVE_IPV6
#ifdef MAX_SECS_TO_LINGER
  /* ### old APR interface */
  status = apr_socket_create(&sock, APR_INET6, SOCK_STREAM, pool);
#else
  status = apr_socket_create(&sock, APR_INET6, SOCK_STREAM, APR_PROTO_TCP,
                             pool);
#endif
  if (status == 0)
    {
      apr_socket_close(sock);
      family = APR_UNSPEC;

      if (prefer_v6)
        {
          if (host == NULL)
            host = "::";
          sockaddr_info_flags = APR_IPV6_ADDR_OK;
        }
      else
        {
          if (host == NULL)
            host = "0.0.0.0";
          sockaddr_info_flags = APR_IPV4_ADDR_OK;
        }
    }
#endif

  status = apr_sockaddr_info_get(&sa, host, family, port,
                                 sockaddr_info_flags, pool);
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't get address info"));
    }


#ifdef MAX_SECS_TO_LINGER
  /* ### old APR interface */
  status = apr_socket_create(&sock, sa->family, SOCK_STREAM, pool);
#else
  status = apr_socket_create(&sock, sa->family, SOCK_STREAM, APR_PROTO_TCP,
                             pool);
#endif
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't create server socket"));
    }

  /* Prevents "socket in use" errors when server is killed and quickly
   * restarted. */
  status = apr_socket_opt_set(sock, APR_SO_REUSEADDR, 1);
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't set options on server socket"));
    }

  status = apr_socket_bind(sock, sa);
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't bind server socket"));
    }

  status = apr_socket_listen(sock, ACCEPT_BACKLOG);
  if (status)
    {
      return svn_error_wrap_apr(status, _("Can't listen on server socket"));
    }

#if APR_HAS_FORK
  if (run_mode != run_mode_listen_once && !foreground)
    /* ### ignoring errors... */
    apr_proc_detach(APR_PROC_DETACH_DAEMONIZE);

  apr_signal(SIGCHLD, sigchld_handler);
#endif

#ifdef SIGPIPE
  /* Disable SIGPIPE generation for the platforms that have it. */
  apr_signal(SIGPIPE, SIG_IGN);
#endif

#ifdef SIGXFSZ
  /* Disable SIGXFSZ generation for the platforms that have it, otherwise
   * working with large files when compiled against an APR that doesn't have
   * large file support will crash the program, which is uncool. */
  apr_signal(SIGXFSZ, SIG_IGN);
#endif

  if (pid_filename)
    SVN_ERR(write_pid_file(pid_filename, pool));

#ifdef WIN32
  status = apr_os_sock_get(&winservice_svnserve_accept_socket, sock);
  if (status)
    winservice_svnserve_accept_socket = INVALID_SOCKET;

  /* At this point, the service is "running".  Notify the SCM. */
  if (run_mode == run_mode_service)
    winservice_running();
#endif

  /* Configure FS caches for maximum efficiency with svnserve.
   * For pre-forked (i.e. multi-processed) mode of operation,
   * keep the per-process caches smaller than the default.
   * Also, apply the respective command line parameters, if given. */
  {
    svn_cache_config_t settings = *svn_cache_config_get();

    if (params.memory_cache_size != -1)
      settings.cache_size = params.memory_cache_size;

    settings.single_threaded = TRUE;
    if (handling_mode == connection_mode_thread)
      {
#if APR_HAS_THREADS
        settings.single_threaded = FALSE;
#else
        /* No requests will be processed at all
         * (see "switch (handling_mode)" code further down).
         * But if they were, some other synchronization code
         * would need to take care of securing integrity of
         * APR-based structures. That would include our caches.
         */
#endif
      }

    svn_cache_config_set(&settings);
  }

#if APR_HAS_THREADS
  SVN_ERR(svn_root_pools__create(&connection_pools));

  if (handling_mode == connection_mode_thread)
    {
      /* create the thread pool with a valid range of threads */
      if (max_thread_count < 1)
        max_thread_count = 1;
      if (min_thread_count > max_thread_count)
        min_thread_count = max_thread_count;

      status = apr_thread_pool_create(&threads,
                                      min_thread_count,
                                      max_thread_count,
                                      pool);
      if (status)
        {
          return svn_error_wrap_apr(status, _("Can't create thread pool"));
        }

      /* let idle threads linger for a while in case more requests are
         coming in */
      apr_thread_pool_idle_wait_set(threads, THREADPOOL_THREAD_IDLE_LIMIT);

      /* don't queue requests unless we reached the worker thread limit */
      apr_thread_pool_threshold_set(threads, 0);
    }
  else
    {
      threads = NULL;
    }
#endif

  while (1)
    {
      connection_t *connection = NULL;
      SVN_ERR(accept_connection(&connection, sock, &params, handling_mode,
                                pool));
      if (run_mode == run_mode_listen_once)
        {
          err = serve_socket(connection, connection->pool);
          close_connection(connection);
          return err;
        }

      switch (handling_mode)
        {
        case connection_mode_fork:
#if APR_HAS_FORK
          status = apr_proc_fork(&proc, connection->pool);
          if (status == APR_INCHILD)
            {
              /* the child would't listen to the main server's socket */
              apr_socket_close(sock);

              /* serve_socket() logs any error it returns, so ignore it. */
              svn_error_clear(serve_socket(connection, connection->pool));
              close_connection(connection);
              return SVN_NO_ERROR;
            }
          else if (status != APR_INPARENT)
            {
              err = svn_error_wrap_apr(status, "apr_proc_fork");
              logger__log_error(params.logger, err, NULL, NULL);
              svn_error_clear(err);
            }
#endif
          break;

        case connection_mode_thread:
          /* Create a detached thread for each connection.  That's not a
             particularly sophisticated strategy for a threaded server, it's
             little different from forking one process per connection. */
#if APR_HAS_THREADS
          attach_connection(connection);

          status = apr_thread_pool_push(threads, serve_thread, connection,
                                        0, NULL);
          if (status)
            {
              return svn_error_wrap_apr(status, _("Can't push task"));
            }
#endif
          break;

        case connection_mode_single:
          /* Serve one connection at a time. */
          /* serve_socket() logs any error it returns, so ignore it. */
          svn_error_clear(serve_socket(connection, connection->pool));
        }

      close_connection(connection);
    }

  /* NOTREACHED */
}
int
main(int argc, char **argv)
{
  svn_error_t *err;
  apr_status_t apr_err;
  apr_file_t *source_file;
  apr_file_t *target_file;
  svn_stream_t *stdout_stream;
  svn_txdelta_stream_t *txdelta_stream;
  svn_txdelta_window_handler_t svndiff_handler;
  svn_stream_t *encoder;
  void *svndiff_baton;
  apr_pool_t *pool;
  int version = 0;

  if (argc < 3)
    {
      printf("usage: %s source target [version]\n", argv[0]);
      exit(0);
    }

  apr_initialize();
  pool = svn_pool_create(NULL);
  apr_err = apr_file_open(&source_file, argv[1], (APR_READ | APR_BINARY),
                          APR_OS_DEFAULT, pool);
  if (apr_err)
    {
      fprintf(stderr, "unable to open \"%s\" for reading\n", argv[1]);
      exit(1);
    }

  apr_err = apr_file_open(&target_file, argv[2], (APR_READ | APR_BINARY),
                          APR_OS_DEFAULT, pool);
  if (apr_err)
    {
      fprintf(stderr, "unable to open \"%s\" for reading\n", argv[2]);
      exit(1);
    }
  if (argc == 4)
    version = atoi(argv[3]);

  svn_txdelta(&txdelta_stream,
              svn_stream_from_aprfile(source_file, pool),
              svn_stream_from_aprfile(target_file, pool),
              pool);

  err = svn_stream_for_stdout(&stdout_stream, pool);
  if (err)
    svn_handle_error2(err, stdout, TRUE, "svndiff-test: ");

#ifdef QUOPRINT_SVNDIFFS
  encoder = svn_quoprint_encode(stdout_stream, pool);
#else
  encoder = svn_base64_encode(stdout_stream, pool);
#endif
  /* use maximum compression level */
  svn_txdelta_to_svndiff3(&svndiff_handler, &svndiff_baton,
                          encoder, version, 9, pool);
  err = svn_txdelta_send_txstream(txdelta_stream,
                                  svndiff_handler,
                                  svndiff_baton,
                                  pool);
  if (err)
    svn_handle_error2(err, stdout, TRUE, "svndiff-test: ");

  apr_file_close(source_file);
  apr_file_close(target_file);
  svn_pool_destroy(pool);
  apr_terminate();
  exit(0);
}
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__blame(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_pool_t *subpool;
  apr_array_header_t *targets;
  blame_baton_t bl;
  int i;
  svn_boolean_t end_revision_unspecified = FALSE;
  svn_diff_file_options_t *diff_options = svn_diff_file_options_create(pool);
  svn_boolean_t seen_nonexistent_target = FALSE;

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

  /* Blame needs a file on which to operate. */
  if (! targets->nelts)
    return svn_error_create(SVN_ERR_CL_INSUFFICIENT_ARGS, 0, NULL);

  if (opt_state->end_revision.kind == svn_opt_revision_unspecified)
    {
      if (opt_state->start_revision.kind != svn_opt_revision_unspecified)
        {
          /* In the case that -rX was specified, we actually want to set the
             range to be -r1:X. */

          opt_state->end_revision = opt_state->start_revision;
          opt_state->start_revision.kind = svn_opt_revision_number;
          opt_state->start_revision.value.number = 1;
        }
      else
        end_revision_unspecified = TRUE;
    }

  if (opt_state->start_revision.kind == svn_opt_revision_unspecified)
    {
      opt_state->start_revision.kind = svn_opt_revision_number;
      opt_state->start_revision.value.number = 1;
    }

  /* The final conclusion from issue #2431 is that blame info
     is client output (unlike 'svn cat' which plainly cats the file),
     so the EOL style should be the platform local one.
  */
  if (! opt_state->xml)
    SVN_ERR(svn_stream_for_stdout(&bl.out, pool));
  else
    bl.sbuf = svn_stringbuf_create("", pool);

  bl.opt_state = opt_state;

  subpool = svn_pool_create(pool);

  if (opt_state->extensions)
    {
      apr_array_header_t *opts;
      opts = svn_cstring_split(opt_state->extensions, " \t\n\r", TRUE, pool);
      SVN_ERR(svn_diff_file_options_parse(diff_options, opts, pool));
    }

  if (opt_state->xml)
    {
      if (opt_state->verbose)
        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                _("'verbose' option invalid in XML mode"));

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

  for (i = 0; i < targets->nelts; i++)
    {
      svn_error_t *err;
      const char *target = APR_ARRAY_IDX(targets, i, const char *);
      const char *truepath;
      svn_opt_revision_t peg_revision;
      svn_client_blame_receiver3_t receiver;

      svn_pool_clear(subpool);
      SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));

      /* Check for a peg revision. */
      SVN_ERR(svn_opt_parse_path(&peg_revision, &truepath, target,
                                 subpool));

      if (end_revision_unspecified)
        {
          if (peg_revision.kind != svn_opt_revision_unspecified)
            opt_state->end_revision = peg_revision;
          else if (svn_path_is_url(target))
            opt_state->end_revision.kind = svn_opt_revision_head;
          else
            opt_state->end_revision.kind = svn_opt_revision_working;
        }

      if (opt_state->xml)
        {
          /* "<target ...>" */
          /* We don't output this tag immediately, which avoids creating
             a target element if this path is skipped. */
          const char *outpath = truepath;
          if (! svn_path_is_url(target))
            outpath = svn_dirent_local_style(truepath, subpool);
          svn_xml_make_open_tag(&bl.sbuf, pool, svn_xml_normal, "target",
                                "path", outpath, NULL);

          receiver = blame_receiver_xml;
        }
      else
        receiver = blame_receiver;

      err = svn_client_blame5(truepath,
                              &peg_revision,
                              &opt_state->start_revision,
                              &opt_state->end_revision,
                              diff_options,
                              opt_state->force,
                              opt_state->use_merge_history,
                              receiver,
                              &bl,
                              ctx,
                              subpool);

      if (err)
        {
          if (err->apr_err == SVN_ERR_CLIENT_IS_BINARY_FILE)
            {
              svn_error_clear(err);
              SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
                                          _("Skipping binary file: '%s'\n"),
                                          target));
            }
          else if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND ||
                   err->apr_err == SVN_ERR_FS_NOT_FILE ||
                   err->apr_err == SVN_ERR_FS_NOT_FOUND)
            {
              svn_handle_warning2(stderr, err, "svn: ");
              svn_error_clear(err);
              err = NULL;
              seen_nonexistent_target = TRUE;
            }
          else
            {
              return svn_error_trace(err);
            }
        }
      else if (opt_state->xml)
        {
          /* "</target>" */
          svn_xml_make_close_tag(&(bl.sbuf), pool, "target");
          SVN_ERR(svn_cl__error_checked_fputs(bl.sbuf->data, stdout));
        }

      if (opt_state->xml)
        svn_stringbuf_setempty(bl.sbuf);
    }
  svn_pool_destroy(subpool);
  if (opt_state->xml && ! opt_state->incremental)
    SVN_ERR(svn_cl__xml_print_footer("blame", pool));

  if (seen_nonexistent_target)
    return svn_error_create(
      SVN_ERR_ILLEGAL_TARGET, NULL,
      _("Could not perform blame on all targets because some "
        "targets don't exist"));
  else
    return SVN_NO_ERROR;
}
Example #12
0
static void put_playlist_patch(sp_playlist *playlist,
                               struct evhttp_request *request,
                               void *userdata) {
  struct state *state = userdata;
  struct evbuffer *buf = evhttp_request_get_input_buffer(request);
  size_t buflen = evbuffer_get_length(buf);

  if (buflen == 0) {
    send_error(request, HTTP_BADREQUEST, "No body");
    return;
  }

  // Read request body
  json_error_t loads_error;
  json_t *json = read_request_body_json(request, &loads_error);

  if (json == NULL) {
    send_error(request, HTTP_BADREQUEST,
               loads_error.text ? loads_error.text : "Unable to parse JSON");
    return;
  }

  if (!json_is_array(json)) {
    json_decref(json);
    send_error(request, HTTP_BADREQUEST, "Not valid JSON array");
    return;
  }

  // Handle empty array
  int num_tracks = json_array_size(json);

  if (num_tracks == 0) {
    send_reply(request, HTTP_OK, "OK", NULL);
    return;
  }

  const sp_track **tracks = calloc(num_tracks, sizeof (sp_track *));
  int num_valid_tracks = 0;

  for (int i = 0; i < num_tracks; i++) {
    json_t *item = json_array_get(json, i);

    if (!json_is_string(item)) {
      json_decref(item);
      continue;
    }

    char *uri = strdup(json_string_value(item));
    sp_link *track_link = sp_link_create_from_string(uri);
    free(uri);

    if (track_link == NULL)
      continue;

    if (sp_link_type(track_link) != SP_LINKTYPE_TRACK) {
      sp_link_release(track_link);
      continue;
    }

    sp_track *track = sp_link_as_track(track_link);
    
    if (track == NULL)
      continue;

    tracks[num_valid_tracks++] = track;
  }

  json_decref(json);
  
  // Bail if no tracks could be read from input
  if (num_valid_tracks == 0) {
    send_error(request, HTTP_BADREQUEST, "No valid tracks");
    free(tracks);
    return;
  }

  tracks = realloc(tracks, num_valid_tracks * sizeof (sp_track *));

  // Apply diff
  apr_pool_t *pool = state->pool;
  svn_diff_t *diff;
  svn_error_t *diff_error = diff_playlist_tracks(&diff, playlist, tracks, 
                                                 num_valid_tracks, pool); 

  if (diff_error != SVN_NO_ERROR) {
    free(tracks);
    svn_handle_error2(diff_error, stderr, false, "Diff");
    send_error(request, HTTP_BADREQUEST, "Search failed");
    return;
  }

  svn_error_t *apply_error = diff_playlist_tracks_apply(diff, playlist, tracks,
                                                        num_valid_tracks,
                                                        state->session);

  svn_stream_t *out;
  svn_stream_for_stdout(&out, pool);
  diff_output_stdout(out, diff, playlist, tracks, num_valid_tracks, pool);

  if (apply_error != SVN_NO_ERROR) {
    free(tracks);
    svn_handle_error2(apply_error, stderr, false, "Updating playlist");
    send_error(request, HTTP_BADREQUEST, "Could not apply diff");
    return;
  }

  if (!sp_playlist_has_pending_changes(playlist)) {
    free(tracks);
    get_playlist(playlist, request, NULL);
    return;
  }

  free(tracks);
  register_playlist_callbacks(playlist, request, &get_playlist,
                              &playlist_update_in_progress_callbacks, NULL);
}