Пример #1
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_add4(target,
                               opt_state->depth,
                               opt_state->force, opt_state->no_ignore,
                               opt_state->parents, ctx, iterpool),
               errors, opt_state->quiet,
               SVN_ERR_ENTRY_EXISTS,
               SVN_ERR_WC_PATH_NOT_FOUND,
               SVN_NO_ERROR));
    }

  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;
}
Пример #2
0
static svn_error_t *
start_element(int *elem, void *baton, int parent_state, const char *nspace,
              const char *elt_name, const char **atts)
{
  replay_baton_t *rb = baton;

  const svn_ra_neon__xml_elm_t *elm
    = svn_ra_neon__lookup_xml_elem(editor_report_elements, nspace, elt_name);

  if (! elm)
    {
      *elem = NE_XML_DECLINE;
      return SVN_NO_ERROR;
    }

  if (parent_state == ELEM_root)
    {
      /* If we're at the root of the tree, the element has to be the editor
       * report itself. */
      if (elm->id != ELEM_editor_report)
        return UNEXPECTED_ELEMENT(nspace, elt_name);
    }
  else if (parent_state != ELEM_editor_report)
    {
      /* If we're not at the root, our parent has to be the editor report,
       * since we don't actually nest any elements. */
      return UNEXPECTED_ELEMENT(nspace, elt_name);
    }

  switch (elm->id)
    {
    case ELEM_target_revision:
      {
        const char *crev = svn_xml_get_attr_value("rev", atts);
        if (! crev)
          return MISSING_ATTR(nspace, elt_name, "rev");
        else
          return rb->editor->set_target_revision(rb->edit_baton,
                                                 SVN_STR_TO_REV(crev),
                                                 rb->pool);
      }
      break;

    case ELEM_open_root:
      {
        const char *crev = svn_xml_get_attr_value("rev", atts);

        if (! crev)
          return MISSING_ATTR(nspace, elt_name, "rev");
        else
          {
            apr_pool_t *subpool = svn_pool_create(rb->pool);
            void *dir_baton;
            SVN_ERR(rb->editor->open_root(rb->edit_baton,
                                          SVN_STR_TO_REV(crev), subpool,
                                          &dir_baton));
            push_dir(rb, dir_baton, "", subpool);
          }
      }
      break;

    case ELEM_delete_entry:
      {
        const char *path = svn_xml_get_attr_value("name", atts);
        const char *crev = svn_xml_get_attr_value("rev", atts);

        if (! path)
          return MISSING_ATTR(nspace, elt_name, "name");
        else if (! crev)
          return MISSING_ATTR(nspace, elt_name, "rev");
        else
          {
            dir_item_t *di = &TOP_DIR(rb);

            SVN_ERR(rb->editor->delete_entry(path, SVN_STR_TO_REV(crev),
                                             di->baton, di->pool));
          }
      }
      break;

    case ELEM_open_directory:
    case ELEM_add_directory:
      {
        const char *crev = svn_xml_get_attr_value("rev", atts);
        const char *name = svn_xml_get_attr_value("name", atts);

        if (! name)
          return MISSING_ATTR(nspace, elt_name, "name");
        else
          {
            dir_item_t *parent = &TOP_DIR(rb);
            apr_pool_t *subpool = svn_pool_create(parent->pool);
            svn_revnum_t rev;
            void *dir_baton;

            if (crev)
              rev = SVN_STR_TO_REV(crev);
            else
              rev = SVN_INVALID_REVNUM;

            if (elm->id == ELEM_open_directory)
              SVN_ERR(rb->editor->open_directory(name, parent->baton,
                                                 rev, subpool, &dir_baton));
            else if (elm->id == ELEM_add_directory)
              {
                const char *cpath = svn_xml_get_attr_value("copyfrom-path",
                                                           atts);

                crev = svn_xml_get_attr_value("copyfrom-rev", atts);

                if (crev)
                  rev = SVN_STR_TO_REV(crev);
                else
                  rev = SVN_INVALID_REVNUM;

                SVN_ERR(rb->editor->add_directory(name, parent->baton,
                                                  cpath, rev, subpool,
                                                  &dir_baton));
              }
            else
              SVN_ERR_MALFUNCTION();

            push_dir(rb, dir_baton, name, subpool);
          }
      }
      break;

    case ELEM_open_file:
    case ELEM_add_file:
      {
        const char *path = svn_xml_get_attr_value("name", atts);
        svn_revnum_t rev;

        dir_item_t *parent = &TOP_DIR(rb);

        if (! path)
          return MISSING_ATTR(nspace, elt_name, "name");

        svn_pool_clear(parent->file_pool);

        if (elm->id == ELEM_add_file)
          {
            const char *cpath = svn_xml_get_attr_value("copyfrom-path", atts);
            const char *crev = svn_xml_get_attr_value("copyfrom-rev", atts);

            if (crev)
              rev = SVN_STR_TO_REV(crev);
            else
              rev = SVN_INVALID_REVNUM;

            SVN_ERR(rb->editor->add_file(path, parent->baton, cpath, rev,
                                         parent->file_pool, &rb->file_baton));
          }
        else
          {
            const char *crev = svn_xml_get_attr_value("rev", atts);

            if (crev)
              rev = SVN_STR_TO_REV(crev);
            else
              rev = SVN_INVALID_REVNUM;

            SVN_ERR(rb->editor->open_file(path, parent->baton, rev,
                                          parent->file_pool,
                                          &rb->file_baton));
          }
      }
      break;

    case ELEM_apply_textdelta:
      if (! rb->file_baton)
        return svn_error_create
                 (SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
                  _("Got apply-textdelta element without preceding "
                    "add-file or open-file"));
      else
        {
          const char *checksum = svn_xml_get_attr_value("checksum", atts);

          SVN_ERR(rb->editor->apply_textdelta(rb->file_baton,
                                              checksum,
                                              TOP_DIR(rb).file_pool,
                                              &rb->whandler,
                                              &rb->whandler_baton));

          rb->svndiff_decoder = svn_txdelta_parse_svndiff
                                  (rb->whandler, rb->whandler_baton,
                                   TRUE, TOP_DIR(rb).file_pool);
          rb->base64_decoder = svn_base64_decode(rb->svndiff_decoder,
                                                 TOP_DIR(rb).file_pool);
        }
      break;

    case ELEM_close_file:
      if (! rb->file_baton)
        return svn_error_create
                  (SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
                   _("Got close-file element without preceding "
                     "add-file or open-file"));
      else
        {
          const char *checksum = svn_xml_get_attr_value("checksum", atts);

          SVN_ERR(rb->editor->close_file(rb->file_baton,
                                         checksum,
                                         TOP_DIR(rb).file_pool));
          rb->file_baton = NULL;
        }
      break;

    case ELEM_close_directory:
      if (rb->dirs->nelts == 0)
        return svn_error_create
                 (SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
                  _("Got close-directory element without ever opening "
                    "a directory"));
      else
        {
          dir_item_t *di = &TOP_DIR(rb);

          SVN_ERR(rb->editor->close_directory(di->baton, di->pool));

          svn_pool_destroy(di->pool);

          apr_array_pop(rb->dirs);
        }
      break;

    case ELEM_change_file_prop:
    case ELEM_change_dir_prop:
      {
        const char *name = svn_xml_get_attr_value("name", atts);

        if (! name)
          return MISSING_ATTR(nspace, elt_name, "name");
        else
          {
            svn_pool_clear(rb->prop_pool);

            if (svn_xml_get_attr_value("del", atts))
              rb->prop_accum = NULL;
            else
              rb->prop_accum = svn_stringbuf_create("", rb->prop_pool);

            rb->prop_name = apr_pstrdup(rb->prop_pool, name);
          }
      }
      break;
    }

  *elem = elm->id;

  return SVN_NO_ERROR;
}
Пример #3
0
/* This implements the svn_client_list_func_t API, printing a single dirent
   in XML format. */
static svn_error_t *
print_dirent_xml(void *baton,
                 const char *path,
                 const svn_dirent_t *dirent,
                 const svn_lock_t *lock,
                 const char *abs_path,
                 apr_pool_t *pool)
{
  struct print_baton *pb = baton;
  const char *entryname;
  svn_stringbuf_t *sb;

  if (strcmp(path, "") == 0)
    {
      if (dirent->kind == svn_node_file)
        entryname = svn_dirent_basename(abs_path, pool);
      else if (pb->verbose)
        entryname = ".";
      else
        /* Don't bother to list if no useful information will be shown. */
        return SVN_NO_ERROR;
    }
  else
    entryname = path;

  if (pb->ctx->cancel_func)
    SVN_ERR(pb->ctx->cancel_func(pb->ctx->cancel_baton));

  sb = svn_stringbuf_create("", pool);

  svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry",
                        "kind", svn_cl__node_kind_str_xml(dirent->kind),
                        NULL);

  svn_cl__xml_tagged_cdata(&sb, pool, "name", entryname);

  if (dirent->kind == svn_node_file)
    {
      svn_cl__xml_tagged_cdata
        (&sb, pool, "size",
         apr_psprintf(pool, "%" SVN_FILESIZE_T_FMT, dirent->size));
    }

  svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "commit",
                        "revision",
                        apr_psprintf(pool, "%ld", dirent->created_rev),
                        NULL);
  svn_cl__xml_tagged_cdata(&sb, pool, "author", dirent->last_author);
  if (dirent->time)
    svn_cl__xml_tagged_cdata(&sb, pool, "date",
                             svn_time_to_cstring(dirent->time, pool));
  svn_xml_make_close_tag(&sb, pool, "commit");

  if (lock)
    {
      svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "lock", NULL);
      svn_cl__xml_tagged_cdata(&sb, pool, "token", lock->token);
      svn_cl__xml_tagged_cdata(&sb, pool, "owner", lock->owner);
      svn_cl__xml_tagged_cdata(&sb, pool, "comment", lock->comment);
      svn_cl__xml_tagged_cdata(&sb, pool, "created",
                               svn_time_to_cstring(lock->creation_date,
                                                   pool));
      if (lock->expiration_date != 0)
        svn_cl__xml_tagged_cdata(&sb, pool, "expires",
                                 svn_time_to_cstring
                                 (lock->expiration_date, pool));
      svn_xml_make_close_tag(&sb, pool, "lock");
    }

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

  return svn_cl__error_checked_fputs(sb->data, stdout);
}
Пример #4
0
svn_error_t *cyrus_auth_request(svn_ra_svn_conn_t *conn,
                                apr_pool_t *pool,
                                server_baton_t *b,
                                enum access_type required,
                                svn_boolean_t needs_username)
{
  sasl_conn_t *sasl_ctx;
  apr_pool_t *subpool;
  apr_status_t apr_err;
  const char *localaddrport = NULL, *remoteaddrport = NULL;
  const char *mechlist;
  char hostname[APRMAXHOSTLEN + 1];
  sasl_security_properties_t secprops;
  svn_boolean_t success, no_anonymous;
  int mech_count, result = SASL_OK;

  SVN_ERR(svn_ra_svn__get_addresses(&localaddrport, &remoteaddrport,
                                        conn, pool));
  apr_err = apr_gethostname(hostname, sizeof(hostname), pool);
  if (apr_err)
    {
      svn_error_t *err = svn_error_wrap_apr(apr_err, _("Can't get hostname"));
      SVN_ERR(write_failure(conn, pool, &err));
      return svn_ra_svn__flush(conn, pool);
    }

  /* Create a SASL context. SASL_SUCCESS_DATA tells SASL that the protocol
     supports sending data along with the final "success" message. */
  result = svn_sasl__server_new(SVN_RA_SVN_SASL_NAME,
                                hostname, b->repository->realm,
                                localaddrport, remoteaddrport,
                                NULL, SASL_SUCCESS_DATA,
                                &sasl_ctx);
  if (result != SASL_OK)
    {
      svn_error_t *err = svn_error_create(
          SVN_ERR_RA_NOT_AUTHORIZED, NULL,
          svn_sasl__errstring(result, NULL, NULL));
      SVN_ERR(write_failure(conn, pool, &err));
      return svn_ra_svn__flush(conn, pool);
    }

  /* Make sure the context is always destroyed. */
  apr_pool_cleanup_register(b->pool, sasl_ctx, sasl_dispose_cb,
                            apr_pool_cleanup_null);

  /* Initialize security properties. */
  svn_ra_svn__default_secprops(&secprops);

  /* Don't allow ANONYMOUS if a username is required. */
  no_anonymous = needs_username || b->repository->anon_access < required;
  if (no_anonymous)
    secprops.security_flags |= SASL_SEC_NOANONYMOUS;

  secprops.min_ssf = b->repository->min_ssf;
  secprops.max_ssf = b->repository->max_ssf;

  /* Set security properties. */
  result = svn_sasl__setprop(sasl_ctx, SASL_SEC_PROPS, &secprops);
  if (result != SASL_OK)
    return fail_cmd(conn, pool, sasl_ctx);

  /* SASL needs to know if we are externally authenticated. */
  if (b->client_info->tunnel_user)
    result = svn_sasl__setprop(sasl_ctx, SASL_AUTH_EXTERNAL,
                               b->client_info->tunnel_user);
  if (result != SASL_OK)
    return fail_cmd(conn, pool, sasl_ctx);

  /* Get the list of mechanisms. */
  result = svn_sasl__listmech(sasl_ctx, NULL, NULL, " ", NULL,
                              &mechlist, NULL, &mech_count);

  if (result != SASL_OK)
    return fail_cmd(conn, pool, sasl_ctx);

  if (mech_count == 0)
    {
      svn_error_t *err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                          _("Could not obtain the list"
                                          " of SASL mechanisms"));
      SVN_ERR(write_failure(conn, pool, &err));
      return svn_ra_svn__flush(conn, pool);
    }

  /* Send the list of mechanisms and the realm to the client. */
  SVN_ERR(svn_ra_svn__write_cmd_response(conn, pool, "(w)c",
                                         mechlist, b->repository->realm));

  /* The main authentication loop. */
  subpool = svn_pool_create(pool);
  do
    {
      svn_pool_clear(subpool);
      SVN_ERR(try_auth(conn, sasl_ctx, subpool, b, &success));
    }
  while (!success);
  svn_pool_destroy(subpool);

  SVN_ERR(svn_ra_svn__enable_sasl_encryption(conn, sasl_ctx, pool));

  if (no_anonymous)
    {
      char *p;
      const void *user;

      /* Get the authenticated username. */
      result = svn_sasl__getprop(sasl_ctx, SASL_USERNAME, &user);

      if (result != SASL_OK)
        return fail_cmd(conn, pool, sasl_ctx);

      if ((p = strchr(user, '@')) != NULL)
        {
          /* Drop the realm part. */
          b->client_info->user = apr_pstrndup(b->pool, user,
                                              p - (const char *)user);
        }
      else
        {
          svn_error_t *err;
          err = svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                 _("Couldn't obtain the authenticated"
                                 " username"));
          SVN_ERR(write_failure(conn, pool, &err));
          return svn_ra_svn__flush(conn, pool);
        }
    }

  return SVN_NO_ERROR;
}
Пример #5
0
/* This helper is the main "meat" of the editor -- it does all the
   work of writing a node record.

   Write out a node record for PATH of type KIND under EB->FS_ROOT.
   ACTION describes what is happening to the node (see enum svn_node_action).
   Write record to writable EB->STREAM, using EB->BUFFER to write in chunks.

   If the node was itself copied, IS_COPY is TRUE and the
   path/revision of the copy source are in CMP_PATH/CMP_REV.  If
   IS_COPY is FALSE, yet CMP_PATH/CMP_REV are valid, this node is part
   of a copied subtree.
  */
static svn_error_t *
dump_node(struct edit_baton *eb,
          const char *path,
          svn_node_kind_t kind,
          enum svn_node_action action,
          svn_boolean_t is_copy,
          const char *cmp_path,
          svn_revnum_t cmp_rev,
          apr_pool_t *pool)
{
  svn_stringbuf_t *propstring;
  svn_filesize_t content_length = 0;
  apr_size_t len;
  svn_boolean_t must_dump_text = FALSE, must_dump_props = FALSE;
  const char *compare_path = path;
  svn_revnum_t compare_rev = eb->current_rev - 1;
  svn_fs_root_t *compare_root = NULL;
  apr_file_t *delta_file = NULL;

  /* Maybe validate the path. */
  if (eb->verify || eb->notify_func)
    {
      svn_error_t *err = svn_fs__path_valid(path, pool);

      if (err)
        {
          if (eb->notify_func)
            {
              char errbuf[512]; /* ### svn_strerror() magic number  */
              svn_repos_notify_t *notify;
              notify = svn_repos_notify_create(svn_repos_notify_warning, pool);

              notify->warning = svn_repos_notify_warning_invalid_fspath;
              notify->warning_str = apr_psprintf(
                     pool,
                     _("E%06d: While validating fspath '%s': %s"),
                     err->apr_err, path,
                     svn_err_best_message(err, errbuf, sizeof(errbuf)));

              eb->notify_func(eb->notify_baton, notify, pool);
            }

          /* Return the error in addition to notifying about it. */
          if (eb->verify)
            return svn_error_trace(err);
          else
            svn_error_clear(err);
        }
    }

  /* Write out metadata headers for this file node. */
  SVN_ERR(svn_stream_printf(eb->stream, pool,
                            SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n",
                            path));
  if (kind == svn_node_file)
    SVN_ERR(svn_stream_printf(eb->stream, pool,
                              SVN_REPOS_DUMPFILE_NODE_KIND ": file\n"));
  else if (kind == svn_node_dir)
    SVN_ERR(svn_stream_printf(eb->stream, pool,
                              SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n"));

  /* Remove leading slashes from copyfrom paths. */
  if (cmp_path)
    cmp_path = svn_relpath_canonicalize(cmp_path, pool);

  /* Validate the comparison path/rev. */
  if (ARE_VALID_COPY_ARGS(cmp_path, cmp_rev))
    {
      compare_path = cmp_path;
      compare_rev = cmp_rev;
    }

  if (action == svn_node_action_change)
    {
      SVN_ERR(svn_stream_printf(eb->stream, pool,
                                SVN_REPOS_DUMPFILE_NODE_ACTION
                                ": change\n"));

      /* either the text or props changed, or possibly both. */
      SVN_ERR(svn_fs_revision_root(&compare_root,
                                   svn_fs_root_fs(eb->fs_root),
                                   compare_rev, pool));

      SVN_ERR(svn_fs_props_changed(&must_dump_props,
                                   compare_root, compare_path,
                                   eb->fs_root, path, pool));
      if (kind == svn_node_file)
        SVN_ERR(svn_fs_contents_changed(&must_dump_text,
                                        compare_root, compare_path,
                                        eb->fs_root, path, pool));
    }
  else if (action == svn_node_action_replace)
    {
      if (! is_copy)
        {
          /* a simple delete+add, implied by a single 'replace' action. */
          SVN_ERR(svn_stream_printf(eb->stream, pool,
                                    SVN_REPOS_DUMPFILE_NODE_ACTION
                                    ": replace\n"));

          /* definitely need to dump all content for a replace. */
          if (kind == svn_node_file)
            must_dump_text = TRUE;
          must_dump_props = TRUE;
        }
      else
        {
          /* more complex:  delete original, then add-with-history.  */

          /* the path & kind headers have already been printed;  just
             add a delete action, and end the current record.*/
          SVN_ERR(svn_stream_printf(eb->stream, pool,
                                    SVN_REPOS_DUMPFILE_NODE_ACTION
                                    ": delete\n\n"));

          /* recurse:  print an additional add-with-history record. */
          SVN_ERR(dump_node(eb, path, kind, svn_node_action_add,
                            is_copy, compare_path, compare_rev, pool));

          /* we can leave this routine quietly now, don't need to dump
             any content;  that was already done in the second record. */
          must_dump_text = FALSE;
          must_dump_props = FALSE;
        }
    }
  else if (action == svn_node_action_delete)
    {
      SVN_ERR(svn_stream_printf(eb->stream, pool,
                                SVN_REPOS_DUMPFILE_NODE_ACTION
                                ": delete\n"));

      /* we can leave this routine quietly now, don't need to dump
         any content. */
      must_dump_text = FALSE;
      must_dump_props = FALSE;
    }
  else if (action == svn_node_action_add)
    {
      SVN_ERR(svn_stream_printf(eb->stream, pool,
                                SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));

      if (! is_copy)
        {
          /* Dump all contents for a simple 'add'. */
          if (kind == svn_node_file)
            must_dump_text = TRUE;
          must_dump_props = TRUE;
        }
      else
        {
          if (!eb->verify && cmp_rev < eb->oldest_dumped_rev
              && eb->notify_func)
            {
              svn_repos_notify_t *notify =
                    svn_repos_notify_create(svn_repos_notify_warning, pool);

              notify->warning = svn_repos_notify_warning_found_old_reference;
              notify->warning_str = apr_psprintf(
                     pool,
                     _("Referencing data in revision %ld,"
                       " which is older than the oldest"
                       " dumped revision (r%ld).  Loading this dump"
                       " into an empty repository"
                       " will fail."),
                     cmp_rev, eb->oldest_dumped_rev);
              eb->found_old_reference = TRUE;
              eb->notify_func(eb->notify_baton, notify, pool);
            }

          SVN_ERR(svn_stream_printf(eb->stream, pool,
                                    SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV
                                    ": %ld\n"
                                    SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH
                                    ": %s\n",
                                    cmp_rev, cmp_path));

          SVN_ERR(svn_fs_revision_root(&compare_root,
                                       svn_fs_root_fs(eb->fs_root),
                                       compare_rev, pool));

          /* Need to decide if the copied node had any extra textual or
             property mods as well.  */
          SVN_ERR(svn_fs_props_changed(&must_dump_props,
                                       compare_root, compare_path,
                                       eb->fs_root, path, pool));
          if (kind == svn_node_file)
            {
              svn_checksum_t *checksum;
              const char *hex_digest;
              SVN_ERR(svn_fs_contents_changed(&must_dump_text,
                                              compare_root, compare_path,
                                              eb->fs_root, path, pool));

              SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5,
                                           compare_root, compare_path,
                                           FALSE, pool));
              hex_digest = svn_checksum_to_cstring(checksum, pool);
              if (hex_digest)
                SVN_ERR(svn_stream_printf(eb->stream, pool,
                                      SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_MD5
                                      ": %s\n", hex_digest));

              SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1,
                                           compare_root, compare_path,
                                           FALSE, pool));
              hex_digest = svn_checksum_to_cstring(checksum, pool);
              if (hex_digest)
                SVN_ERR(svn_stream_printf(eb->stream, pool,
                                      SVN_REPOS_DUMPFILE_TEXT_COPY_SOURCE_SHA1
                                      ": %s\n", hex_digest));
            }
        }
    }

  if ((! must_dump_text) && (! must_dump_props))
    {
      /* If we're not supposed to dump text or props, so be it, we can
         just go home.  However, if either one needs to be dumped,
         then our dumpstream format demands that at a *minimum*, we
         see a lone "PROPS-END" as a divider between text and props
         content within the content-block. */
      len = 2;
      return svn_stream_write(eb->stream, "\n\n", &len); /* ### needed? */
    }

  /*** Start prepping content to dump... ***/

  /* If we are supposed to dump properties, write out a property
     length header and generate a stringbuf that contains those
     property values here. */
  if (must_dump_props)
    {
      apr_hash_t *prophash, *oldhash = NULL;
      apr_size_t proplen;
      svn_stream_t *propstream;

      SVN_ERR(svn_fs_node_proplist(&prophash, eb->fs_root, path, pool));

      /* If this is a partial dump, then issue a warning if we dump mergeinfo
         properties that refer to revisions older than the first revision
         dumped. */
      if (!eb->verify && eb->notify_func && eb->oldest_dumped_rev > 1)
        {
          svn_string_t *mergeinfo_str = apr_hash_get(prophash,
                                                     SVN_PROP_MERGEINFO,
                                                     APR_HASH_KEY_STRING);
          if (mergeinfo_str)
            {
              svn_mergeinfo_t mergeinfo, old_mergeinfo;

              SVN_ERR(svn_mergeinfo_parse(&mergeinfo, mergeinfo_str->data,
                                          pool));
              SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
                &old_mergeinfo, mergeinfo,
                eb->oldest_dumped_rev - 1, 0,
                TRUE, pool, pool));
              if (apr_hash_count(old_mergeinfo))
                {
                  svn_repos_notify_t *notify =
                    svn_repos_notify_create(svn_repos_notify_warning, pool);

                  notify->warning = svn_repos_notify_warning_found_old_mergeinfo;
                  notify->warning_str = apr_psprintf(
                    pool,
                    _("Mergeinfo referencing revision(s) prior "
                      "to the oldest dumped revision (r%ld). "
                      "Loading this dump may result in invalid "
                      "mergeinfo."),
                    eb->oldest_dumped_rev);

                  eb->found_old_mergeinfo = TRUE;
                  eb->notify_func(eb->notify_baton, notify, pool);
                }
            }
        }

      if (eb->use_deltas && compare_root)
        {
          /* Fetch the old property hash to diff against and output a header
             saying that our property contents are a delta. */
          SVN_ERR(svn_fs_node_proplist(&oldhash, compare_root, compare_path,
                                       pool));
          SVN_ERR(svn_stream_printf(eb->stream, pool,
                                    SVN_REPOS_DUMPFILE_PROP_DELTA
                                    ": true\n"));
        }
      else
        oldhash = apr_hash_make(pool);
      propstring = svn_stringbuf_create_ensure(0, pool);
      propstream = svn_stream_from_stringbuf(propstring, pool);
      SVN_ERR(svn_hash_write_incremental(prophash, oldhash, propstream,
                                         "PROPS-END", pool));
      SVN_ERR(svn_stream_close(propstream));
      proplen = propstring->len;
      content_length += proplen;
      SVN_ERR(svn_stream_printf(eb->stream, pool,
                                SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
                                ": %" APR_SIZE_T_FMT "\n", proplen));
    }

  /* If we are supposed to dump text, write out a text length header
     here, and an MD5 checksum (if available). */
  if (must_dump_text && (kind == svn_node_file))
    {
      svn_checksum_t *checksum;
      const char *hex_digest;
      svn_filesize_t textlen;

      if (eb->use_deltas)
        {
          /* Compute the text delta now and write it into a temporary
             file, so that we can find its length.  Output a header
             saying our text contents are a delta. */
          SVN_ERR(store_delta(&delta_file, &textlen, compare_root,
                              compare_path, eb->fs_root, path, pool));
          SVN_ERR(svn_stream_printf(eb->stream, pool,
                                    SVN_REPOS_DUMPFILE_TEXT_DELTA
                                    ": true\n"));

          if (compare_root)
            {
              SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5,
                                           compare_root, compare_path,
                                           FALSE, pool));
              hex_digest = svn_checksum_to_cstring(checksum, pool);
              if (hex_digest)
                SVN_ERR(svn_stream_printf(eb->stream, pool,
                                          SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_MD5
                                          ": %s\n", hex_digest));

              SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1,
                                           compare_root, compare_path,
                                           FALSE, pool));
              hex_digest = svn_checksum_to_cstring(checksum, pool);
              if (hex_digest)
                SVN_ERR(svn_stream_printf(eb->stream, pool,
                                      SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_SHA1
                                      ": %s\n", hex_digest));
            }
        }
      else
        {
          /* Just fetch the length of the file. */
          SVN_ERR(svn_fs_file_length(&textlen, eb->fs_root, path, pool));
        }

      content_length += textlen;
      SVN_ERR(svn_stream_printf(eb->stream, pool,
                                SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH
                                ": %" SVN_FILESIZE_T_FMT "\n", textlen));

      SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_md5,
                                   eb->fs_root, path, FALSE, pool));
      hex_digest = svn_checksum_to_cstring(checksum, pool);
      if (hex_digest)
        SVN_ERR(svn_stream_printf(eb->stream, pool,
                                  SVN_REPOS_DUMPFILE_TEXT_CONTENT_MD5
                                  ": %s\n", hex_digest));

      SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1,
                                   eb->fs_root, path, FALSE, pool));
      hex_digest = svn_checksum_to_cstring(checksum, pool);
      if (hex_digest)
        SVN_ERR(svn_stream_printf(eb->stream, pool,
                                  SVN_REPOS_DUMPFILE_TEXT_CONTENT_SHA1
                                  ": %s\n", hex_digest));
    }

  /* 'Content-length:' is the last header before we dump the content,
     and is the sum of the text and prop contents lengths.  We write
     this only for the benefit of non-Subversion RFC-822 parsers. */
  SVN_ERR(svn_stream_printf(eb->stream, pool,
                            SVN_REPOS_DUMPFILE_CONTENT_LENGTH
                            ": %" SVN_FILESIZE_T_FMT "\n\n",
                            content_length));

  /* Dump property content if we're supposed to do so. */
  if (must_dump_props)
    {
      len = propstring->len;
      SVN_ERR(svn_stream_write(eb->stream, propstring->data, &len));
    }

  /* Dump text content */
  if (must_dump_text && (kind == svn_node_file))
    {
      svn_stream_t *contents;

      if (delta_file)
        {
          /* Make sure to close the underlying file when the stream is
             closed. */
          contents = svn_stream_from_aprfile2(delta_file, FALSE, pool);
        }
      else
        SVN_ERR(svn_fs_file_contents(&contents, eb->fs_root, path, pool));

      SVN_ERR(svn_stream_copy3(contents, svn_stream_disown(eb->stream, pool),
                               NULL, NULL, pool));
    }

  len = 2;
  return svn_stream_write(eb->stream, "\n\n", &len); /* ### needed? */
}
Пример #6
0
svn_error_t *
svn_ra_serf__get_location_segments(svn_ra_session_t *ra_session,
                                   const char *path,
                                   svn_revnum_t peg_revision,
                                   svn_revnum_t start_rev,
                                   svn_revnum_t end_rev,
                                   svn_location_segment_receiver_t receiver,
                                   void *receiver_baton,
                                   apr_pool_t *pool)
{
  gls_context_t *gls_ctx;
  svn_ra_serf__session_t *session = ra_session->priv;
  svn_ra_serf__handler_t *handler;
  svn_ra_serf__xml_parser_t *parser_ctx;
  serf_bucket_t *buckets;
  const char *relative_url, *basecoll_url, *req_url;
  svn_error_t *err;

  gls_ctx = apr_pcalloc(pool, sizeof(*gls_ctx));
  gls_ctx->receiver = receiver;
  gls_ctx->receiver_baton = receiver_baton;
  gls_ctx->subpool = svn_pool_create(pool);
  gls_ctx->inside_report = FALSE;
  gls_ctx->error = SVN_NO_ERROR;
  gls_ctx->done = FALSE;

  buckets = serf_bucket_aggregate_create(session->bkt_alloc);

  svn_ra_serf__add_open_tag_buckets(buckets, session->bkt_alloc,
                                    "S:get-location-segments",
                                    "xmlns:S", SVN_XML_NAMESPACE,
                                    NULL);

  svn_ra_serf__add_tag_buckets(buckets,
                               "S:path", path,
                               session->bkt_alloc);

  svn_ra_serf__add_tag_buckets(buckets,
                               "S:peg-revision",
                               apr_ltoa(pool, peg_revision),
                               session->bkt_alloc);

  svn_ra_serf__add_tag_buckets(buckets,
                               "S:start-revision",
                               apr_ltoa(pool, start_rev),
                               session->bkt_alloc);

  svn_ra_serf__add_tag_buckets(buckets,
                               "S:end-revision",
                               apr_ltoa(pool, end_rev),
                               session->bkt_alloc);

  svn_ra_serf__add_close_tag_buckets(buckets, session->bkt_alloc,
                                     "S:get-location-segments");

  SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url, session,
                                         NULL, NULL, peg_revision, NULL, pool));

  req_url = svn_path_url_add_component(basecoll_url, relative_url, pool);

  handler = apr_pcalloc(pool, sizeof(*handler));

  handler->method = "REPORT";
  handler->path = req_url;
  handler->body_buckets = buckets;
  handler->body_type = "text/xml";
  handler->conn = session->conns[0];
  handler->session = session;

  parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));

  parser_ctx->pool = pool;
  parser_ctx->user_data = gls_ctx;
  parser_ctx->start = start_gls;
  parser_ctx->end = end_gls;
  parser_ctx->status_code = &gls_ctx->status_code;
  parser_ctx->done = &gls_ctx->done;

  handler->response_handler = svn_ra_serf__handle_xml_parser;
  handler->response_baton = parser_ctx;

  svn_ra_serf__request_create(handler);

  err = svn_ra_serf__context_run_wait(&gls_ctx->done, session, pool);

  if (gls_ctx->error || parser_ctx->error)
    {
      svn_error_clear(err);
      err = SVN_NO_ERROR;
      SVN_ERR(gls_ctx->error);
      SVN_ERR(parser_ctx->error);
    }

  if (gls_ctx->inside_report)
    err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
                            _("Location segment report failed on '%s'@'%ld'"),
                              path, peg_revision);

  SVN_ERR(svn_ra_serf__error_on_status(gls_ctx->status_code, handler->path));

  svn_pool_destroy(gls_ctx->subpool);

  if (err && (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE))
    return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, err, NULL);

  return err;
}
Пример #7
0
svn_error_t *cyrus_init(apr_pool_t *pool)
{
  SVN_ERR(svn_atomic__init_once(&svn_ra_svn__sasl_status,
                                initialize, NULL, pool));
  return SVN_NO_ERROR;
}
Пример #8
0
svn_error_t *
svn_client_info2(const char *path_or_url,
                 const svn_opt_revision_t *peg_revision,
                 const svn_opt_revision_t *revision,
                 svn_info_receiver_t receiver,
                 void *receiver_baton,
                 svn_depth_t depth,
                 const apr_array_header_t *changelists,
                 svn_client_ctx_t *ctx,
                 apr_pool_t *pool)
{
  svn_ra_session_t *ra_session, *parent_ra_session;
  svn_revnum_t rev;
  const char *url;
  svn_node_kind_t url_kind;
  const char *repos_root_URL, *repos_UUID;
  svn_lock_t *lock;
  svn_boolean_t related;
  apr_hash_t *parent_ents;
  const char *parent_url, *base_name;
  svn_dirent_t *the_ent;
  svn_info_t *info;
  svn_error_t *err;

  if ((revision == NULL
       || revision->kind == svn_opt_revision_unspecified)
      && (peg_revision == NULL
          || peg_revision->kind == svn_opt_revision_unspecified))
    {
      /* Do all digging in the working copy. */
      apr_hash_t *changelist_hash = NULL;
      if (changelists && changelists->nelts)
        SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, 
                                           changelists, pool));
      return crawl_entries(path_or_url, receiver, receiver_baton,
                           depth, changelist_hash, ctx, pool);
    }

  /* Go repository digging instead. */

  /* Trace rename history (starting at path_or_url@peg_revision) and
     return RA session to the possibly-renamed URL as it exists in REVISION.
     The ra_session returned will be anchored on this "final" URL. */
  SVN_ERR(svn_client__ra_session_from_path(&ra_session, &rev,
                                           &url, path_or_url, NULL,
                                           peg_revision,
                                           revision, ctx, pool));

  SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_URL, pool));
  SVN_ERR(svn_ra_get_uuid2(ra_session, &repos_UUID, pool));

  svn_path_split(url, &parent_url, &base_name, pool);
  base_name = svn_path_uri_decode(base_name, pool);

  /* Get the dirent for the URL itself. */
  err = svn_ra_stat(ra_session, "", rev, &the_ent, pool);

  /* svn_ra_stat() will work against old versions of mod_dav_svn, but
     not old versions of svnserve.  In the case of a pre-1.2 svnserve,
     catch the specific error it throws:*/
  if (err && err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)
    {
      /* Fall back to pre-1.2 strategy for fetching dirent's URL. */
      svn_error_clear(err);

      if (strcmp(url, repos_root_URL) == 0)
        {
          /* In this universe, there's simply no way to fetch
             information about the repository's root directory!
             If we're recursing, degrade gracefully: rather than
             throw an error, return no information about the
             repos root. */
          if (depth > svn_depth_empty)
            goto pre_1_2_recurse;

          /* Otherwise, we really are stuck.  Better tell the user
             what's going on. */
          return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                                   _("Server does not support retrieving "
                                     "information about the repository root"));
        }

      SVN_ERR(svn_ra_check_path(ra_session, "", rev, &url_kind, pool));
      if (url_kind == svn_node_none)
        return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
                                 _("URL '%s' non-existent in revision %ld"),
                                 url, rev);

      /* Open a new RA session to the item's parent. */
      SVN_ERR(svn_client__open_ra_session_internal(&parent_ra_session,
                                                   parent_url, NULL,
                                                   NULL, NULL, FALSE, TRUE,
                                                   ctx, pool));

      /* Get all parent's entries, and find the item's dirent in the hash. */
      SVN_ERR(svn_ra_get_dir2(parent_ra_session, &parent_ents, NULL, NULL,
                              "", rev, DIRENT_FIELDS, pool));
      the_ent = apr_hash_get(parent_ents, base_name, APR_HASH_KEY_STRING);
      if (the_ent == NULL)
        return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
                                 _("URL '%s' non-existent in revision %ld"),
                                 url, rev);
    }
  else if (err)
    {
      return err;
    }

  if (! the_ent)
    return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL,
                             _("URL '%s' non-existent in revision %ld"),
                             url, rev);

  /* Check if the URL exists in HEAD and refers to the same resource.
     In this case, we check the repository for a lock on this URL.

     ### There is a possible race here, since HEAD might have changed since
     ### we checked it.  A solution to this problem could be to do the below
     ### check in a loop which only terminates if the HEAD revision is the same
     ### before and after this check.  That could, however, lead to a
     ### starvation situation instead.  */
  SVN_ERR(same_resource_in_head(&related, url, rev, ra_session, ctx, pool));
  if (related)
    {
      err = svn_ra_get_lock(ra_session, &lock, "", pool);

      /* An old mod_dav_svn will always work; there's nothing wrong with
         doing a PROPFIND for a property named "DAV:supportedlock". But
         an old svnserve will error. */
      if (err && err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)
        {
          svn_error_clear(err);
          lock = NULL;
        }
      else if (err)
        return err;
    }
  else
    lock = NULL;

  /* Push the URL's dirent (and lock) at the callback.*/
  SVN_ERR(build_info_from_dirent(&info, the_ent, lock, url, rev,
                                 repos_UUID, repos_root_URL, pool));
  SVN_ERR(receiver(receiver_baton, base_name, info, pool));

  /* Possibly recurse, using the original RA session. */
  if (depth > svn_depth_empty && (the_ent->kind == svn_node_dir))
    {
      apr_hash_t *locks;

pre_1_2_recurse:
      if (peg_revision->kind == svn_opt_revision_head)
        {
          err = svn_ra_get_locks(ra_session, &locks, "", pool);

          /* Catch specific errors thrown by old mod_dav_svn or svnserve. */
          if (err &&
              (err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED
               || err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE))
            {
              svn_error_clear(err);
              locks = apr_hash_make(pool); /* use an empty hash */
            }
          else if (err)
            return err;
        }
      else
        locks = apr_hash_make(pool); /* use an empty hash */

      SVN_ERR(push_dir_info(ra_session, url, "", rev,
                            repos_UUID, repos_root_URL,
                            receiver, receiver_baton,
                            depth, ctx, locks, pool));
    }

  return SVN_NO_ERROR;
}
Пример #9
0
static svn_error_t *
subcommand_accessof(apr_getopt_t *os, void *baton, apr_pool_t *pool)
{
  svn_authz_t *authz;
  svn_boolean_t read_access = FALSE, write_access = FALSE;
  svn_boolean_t check_r = FALSE, check_rw = FALSE, check_no = FALSE;
  svn_error_t *err;
  struct svnauthz_opt_state *opt_state = baton;
  const char *user = opt_state->username;
  const char *path = opt_state->fspath;
  const char *repos = opt_state->repos_name;
  const char *is = opt_state->is;
  svn_repos_authz_access_t request;

  if (opt_state->recursive && !path)
    return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                            ("--recursive not valid without --path"));

  /* Handle is argument parsing/allowed values */
  if (is) {
      if (0 == strcmp(is, "rw"))
        check_rw = TRUE;
      else if (0 == strcmp(is, "r"))
        check_r = TRUE;
      else if (0 == strcmp(is, "no"))
        check_no = TRUE;
      else
        return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                 ("'%s' is not a valid argument for --is"), is);
  }

  SVN_ERR(get_authz(&authz, opt_state, pool));


  request = svn_authz_write;
  if (opt_state->recursive)
    request |= svn_authz_recursive;
  err = svn_repos_authz_check_access(authz, repos, path, user,
                                     request, &write_access,
                                     pool);

  if (!write_access && !err)
    {
      request = svn_authz_read;
      if (opt_state->recursive)
        request |= svn_authz_recursive;
      err = svn_repos_authz_check_access(authz, repos, path, user,
                                         request, &read_access,
                                         pool);
    }

  if (!err)
    {
      const char *access_str = write_access ? "rw" : read_access ? "r" : "no";

      if (is)
        {
          /* Check that --is argument matches.
           * The errors returned here are not strictly correct, but
           * none of the other code paths will generate them and they
           * roughly mean what we're saying here. */
          if (check_rw && !write_access)
            err = svn_error_createf(SVN_ERR_AUTHZ_UNWRITABLE, NULL,
                                    ("%s is '%s', not writable"),
                                    path ? path : ("Repository"), access_str);
          else if (check_r && !read_access)
            err = svn_error_createf(SVN_ERR_AUTHZ_UNREADABLE, NULL,
                                    ("%s is '%s', not read only"),
                                    path ? path : ("Repository"), access_str);
          else if (check_no && (read_access || write_access))
            err = svn_error_createf(SVN_ERR_AUTHZ_PARTIALLY_READABLE,
                                    NULL, ("%s is '%s', not no access"),
                                    path ? path : ("Repository"), access_str);
        }
      else
        {
          err = svn_cmdline_printf(pool, "%s\n", access_str);
        }
    }

  return err;
}
Пример #10
0
svn_error_t *
svn_sqlite__open(svn_sqlite__db_t **db, const char *path,
                 svn_sqlite__mode_t mode, const char * const statements[],
                 int latest_schema, const char * const *upgrade_sql,
                 apr_pool_t *result_pool, apr_pool_t *scratch_pool)
{
  SVN_ERR(svn_atomic__init_once(&sqlite_init_state,
                                init_sqlite, NULL, scratch_pool));

  *db = apr_pcalloc(result_pool, sizeof(**db));

  SVN_ERR(internal_open(&(*db)->db3, path, mode, scratch_pool));

#ifdef SQLITE3_DEBUG
  sqlite3_trace((*db)->db3, sqlite_tracer, (*db)->db3);
#endif
#ifdef SQLITE3_PROFILE
  sqlite3_profile((*db)->db3, sqlite_profiler, (*db)->db3);
#endif

  /* Work around a bug in SQLite 3.7.7.  The bug was fixed in SQLite 3.7.7.1.

     See:

       Date: Sun, 26 Jun 2011 18:52:14 -0400
       From: Richard Hipp <*****@*****.**>
       To: General Discussion of SQLite Database <*****@*****.**>
       Cc: [email protected]
       Subject: Re: [sqlite] PRAGMA bug in 3.7.7 (but fine in 3.7.6.3)
       Message-ID: <*****@*****.**>
   */
  {
    int ignored_err = SQLITE_OK;
#if !SQLITE_VERSION_AT_LEAST(3,7,8) && defined(SQLITE_SCHEMA)
    if (!strcmp(sqlite3_libversion(), "3.7.7"))
      ignored_err = SQLITE_SCHEMA;
#endif

    SVN_ERR(exec_sql2(*db, "PRAGMA case_sensitive_like=1;", ignored_err));
  }

  SVN_ERR(exec_sql(*db,
              /* Disable synchronization to disable the explicit disk flushes
                 that make Sqlite up to 50 times slower; especially on small
                 transactions.

                 This removes some stability guarantees on specific hardware
                 and power failures, but still guarantees atomic commits on
                 application crashes. With our dependency on external data
                 like pristine files (Wc) and revision files (repository),
                 we can't keep up these additional guarantees anyway.

                 ### Maybe switch to NORMAL(1) when we use larger transaction
                     scopes */
              "PRAGMA synchronous=OFF;"
              /* Enable recursive triggers so that a user trigger will fire
                 in the deletion phase of an INSERT OR REPLACE statement.
                 Requires SQLite >= 3.6.18  */
              "PRAGMA recursive_triggers=ON;"));

#if SQLITE_VERSION_AT_LEAST(3,6,19) && defined(SVN_DEBUG)
  /* When running in debug mode, enable the checking of foreign key
     constraints.  This has possible performance implications, so we don't
     bother to do it for production...for now. */
  SVN_ERR(exec_sql(*db, "PRAGMA foreign_keys=ON;"));
#endif

  /* Store temporary tables in RAM instead of in temporary files, but don't
     fail on this if this option is disabled in the sqlite compilation by
     setting SQLITE_TEMP_STORE to 0 (always to disk) */
  svn_error_clear(exec_sql(*db, "PRAGMA temp_store = MEMORY;"));

  /* Validate the schema, upgrading if necessary. */
  if (upgrade_sql != NULL)
    SVN_ERR(check_format(*db, latest_schema, upgrade_sql, scratch_pool));

  /* Store the provided statements. */
  if (statements)
    {
      (*db)->statement_strings = statements;
      (*db)->nbr_statements = 0;
      while (*statements != NULL)
        {
          statements++;
          (*db)->nbr_statements++;
        }
      (*db)->prepared_stmts = apr_pcalloc(result_pool, (*db)->nbr_statements
                                                * sizeof(svn_sqlite__stmt_t *));
    }
  else
    (*db)->nbr_statements = 0;

  (*db)->state_pool = result_pool;
  apr_pool_cleanup_register(result_pool, *db, close_apr, apr_pool_cleanup_null);

  return SVN_NO_ERROR;
}
Пример #11
0
/* Helper func for recursively fetching svn_dirent_t's from a remote
   directory and pushing them at an info-receiver callback.

   DEPTH is the depth starting at DIR, even though RECEIVER is never
   invoked on DIR: if DEPTH is svn_depth_immediates, then invoke
   RECEIVER on all children of DIR, but none of their children; if
   svn_depth_files, then invoke RECEIVER on file children of DIR but
   not on subdirectories; if svn_depth_infinity, recurse fully.
*/
static svn_error_t *
push_dir_info(svn_ra_session_t *ra_session,
              const char *session_URL,
              const char *dir,
              svn_revnum_t rev,
              const char *repos_UUID,
              const char *repos_root,
              svn_info_receiver_t receiver,
              void *receiver_baton,
              svn_depth_t depth,
              svn_client_ctx_t *ctx,
              apr_hash_t *locks,
              apr_pool_t *pool)
{
  apr_hash_t *tmpdirents;
  svn_dirent_t *the_ent;
  svn_info_t *info;
  apr_hash_index_t *hi;
  apr_pool_t *subpool = svn_pool_create(pool);

  SVN_ERR(svn_ra_get_dir2(ra_session, &tmpdirents, NULL, NULL,
                          dir, rev, DIRENT_FIELDS, pool));

  for (hi = apr_hash_first(pool, tmpdirents); hi; hi = apr_hash_next(hi))
    {
      const char *path, *URL, *fs_path;
      const void *key;
      svn_lock_t *lock;
      void *val;

      svn_pool_clear(subpool);

      if (ctx->cancel_func)
        SVN_ERR(ctx->cancel_func(ctx->cancel_baton));

      apr_hash_this(hi, &key, NULL, &val);
      the_ent = val;

      path = svn_path_join(dir, key, subpool);
      URL  = svn_path_url_add_component(session_URL, key, subpool);

      fs_path = svn_path_is_child(repos_root, URL, subpool);
      fs_path = apr_pstrcat(subpool, "/", fs_path, NULL);
      fs_path = svn_path_uri_decode(fs_path, subpool);

      lock = apr_hash_get(locks, fs_path, APR_HASH_KEY_STRING);

      SVN_ERR(build_info_from_dirent(&info, the_ent, lock, URL, rev,
                                     repos_UUID, repos_root, subpool));

      if (depth >= svn_depth_immediates
          || (depth == svn_depth_files && the_ent->kind == svn_node_file))
        {
          SVN_ERR(receiver(receiver_baton, path, info, subpool));
        }

      if (depth == svn_depth_infinity && the_ent->kind == svn_node_dir)
        {
          SVN_ERR(push_dir_info(ra_session, URL, path,
                                rev, repos_UUID, repos_root,
                                receiver, receiver_baton,
                                depth, ctx, locks, subpool));
        }
    }

  svn_pool_destroy(subpool);

  return SVN_NO_ERROR;
}
Пример #12
0
svn_error_t *
svn_sqlite__step_done(svn_sqlite__stmt_t *stmt)
{
  SVN_ERR(step_with_expectation(stmt, FALSE));
  return svn_error_trace(svn_sqlite__reset(stmt));
}
Пример #13
0
static svn_error_t *
svn_fs_bdb__open_internal(bdb_env_baton_t **bdb_batonp, 
                          const char *path,
                          u_int32_t flags, int mode,
                          apr_pool_t *pool)
{
  bdb_env_key_t key;
  bdb_env_t *bdb;
  svn_boolean_t panic;

  /* We can safely discard the open DB_CONFIG file handle.  If the
     environment descriptor is in the cache, the key's immutability is
     guaranteed.  If it's not, we don't care if the key changes,
     between here and the actual insertion of the newly-created
     environment into the cache, because no other thread can touch the
     cache in the meantime. */
  SVN_ERR(bdb_cache_key(&key, NULL, path, pool));

  bdb = bdb_cache_get(&key, &panic);
  if (panic)
    return svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL,
                            db_strerror(DB_RUNRECOVERY));

  /* Make sure that the environment's open flags haven't changed. */
  if (bdb && bdb->flags != flags)
    {
      /* Handle changes to the DB_PRIVATE flag specially */
      if ((flags ^ bdb->flags) & DB_PRIVATE)
        {
          if (flags & DB_PRIVATE)
            return svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL,
                                    "Reopening a public Berkeley DB"
                                    " environment with private attributes");
          else
            return svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL,
                                    "Reopening a private Berkeley DB"
                                    " environment with public attributes");
        }

      /* Otherwise return a generic "flags-mismatch" error. */
      return svn_error_create(SVN_ERR_FS_BERKELEY_DB, NULL,
                              "Reopening a Berkeley DB environment"
                              " with different attributes");
    }

  if (!bdb)
    {
      svn_error_t *err;

      SVN_ERR(create_env(&bdb, path, svn_pool_create(bdb_cache_pool)));
      err = bdb_open(bdb, flags, mode);
      if (err)
        {
          /* Clean up, and we can't do anything about returned errors. */
          svn_error_clear(bdb_close(bdb));
          return svn_error_trace(err);
        }
        
      apr_hash_set(bdb_cache, &bdb->key, sizeof bdb->key, bdb);
      bdb->flags = flags;
      bdb->refcount = 1;
    }
  else
    {
      ++bdb->refcount;
    }

  *bdb_batonp = apr_palloc(pool, sizeof **bdb_batonp);
  (*bdb_batonp)->env = bdb->env;
  (*bdb_batonp)->bdb = bdb;
  (*bdb_batonp)->error_info = get_error_info(bdb);
  ++(*bdb_batonp)->error_info->refcount;
  apr_pool_cleanup_register(pool, *bdb_batonp, cleanup_env_baton,
                            apr_pool_cleanup_null);

  return SVN_NO_ERROR;
}
Пример #14
0
/* Create a Berkeley DB environment. */
static svn_error_t *
create_env(bdb_env_t **bdbp, const char *path, apr_pool_t *pool)
{
  int db_err;
  bdb_env_t *bdb;
  const char *path_bdb;
  char *tmp_path, *tmp_path_bdb;
  apr_size_t path_size, path_bdb_size;

#if SVN_BDB_PATH_UTF8
  path_bdb = svn_dirent_local_style(path, pool);
#else
  SVN_ERR(svn_utf_cstring_from_utf8(&path_bdb,
                                    svn_dirent_local_style(path, pool),
                                    pool));
#endif

  /* Allocate the whole structure, including strings, from the heap,
     because it must survive the cache pool cleanup. */
  path_size = strlen(path) + 1;
  path_bdb_size = strlen(path_bdb) + 1;
  /* Using calloc() to ensure the padding bytes in bdb->key (which is used as
   * a hash key) are zeroed. */
  bdb = calloc(1, sizeof(*bdb) + path_size + path_bdb_size);

  /* We must initialize this now, as our callers may assume their bdb
     pointer is valid when checking for errors.  */
  apr_pool_cleanup_register(pool, bdb, cleanup_env, apr_pool_cleanup_null);
  apr_cpystrn(bdb->errpfx_string, BDB_ERRPFX_STRING,
              sizeof(bdb->errpfx_string));
  bdb->path = tmp_path = (char*)(bdb + 1);
  bdb->path_bdb = tmp_path_bdb = tmp_path + path_size;
  apr_cpystrn(tmp_path, path, path_size);
  apr_cpystrn(tmp_path_bdb, path_bdb, path_bdb_size);
  bdb->pool = pool;
  *bdbp = bdb;

#if APR_HAS_THREADS
  {
    apr_status_t apr_err = apr_threadkey_private_create(&bdb->error_info,
                                                        cleanup_error_info,
                                                        pool);
    if (apr_err)
      return svn_error_create(apr_err, NULL,
                              "Can't allocate thread-specific storage"
                              " for the Berkeley DB environment descriptor");
  }
#endif /* APR_HAS_THREADS */

  db_err = db_env_create(&(bdb->env), 0);
  if (!db_err)
    {
      /* See the documentation at bdb_env_t's definition why the
         (char *) cast is safe and why it is done. */
      bdb->env->set_errpfx(bdb->env, (char *) bdb);

      /* bdb_error_gatherer is in parens to stop macro expansion. */
      bdb->env->set_errcall(bdb->env, (bdb_error_gatherer));

      /* Needed on Windows in case Subversion and Berkeley DB are using
         different C runtime libraries  */
      db_err = bdb->env->set_alloc(bdb->env, malloc, realloc, free);

      /* If we detect a deadlock, select a transaction to abort at
         random from those participating in the deadlock.  */
      if (!db_err)
        db_err = bdb->env->set_lk_detect(bdb->env, DB_LOCK_RANDOM);
    }
  return convert_bdb_error(bdb, db_err);
}
Пример #15
0
svn_error_t *
svn_wc__sync_flags_with_props(svn_boolean_t *did_set,
                              svn_wc__db_t *db,
                              const char *local_abspath,
                              apr_pool_t *scratch_pool)
{
  svn_wc__db_status_t status;
  svn_node_kind_t kind;
  svn_wc__db_lock_t *lock;
  apr_hash_t *props = NULL;
  svn_boolean_t had_props;
  svn_boolean_t props_mod;

  if (did_set)
    *did_set = FALSE;

  /* ### We'll consolidate these info gathering statements in a future
         commit. */

  SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                               NULL, &lock, NULL, NULL, NULL, NULL, NULL,
                               &had_props, &props_mod, NULL, NULL, NULL,
                               db, local_abspath,
                               scratch_pool, scratch_pool));

  /* We actually only care about the following flags on files, so just
     early-out for all other types.

     Also bail if there is no in-wc representation of the file. */
  if (kind != svn_node_file
      || (status != svn_wc__db_status_normal
          && status != svn_wc__db_status_added))
    return SVN_NO_ERROR;

  if (props_mod || had_props)
    SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath, scratch_pool,
                                  scratch_pool));
  else
    props = NULL;

  /* If we get this far, we're going to change *something*, so just set
     the flag appropriately. */
  if (did_set)
    *did_set = TRUE;

  /* Handle the read-write bit. */
  if (status != svn_wc__db_status_normal
      || props == NULL
      || ! svn_hash_gets(props, SVN_PROP_NEEDS_LOCK)
      || lock)
    {
      SVN_ERR(svn_io_set_file_read_write(local_abspath, FALSE, scratch_pool));
    }
  else
    {
      /* Special case: If we have an uncommitted svn:needs-lock, we don't
         set the file read_only just yet.  That happens upon commit. */
      apr_hash_t *pristine_props;

      if (! props_mod)
        pristine_props = props;
      else if (had_props)
        SVN_ERR(svn_wc__db_read_pristine_props(&pristine_props, db, local_abspath,
                                                scratch_pool, scratch_pool));
      else
        pristine_props = NULL;

      if (pristine_props
            && svn_hash_gets(pristine_props, SVN_PROP_NEEDS_LOCK) )
            /*&& props
            && apr_hash_get(props, SVN_PROP_NEEDS_LOCK, APR_HASH_KEY_STRING) )*/
        SVN_ERR(svn_io_set_file_read_only(local_abspath, FALSE, scratch_pool));
    }

/* Windows doesn't care about the execute bit. */
#ifndef WIN32

  if (props == NULL
      || ! svn_hash_gets(props, SVN_PROP_EXECUTABLE))
    {
      /* Turn off the execute bit */
      SVN_ERR(svn_io_set_file_executable(local_abspath, FALSE, FALSE,
                                         scratch_pool));
    }
  else
    SVN_ERR(svn_io_set_file_executable(local_abspath, TRUE, FALSE,
                                       scratch_pool));
#endif

  return SVN_NO_ERROR;
}
Пример #16
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;
}
Пример #17
0
svn_error_t *
svn_wc__internal_translated_stream(svn_stream_t **stream,
                                   svn_wc__db_t *db,
                                   const char *local_abspath,
                                   const char *versioned_abspath,
                                   apr_uint32_t flags,
                                   apr_pool_t *result_pool,
                                   apr_pool_t *scratch_pool)
{
  svn_boolean_t special;
  svn_boolean_t to_nf = flags & SVN_WC_TRANSLATE_TO_NF;
  svn_subst_eol_style_t style;
  const char *eol;
  apr_hash_t *keywords;
  svn_boolean_t repair_forced = flags & SVN_WC_TRANSLATE_FORCE_EOL_REPAIR;

  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
  SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_abspath));

  SVN_ERR(svn_wc__get_translate_info(&style, &eol,
                                     &keywords,
                                     &special,
                                     db, versioned_abspath, NULL, FALSE,
                                     scratch_pool, scratch_pool));

  if (special)
    {
      if (to_nf)
        return svn_subst_read_specialfile(stream, local_abspath, result_pool,
                                          scratch_pool);

      return svn_subst_create_specialfile(stream, local_abspath, result_pool,
                                          scratch_pool);
    }

  if (to_nf)
    SVN_ERR(svn_stream_open_readonly(stream, local_abspath, result_pool,
                                     scratch_pool));
  else
    {
      apr_file_t *file;

      /* We don't want the "open-exclusively" feature of the normal
         svn_stream_open_writable interface. Do this manually. */
      SVN_ERR(svn_io_file_open(&file, local_abspath,
                               APR_CREATE | APR_WRITE | APR_BUFFERED,
                               APR_OS_DEFAULT, result_pool));
      *stream = svn_stream_from_aprfile2(file, FALSE, result_pool);
    }

  if (svn_subst_translation_required(style, eol, keywords, special, TRUE))
    {
      if (to_nf)
        {
          if (style == svn_subst_eol_style_native)
            eol = SVN_SUBST_NATIVE_EOL_STR;
          else if (style == svn_subst_eol_style_fixed)
            repair_forced = TRUE;
          else if (style != svn_subst_eol_style_none)
            return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL);

          /* Wrap the stream to translate to normal form */
          *stream = svn_subst_stream_translated(*stream,
                                                eol,
                                                repair_forced,
                                                keywords,
                                                FALSE /* expand */,
                                                result_pool);

          /* Enforce our contract. TO_NF streams are readonly */
          svn_stream_set_write(*stream, write_handler_unsupported);
        }
      else
        {
          *stream = svn_subst_stream_translated(*stream, eol, TRUE,
                                                keywords, TRUE, result_pool);

          /* Enforce our contract. FROM_NF streams are write-only */
          svn_stream_set_read(*stream, read_handler_unsupported);
        }
    }

  return SVN_NO_ERROR;
}
Пример #18
0
static svn_error_t *
test_parse_unidiff(apr_pool_t *pool)
{
  svn_patch_file_t *patch_file;
  svn_boolean_t reverse;
  svn_boolean_t ignore_whitespace;
  int i;
  apr_pool_t *iterpool;

  reverse = FALSE;
  ignore_whitespace = FALSE;
  iterpool = svn_pool_create(pool);
  for (i = 0; i < 2; i++)
    {
      svn_patch_t *patch;
      svn_diff_hunk_t *hunk;

      svn_pool_clear(iterpool);

      SVN_ERR(create_patch_file(&patch_file, unidiff, pool));

      /* We have two patches with one hunk each.
       * Parse the first patch. */
      SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file, reverse,
                                        ignore_whitespace, iterpool,
                                        iterpool));
      SVN_TEST_ASSERT(patch);
      SVN_TEST_STRING_ASSERT(patch->old_filename, "A/C/gamma");
      SVN_TEST_STRING_ASSERT(patch->new_filename, "A/C/gamma");
      SVN_TEST_ASSERT(patch->hunks->nelts == 1);

      hunk = APR_ARRAY_IDX(patch->hunks, 0, svn_diff_hunk_t *);
      SVN_ERR(check_content(hunk, ! reverse,
                            "This is the file 'gamma'." NL,
                            pool));

      SVN_ERR(check_content(hunk, reverse,
                            "This is the file 'gamma'." NL
                            "some more bytes to 'gamma'" NL,
                            pool));

      /* Parse the second patch. */
      SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file, reverse,
                                        ignore_whitespace, pool, pool));
      SVN_TEST_ASSERT(patch);
      if (reverse)
        {
          SVN_TEST_STRING_ASSERT(patch->new_filename, "A/D/gamma.orig");
          SVN_TEST_STRING_ASSERT(patch->old_filename, "A/D/gamma");
        }
      else
        {
          SVN_TEST_STRING_ASSERT(patch->old_filename, "A/D/gamma.orig");
          SVN_TEST_STRING_ASSERT(patch->new_filename, "A/D/gamma");
        }
      SVN_TEST_ASSERT(patch->hunks->nelts == 1);

      hunk = APR_ARRAY_IDX(patch->hunks, 0, svn_diff_hunk_t *);
      SVN_ERR(check_content(hunk, ! reverse,
                            "This is the file 'gamma'." NL
                            "some less bytes to 'gamma'" NL,
                            pool));

      SVN_ERR(check_content(hunk, reverse,
                            "This is the file 'gamma'." NL,
                            pool));

      reverse = !reverse;
      SVN_ERR(svn_diff_close_patch_file(patch_file, pool));
    }
  svn_pool_destroy(iterpool);
  return SVN_NO_ERROR;
}
Пример #19
0
/* Set up, run, and verify the results of a substitution.
 *
 * Create a file TEST_NAME.src using global `lines' as the initial
 * data, with SRC_EOL as the line separator, then convert it to file
 * TEST_NAME.dst (using DST_EOL, REPAIR, EXPAND, REV, AUTHOR, DATE,
 * and URL as svn_subst_copy_and_translate() does), and verify that the
 * conversion worked.  Null SRC_EOL means create a mixed eol src
 * file.
 *
 * If the verification succeeds, remove both files and return
 * SVN_NO_ERROR.
 *
 * If the verification fails, leave the files for post-mortem.  If the
 * failure is due to non-eol data being wrong, return
 * SVN_ERR_MALFORMED_FILE.  If the problem is an incorrect eol marker,
 * return SVN_ERR_IO_UNKNOWN_EOL.  If the problem is that a mixed eol
 * style was repaired even though no repair flag was passed, return
 * SVN_ERR_TEST_FAILED.
 *
 * Use POOL for temporary allocation.
 *
 * Note: as with svn_subst_copy_and_translate(), if any of DST_EOL, REV,
 * AUTHOR, DATE, and/or URL is null, then that substitution is not
 * performed.
 */
static svn_error_t *
substitute_and_verify(const char *test_name,
                      const char *src_eol,
                      const char *dst_eol,
                      svn_boolean_t repair,
                      const char *rev,
                      const char *date,
                      const char *author,
                      const char *url,
                      svn_boolean_t expand,
                      apr_pool_t *pool)
{
  svn_error_t *err;
  svn_stringbuf_t *contents;
  apr_hash_t *keywords = apr_hash_make(pool);
  apr_size_t idx = 0;
  apr_size_t i;
  const char *expect[(sizeof(lines) / sizeof(*lines))];
  const char *src_fname = apr_pstrcat(pool, test_name, ".src", NULL);
  const char *dst_fname = apr_pstrcat(pool, test_name, ".dst", NULL);
  svn_string_t *val;
  apr_pool_t *subpool = svn_pool_create(pool);

  /** Clean up from previous tests, set up src data, and convert. **/
  SVN_ERR(remove_file(src_fname, pool));
  SVN_ERR(remove_file(dst_fname, pool));
  SVN_ERR(create_file(src_fname, src_eol, pool));

  if (rev)
    {
      val = svn_string_create(rev, pool);
      apr_hash_set(keywords, SVN_KEYWORD_REVISION_LONG,
                   APR_HASH_KEY_STRING, val);
      apr_hash_set(keywords, SVN_KEYWORD_REVISION_MEDIUM,
                   APR_HASH_KEY_STRING, val);
      apr_hash_set(keywords, SVN_KEYWORD_REVISION_SHORT,
                   APR_HASH_KEY_STRING, val);
    }
  if (date)
    {
      val = svn_string_create(date, pool);
      apr_hash_set(keywords, SVN_KEYWORD_DATE_LONG,
                   APR_HASH_KEY_STRING, val);
      apr_hash_set(keywords, SVN_KEYWORD_DATE_SHORT,
                   APR_HASH_KEY_STRING, val);
    }
  if (author)
    {
      val = svn_string_create(author, pool);
      apr_hash_set(keywords, SVN_KEYWORD_AUTHOR_LONG,
                   APR_HASH_KEY_STRING, val);
      apr_hash_set(keywords, SVN_KEYWORD_AUTHOR_SHORT,
                   APR_HASH_KEY_STRING, val);
    }
  if (url)
    {
      val = svn_string_create(url, pool);
      apr_hash_set(keywords, SVN_KEYWORD_URL_LONG,
                   APR_HASH_KEY_STRING, val);
      apr_hash_set(keywords, SVN_KEYWORD_URL_SHORT,
                   APR_HASH_KEY_STRING, val);
    }

  err = svn_subst_copy_and_translate3(src_fname, dst_fname, dst_eol, repair,
                                      keywords, expand, FALSE, subpool);
  svn_pool_destroy(subpool);

  /* Conversion should have failed, if src has mixed eol, and the
     repair flag was not set, and we requested eol translation. */
  if ((! src_eol) && dst_eol && (! repair))
    {
      if (! err)
        {
          return svn_error_createf
            (SVN_ERR_TEST_FAILED, NULL,
             "translation of '%s' should have failed, but didn't", src_fname);
        }
      else if (err->apr_err != SVN_ERR_IO_INCONSISTENT_EOL)
        {
          return svn_error_createf
            (SVN_ERR_TEST_FAILED, err,
             "translation of '%s' should fail, but not with this error",
             src_fname);
        }
      else
        {
          svn_error_clear(err);
          SVN_ERR(remove_file(src_fname, pool));
          return SVN_NO_ERROR;
        }

    }
  else if (err)
    return err;


  /** Verify that the conversion worked. **/

  for (i = 0; i < (sizeof(expect) / sizeof(*expect)); i++)
    expect[i] = lines[i];

  /* Certain lines contain keywords; expect their expansions. */
  if (rev)
    {
      if (expand)
        {
          expect[3 - 1] =
            apr_pstrcat(pool, "Line 3: ",
                        "Valid $LastChangedRevision: ",
                        rev,
                        " $, started unexpanded.",
                        NULL);
          expect[5 - 1] =
            apr_pstrcat(pool, "Line 5: ",
                        "Valid $Rev: ", rev, " $, started unexpanded.",
                        NULL);
          expect[26 - 1] =
            apr_pstrcat(pool, "Line 26: ",
                        "Emptily expanded keyword $Rev: ", rev," $.",
                        NULL);
          expect[29 - 1] =
            apr_pstrcat(pool, "Line 29: ",
                        "Valid $LastChangedRevision: ",
                        rev,
                        " $, started expanded.",
                        NULL);
          expect[30 - 1] =
            apr_pstrcat(pool, "Line 30: ",
                        "Valid $Rev: ",
                        rev,
                        " $, started expanded.",
                        NULL);
        }
      else  /* unexpand */
        {
          /* Lines 3 and 5 remain unchanged. */
          expect[26 - 1] =
            "Line 26: Emptily expanded keyword $Rev$.";
          expect[29 - 1] =
            "Line 29: Valid $LastChangedRevision$, started expanded.";
          expect[30 - 1] =
            "Line 30: Valid $Rev$, started expanded.";
        }
    }

  if (date)
    {
      if (expand)
        {
          expect[12 - 1] =
            apr_pstrcat(pool, "Line 12: ",
                        "Valid $LastChangedDate: ",
                        date,
                        " $, started unexpanded.",
                        NULL);
          expect[13 - 1] =
            apr_pstrcat(pool, "Line 13: ",
                        "Valid $Date: ", date, " $, started unexpanded.",
                        NULL);
          expect[33 - 1] =
            apr_pstrcat(pool, "Line 33: ",
                        "Valid $LastChangedDate: ",
                        date,
                        " $, started expanded.",
                        NULL);
          expect[34 - 1] =
            apr_pstrcat(pool, "Line 34: ",
                        "Valid $Date: ", date, " $, started expanded.",
                        NULL);
          expect[51 - 1] =
            apr_pstrcat(pool, "Line 51: ",
                        "same, but with embedded keyword ",
                        "$$$$$$$$Date: ", date, " $$$$$$$$$$.",
                        NULL);
          expect[52 - 1] =
            apr_pstrcat(pool, "Line 52: ",
                        "same, with expanded, empty keyword ",
                        "$$$$$$Date: ", date, " $$$$$$.",
                        NULL);
        }
      else  /* unexpand */
        {
          /* Lines 12 and 13 remain unchanged. */
          expect[33 - 1] =
            "Line 33: Valid $LastChangedDate$, started expanded.";
          expect[34 - 1] =
            "Line 34: Valid $Date$, started expanded.";
          expect[51 - 1] =
            "Line 51: same, but with embedded keyword $$$$$$$$Date$$$$$$$$$$.";
          expect[52 - 1] =
            "Line 52: same, with expanded, empty keyword $$$$$$Date$$$$$$.";
        }
    }

  if (author)
    {
      if (expand)
        {
          expect[8 - 1] =
            apr_pstrcat(pool, "Line 8: ",
                        "Valid $LastChangedBy: ",
                        author,
                        " $, started unexpanded.",
                        NULL);
          expect[9 - 1] =
            apr_pstrcat(pool, "Line 9: ",
                        "Valid $Author: ", author, " $, started unexpanded.",
                        NULL);
          expect[37 - 1] =
            apr_pstrcat(pool, "Line 37: ",
                        "Valid $LastChangedBy: ", author,
                        " $, started expanded.", NULL);
          expect[38 - 1] =
            apr_pstrcat(pool, "Line 38: ",
                        "Valid $Author: ", author, " $, started expanded.",
                        NULL);
          expect[46 - 1] =
            apr_pstrcat(pool, "Line 46: ",
                        "Empty $Author: ", author, " $, started expanded.",
                        NULL);
          expect[71 - 1] =
            apr_pstrcat(pool, ".$veR$Author: ", author, " $", NULL);

          expect[74 - 1] =
            apr_pstrcat(pool, "Line 74: ",
                        "Valid $Author: ", author, " $, started expanded.",
                        NULL);
          expect[79 - 1] =
            apr_pstrcat(pool, "Line 79: ",
                        "Valid $Author: ", author, " $, started expanded.",
                        NULL);
          expect[80 - 1] =
            apr_pstrcat(pool, "Line 80: ",
                        "Valid $Author: ", author, " $, started expanded.",
                        NULL);
          expect[81 - 1] =
            apr_pstrcat(pool, "Line 81: ",
                        "Valid $Author: ", author, " $, started expanded.",
                        NULL);
          expect[82 - 1] =
            apr_pstrcat(pool, "Line 82: ",
                        "Valid $Author: ", author, " $, started expanded.",
                        NULL);
        }
      else  /* unexpand */
        {
          /* Lines 8, 9, and 71 remain unchanged. */
          expect[37 - 1] =
            "Line 37: Valid $LastChangedBy$, started expanded.";
          expect[38 - 1] =
            "Line 38: Valid $Author$, started expanded.";
          expect[46 - 1] =
            "Line 46: Empty $Author$, started expanded.";
          expect[74 - 1] =
            "Line 74: Valid $Author$, started expanded.";
          expect[79 - 1] =
            "Line 79: Valid $Author$, started expanded.";
          expect[80 - 1] =
            "Line 80: Valid $Author$, started expanded.";
          expect[81 - 1] =
            "Line 81: Valid $Author$, started expanded.";
          expect[82 - 1] =
            "Line 82: Valid $Author$, started expanded.";
        }
    }

  if (url)
    {
      if (expand)
        {
          expect[16 - 1] =
            apr_pstrcat(pool, "Line 16: ",
                        "Valid $HeadURL: ", url, " $, started unexpanded.",
                        NULL);
          expect[17 - 1] =
            apr_pstrcat(pool, "Line 17: ",
                        "Valid $URL: ", url, " $, started unexpanded.",
                        NULL);
          expect[41 - 1] =
            apr_pstrcat(pool, "Line 41: ",
                        "Valid $HeadURL: ", url, " $, started expanded.",
                        NULL);
          expect[42 - 1] =
            apr_pstrcat(pool, "Line 42: ",
                        "Valid $URL: ", url, " $, started expanded.",
                        NULL);
          expect[75 - 1] =
            apr_pstrcat(pool, "Line 75: ",
                        "Valid $URL: ", url, " $, started expanded.",
                        NULL);
        }
      else  /* unexpand */
        {
          /* Lines 16 and 17 and remain unchanged. */
          expect[41 - 1] =
            "Line 41: Valid $HeadURL$, started expanded.";
          expect[42 - 1] =
            "Line 42: Valid $URL$, started expanded.";
          expect[75 - 1] =
            "Line 75: Valid $URL$, started expanded.";
        }
    }

  /* Handle lines 48, 49, and 70 specially, as they contains two valid
     keywords. */
  if (rev && author)
    {
      if (expand)
        {
          expect[48 - 1] =
            apr_pstrcat(pool, "Line 48: ",
                        "Two keywords back to back: "
                        "$Author: ", author, " $"
                        "$Rev: ", rev, " $.",
                        NULL);
          expect[49 - 1] =
            apr_pstrcat(pool, "Line 49: ",
                        "One keyword, one not, back to back: "
                        "$Author: ", author, " $Rev$.",
                        NULL);
          expect[70 - 1] =
            apr_pstrcat(pool, "$Author: ", author, " $Rev$.", NULL);
        }
      /* Else Lines 48, 49, and 70 remain unchanged. */
    }
  else if (rev && (! author))
    {
      if (expand)
        {
          expect[48 - 1] =
            apr_pstrcat(pool, "Line 48: ",
                        "Two keywords back to back: "
                        "$Author$$Rev: ", rev, " $.",
                        NULL);
          expect[49 - 1] =
            apr_pstrcat(pool, "Line 49: ",
                        "One keyword, one not, back to back: "
                        "$Author$Rev: ", rev, " $.",
                        NULL);
          expect[70 - 1] =
            apr_pstrcat(pool, "$Author$Rev: ", rev, " $.", NULL);
        }
      /* Else Lines 48, 49, and 70 remain unchanged. */
    }
  else if ((! rev) && author)
    {
      if (expand)
        {
          expect[48 - 1] =
            apr_pstrcat(pool, "Line 48: ",
                        "Two keywords back to back: "
                        "$Author: ", author, " $$Rev$.",
                        NULL);
          expect[49 - 1] =
            apr_pstrcat(pool, "Line 49: ",
                        "One keyword, one not, back to back: "
                        "$Author: ", author, " $Rev$.",
                        NULL);
          expect[70 - 1] =
            apr_pstrcat(pool, "$Author: ", author, " $Rev$.", NULL);
        }
      /* Else Lines 48, 49, and 70 remain unchanged. */
    }
  /* Else neither rev nor author, so Lines 48, 49, and 70 remain
     unchanged. */

  /* Handle line 24 specially, as it contains two valid keywords. */
  if (date && author)
    {
      if (expand)
        {
          expect[24 - 1] =
            apr_pstrcat(pool, "Line 24: ",
                        "keyword in a keyword: $Author: ",
                        author,
                        " $Date$ $",
                        NULL);
        }
      else  /* unexpand */
        {
          expect[24 - 1] =
            apr_pstrcat(pool, "Line 24: ",
                        "keyword in a keyword: $Author$Date$ $",
                        NULL);
        }
    }
  else if (date && (! author))
    {
      if (expand)
        {
          expect[24 - 1] =
            apr_pstrcat(pool, "Line 24: ",
                        "keyword in a keyword: $Author: $Date: ",
                        date,
                        " $ $",
                        NULL);
        }
      /* Else Line 24 remains unchanged. */
    }
  else if ((! date) && author)
    {
      if (expand)
        {
          expect[24 - 1] =
            apr_pstrcat(pool, "Line 24: ",
                        "keyword in a keyword: $Author: ",
                        author,
                        " $Date$ $",
                        NULL);
        }
      else  /* unexpand */
        {
          expect[24 - 1] =
            apr_pstrcat(pool, "Line 24: ",
                        "keyword in a keyword: $Author$Date$ $",
                        NULL);
        }
    }
  /* Else neither author nor date, so Line 24 remains unchanged. */

  /** Ready to verify. **/

  SVN_ERR(svn_stringbuf_from_file(&contents, dst_fname, pool));

  for (i = 0; i < (sizeof(expect) / sizeof(*expect)); i++)
    {
      if (contents->len < idx)
        return svn_error_createf
          (SVN_ERR_MALFORMED_FILE, NULL,
           "'%s' has short contents at line %" APR_SIZE_T_FMT,
           dst_fname, i + 1);

      if (strncmp(contents->data + idx, expect[i], strlen(expect[i])) != 0)
        return svn_error_createf
          (SVN_ERR_MALFORMED_FILE, NULL,
           "'%s' has wrong contents at line %" APR_SIZE_T_FMT,
           dst_fname, i + 1);

      /* Else, the data is correct, at least up to the next eol. */

      idx += strlen(expect[i]);

      if (dst_eol)  /* verify the promised consistent eol style */
        {
          if (strncmp(contents->data + idx, dst_eol, strlen(dst_eol)) != 0)
            return svn_error_createf
              (SVN_ERR_IO_UNKNOWN_EOL, NULL,
               "'%s' has wrong eol style at line %" APR_SIZE_T_FMT, dst_fname,
               i + 1);
          else
            idx += strlen(dst_eol);
        }
      else  /* allow any eol style, even inconsistent ones, loosely */
        {
          while ((*(contents->data + idx) == '\r')
                 || (*(contents->data + idx) == '\n'))
            idx++;
        }
    }

  /* Clean up this test, since successful. */
  SVN_ERR(remove_file(src_fname, pool));
  SVN_ERR(remove_file(dst_fname, pool));

  return SVN_NO_ERROR;
}
Пример #20
0
static svn_error_t *
test_parse_git_tree_and_text_diff(apr_pool_t *pool)
{
  /* ### Should we check for reversed diffs? */

  svn_patch_file_t *patch_file;
  svn_patch_t *patch;
  svn_diff_hunk_t *hunk;

  SVN_ERR(create_patch_file(&patch_file, git_tree_and_text_unidiff, pool));

  /* Parse a copied file with text modifications. */
  SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
                                    FALSE, /* reverse */
                                    FALSE, /* ignore_whitespace */
                                    pool, pool));
  SVN_TEST_ASSERT(patch);
  SVN_TEST_STRING_ASSERT(patch->old_filename, "iota");
  SVN_TEST_STRING_ASSERT(patch->new_filename, "iota.copied");
  SVN_TEST_ASSERT(patch->operation == svn_diff_op_copied);
  SVN_TEST_ASSERT(patch->hunks->nelts == 1);

  hunk = APR_ARRAY_IDX(patch->hunks, 0, svn_diff_hunk_t *);

  SVN_ERR(check_content(hunk, TRUE,
                        "This is the file 'iota'." NL,
                        pool));

  SVN_ERR(check_content(hunk, FALSE,
                        "This is the file 'iota'." NL
                        "some more bytes to 'iota'" NL,
                        pool));

  /* Parse a moved file with text modifications. */
  SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
                                    FALSE, /* reverse */
                                    FALSE, /* ignore_whitespace */
                                    pool, pool));
  SVN_TEST_ASSERT(patch);
  SVN_TEST_STRING_ASSERT(patch->old_filename, "A/mu");
  SVN_TEST_STRING_ASSERT(patch->new_filename, "A/mu.moved");
  SVN_TEST_ASSERT(patch->operation == svn_diff_op_moved);
  SVN_TEST_ASSERT(patch->hunks->nelts == 1);

  hunk = APR_ARRAY_IDX(patch->hunks, 0, svn_diff_hunk_t *);

  SVN_ERR(check_content(hunk, TRUE,
                        "This is the file 'mu'." NL,
                        pool));

  SVN_ERR(check_content(hunk, FALSE,
                        "This is the file 'mu'." NL
                        "some more bytes to 'mu'" NL,
                        pool));

  SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
                                    FALSE, /* reverse */
                                    FALSE, /* ignore_whitespace */
                                    pool, pool));
  SVN_TEST_ASSERT(patch);
  SVN_TEST_STRING_ASSERT(patch->old_filename, "/dev/null");
  SVN_TEST_STRING_ASSERT(patch->new_filename, "new");
  SVN_TEST_ASSERT(patch->operation == svn_diff_op_added);
  SVN_TEST_ASSERT(patch->hunks->nelts == 1);

  hunk = APR_ARRAY_IDX(patch->hunks, 0, svn_diff_hunk_t *);

  SVN_ERR(check_content(hunk, TRUE,
                        "",
                        pool));

  SVN_ERR(check_content(hunk, FALSE,
                        "This is the file 'new'." NL,
                        pool));

  SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
                                    FALSE, /* reverse */
                                    FALSE, /* ignore_whitespace */
                                    pool, pool));
  SVN_TEST_ASSERT(patch);
  SVN_TEST_STRING_ASSERT(patch->old_filename, "A/B/lambda");
  SVN_TEST_STRING_ASSERT(patch->new_filename, "/dev/null");
  SVN_TEST_ASSERT(patch->operation == svn_diff_op_deleted);
  SVN_TEST_ASSERT(patch->hunks->nelts == 1);

  hunk = APR_ARRAY_IDX(patch->hunks, 0, svn_diff_hunk_t *);

  SVN_ERR(check_content(hunk, TRUE,
                        "This is the file 'lambda'." NL,
                        pool));

  SVN_ERR(check_content(hunk, FALSE,
                        "",
                        pool));

  SVN_ERR(svn_diff_close_patch_file(patch_file, pool));
  return SVN_NO_ERROR;
}
Пример #21
0
static svn_error_t *try_auth(svn_ra_svn_conn_t *conn,
                             sasl_conn_t *sasl_ctx,
                             apr_pool_t *pool,
                             server_baton_t *b,
                             svn_boolean_t *success)
{
  const char *out, *mech;
  const svn_string_t *arg = NULL, *in;
  unsigned int outlen;
  int result;
  svn_boolean_t use_base64;

  *success = FALSE;

  /* Read the client's chosen mech and the initial token. */
  SVN_ERR(svn_ra_svn__read_tuple(conn, pool, "w(?s)", &mech, &in));

  if (strcmp(mech, "EXTERNAL") == 0 && !in)
    in = svn_string_create(b->client_info->tunnel_user, pool);
  else if (in)
    in = svn_base64_decode_string(in, pool);

  /* For CRAM-MD5, we don't base64-encode stuff. */
  use_base64 = (strcmp(mech, "CRAM-MD5") != 0);

  /* sasl uses unsigned int for the length of strings, we use apr_size_t
   * which may not be the same size.  Deal with potential integer overflow */
  if (in && in->len > UINT_MAX)
    return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                             _("Initial token is too long"));

  result = svn_sasl__server_start(sasl_ctx, mech,
                                  in ? in->data : NULL,
                                  in ? (unsigned int) in->len : 0,
                                  &out, &outlen);

  if (result != SASL_OK && result != SASL_CONTINUE)
    return fail_auth(conn, pool, sasl_ctx);

  while (result == SASL_CONTINUE)
    {
      svn_ra_svn__item_t *item;

      arg = svn_string_ncreate(out, outlen, pool);
      /* Encode what we send to the client. */
      if (use_base64)
        arg = svn_base64_encode_string2(arg, TRUE, pool);

      SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(s)", "step", arg));

      /* Read and decode the client response. */
      SVN_ERR(svn_ra_svn__read_item(conn, pool, &item));
      if (item->kind != SVN_RA_SVN_STRING)
        return SVN_NO_ERROR;

      in = &item->u.string;
      if (use_base64)
        in = svn_base64_decode_string(in, pool);

      if (in->len > UINT_MAX)
        return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
                                 _("Step response is too long"));

      result = svn_sasl__server_step(sasl_ctx, in->data,
                                     (unsigned int) in->len,
                                     &out, &outlen);
    }

  if (result != SASL_OK)
    return fail_auth(conn, pool, sasl_ctx);

  /* Send our last response, if necessary. */
  if (outlen)
    arg = svn_base64_encode_string2(svn_string_ncreate(out, outlen, pool), TRUE,
                                    pool);
  else
    arg = NULL;

  *success = TRUE;
  SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(?s)", "success", arg));

  return SVN_NO_ERROR;
}
Пример #22
0
/* Tests to parse a diff with three property changes, one is added, one is
 * modified and one is deleted. */
static svn_error_t *
test_parse_property_diff(apr_pool_t *pool)
{
  svn_patch_file_t *patch_file;
  svn_patch_t *patch;
  svn_prop_patch_t *prop_patch;
  svn_diff_hunk_t *hunk;
  apr_array_header_t *hunks;

  SVN_ERR(create_patch_file(&patch_file, property_unidiff, pool));

  SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
                                    FALSE, /* reverse */
                                    FALSE, /* ignore_whitespace */
                                    pool, pool));
  SVN_TEST_ASSERT(patch);
  SVN_TEST_STRING_ASSERT(patch->old_filename, "iota");
  SVN_TEST_STRING_ASSERT(patch->new_filename, "iota");
  SVN_TEST_ASSERT(patch->hunks->nelts == 0);
  SVN_TEST_ASSERT(apr_hash_count(patch->prop_patches) == 3);

  /* Check the deleted property */
  prop_patch = apr_hash_get(patch->prop_patches, "prop_del",
                            APR_HASH_KEY_STRING);

  SVN_TEST_ASSERT(prop_patch->operation == svn_diff_op_deleted);
  hunks = prop_patch->hunks;

  SVN_TEST_ASSERT(hunks->nelts == 1);
  hunk = APR_ARRAY_IDX(hunks, 0 , svn_diff_hunk_t *);

  SVN_ERR(check_content(hunk, TRUE,
                        "value" NL,
                        pool));

  SVN_ERR(check_content(hunk, FALSE,
                        "",
                        pool));

  /* Check the added property */
  prop_patch = apr_hash_get(patch->prop_patches, "prop_add",
                            APR_HASH_KEY_STRING);

  SVN_TEST_ASSERT(!strcmp("prop_add", prop_patch->name));
  SVN_TEST_ASSERT(prop_patch->operation == svn_diff_op_added);
  hunks = prop_patch->hunks;

  SVN_TEST_ASSERT(hunks->nelts == 1);
  hunk = APR_ARRAY_IDX(hunks, 0 , svn_diff_hunk_t *);

  SVN_ERR(check_content(hunk, TRUE,
                        "",
                        pool));

  SVN_ERR(check_content(hunk, FALSE,
                        "value" NL,
                        pool));

  /* Check the modified property */
  prop_patch = apr_hash_get(patch->prop_patches, "prop_mod",
                            APR_HASH_KEY_STRING);

  SVN_TEST_ASSERT(prop_patch->operation == svn_diff_op_modified);
  hunks = prop_patch->hunks;

  SVN_TEST_ASSERT(hunks->nelts == 2);
  hunk = APR_ARRAY_IDX(hunks, 0 , svn_diff_hunk_t *);

  SVN_ERR(check_content(hunk, TRUE,
                        "value" NL
                        "context" NL
                        "context" NL
                        "context" NL,
                        pool));

  SVN_ERR(check_content(hunk, FALSE,
                        "new value" NL
                        "context" NL
                        "context" NL
                        "context" NL,
                        pool));

  hunk = APR_ARRAY_IDX(hunks, 1 , svn_diff_hunk_t *);

  SVN_ERR(check_content(hunk, TRUE,
                        "context" NL
                        "context" NL
                        "context" NL
                        "value" NL,
                        pool));

  SVN_ERR(check_content(hunk, FALSE,
                        "context" NL
                        "context" NL
                        "context" NL
                        "new value" NL,
                        pool));

  SVN_ERR(svn_diff_close_patch_file(patch_file, pool));
  return SVN_NO_ERROR;
}
Пример #23
0
svn_error_t *
svn_repos_verify_fs2(svn_repos_t *repos,
                     svn_revnum_t start_rev,
                     svn_revnum_t end_rev,
                     svn_repos_notify_func_t notify_func,
                     void *notify_baton,
                     svn_cancel_func_t cancel_func,
                     void *cancel_baton,
                     apr_pool_t *pool)
{
  svn_fs_t *fs = svn_repos_fs(repos);
  svn_revnum_t youngest;
  svn_revnum_t rev;
  apr_pool_t *iterpool = svn_pool_create(pool);
  svn_repos_notify_t *notify;

  /* Determine the current youngest revision of the filesystem. */
  SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));

  /* Use default vals if necessary. */
  if (! SVN_IS_VALID_REVNUM(start_rev))
    start_rev = 0;
  if (! SVN_IS_VALID_REVNUM(end_rev))
    end_rev = youngest;

  /* Validate the revisions. */
  if (start_rev > end_rev)
    return svn_error_createf(SVN_ERR_REPOS_BAD_ARGS, NULL,
                             _("Start revision %ld"
                               " is greater than end revision %ld"),
                             start_rev, end_rev);
  if (end_rev > youngest)
    return svn_error_createf(SVN_ERR_REPOS_BAD_ARGS, NULL,
                             _("End revision %ld is invalid "
                               "(youngest revision is %ld)"),
                             end_rev, youngest);

  /* Create a notify object that we can reuse within the loop. */
  if (notify_func)
    notify = svn_repos_notify_create(svn_repos_notify_verify_rev_end,
                                     pool);

  for (rev = start_rev; rev <= end_rev; rev++)
    {
      svn_delta_editor_t *dump_editor;
      void *dump_edit_baton;
      const svn_delta_editor_t *cancel_editor;
      void *cancel_edit_baton;
      svn_fs_root_t *to_root;
      apr_hash_t *props;

      svn_pool_clear(iterpool);

      /* Get cancellable dump editor, but with our close_directory handler. */
      SVN_ERR(get_dump_editor((const svn_delta_editor_t **)&dump_editor,
                              &dump_edit_baton, fs, rev, "",
                              svn_stream_empty(pool),
                              notify_func, notify_baton,
                              start_rev,
                              FALSE, TRUE, /* use_deltas, verify */
                              iterpool));
      dump_editor->close_directory = verify_close_directory;
      SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
                                                dump_editor, dump_edit_baton,
                                                &cancel_editor,
                                                &cancel_edit_baton,
                                                iterpool));

      SVN_ERR(svn_fs_revision_root(&to_root, fs, rev, iterpool));
      SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
                                cancel_editor, cancel_edit_baton,
                                NULL, NULL, iterpool));
      SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, iterpool));

      if (notify_func)
        {
          notify->revision = rev;
          notify_func(notify_baton, notify, iterpool);
        }
    }

  /* We're done. */
  if (notify_func)
    {
      notify = svn_repos_notify_create(svn_repos_notify_verify_end, iterpool);
      notify_func(notify_baton, notify, iterpool);
    }

  svn_pool_destroy(iterpool);

  return SVN_NO_ERROR;
}
Пример #24
0
static svn_error_t *
test_parse_diff_symbols_in_prop_unidiff(apr_pool_t *pool)
{
  svn_patch_t *patch;
  svn_patch_file_t *patch_file;
  svn_prop_patch_t *prop_patch;
  svn_diff_hunk_t *hunk;
  apr_array_header_t *hunks;

  SVN_ERR(create_patch_file(&patch_file, diff_symbols_in_prop_unidiff, pool));

  SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
                                    FALSE, /* reverse */
                                    FALSE, /* ignore_whitespace */
                                    pool, pool));
  SVN_TEST_ASSERT(patch);
  SVN_TEST_STRING_ASSERT(patch->old_filename, "iota");
  SVN_TEST_STRING_ASSERT(patch->new_filename, "iota");
  SVN_TEST_ASSERT(patch->hunks->nelts == 0);
  SVN_TEST_ASSERT(apr_hash_count(patch->prop_patches) == 3);

  /* Check the added property */
  prop_patch = apr_hash_get(patch->prop_patches, "prop_add",
                            APR_HASH_KEY_STRING);
  SVN_TEST_ASSERT(prop_patch->operation == svn_diff_op_added);

  hunks = prop_patch->hunks;
  SVN_TEST_ASSERT(hunks->nelts == 1);
  hunk = APR_ARRAY_IDX(hunks, 0 , svn_diff_hunk_t *);

  SVN_ERR(check_content(hunk, TRUE,
                        "",
                        pool));

  SVN_ERR(check_content(hunk, FALSE,
                        "Added: bogus_prop" NL
                        "## -0,0 +20 ##" NL
                        "@@ -1,2 +0,0 @@" NL,
                        pool));

  /* Check the deleted property */
  prop_patch = apr_hash_get(patch->prop_patches, "prop_del",
                            APR_HASH_KEY_STRING);
  SVN_TEST_ASSERT(prop_patch->operation == svn_diff_op_deleted);

  hunks = prop_patch->hunks;
  SVN_TEST_ASSERT(hunks->nelts == 1);
  hunk = APR_ARRAY_IDX(hunks, 0 , svn_diff_hunk_t *);

  SVN_ERR(check_content(hunk, TRUE,
                        "--- iota" NL
                        "+++ iota" NL,
                        pool));

  SVN_ERR(check_content(hunk, FALSE,
                        "",
                        pool));

  /* Check the modified property */
  prop_patch = apr_hash_get(patch->prop_patches, "prop_mod",
                            APR_HASH_KEY_STRING);
  SVN_TEST_ASSERT(prop_patch->operation == svn_diff_op_modified);
  hunks = prop_patch->hunks;
  SVN_TEST_ASSERT(hunks->nelts == 2);
  hunk = APR_ARRAY_IDX(hunks, 0 , svn_diff_hunk_t *);

  SVN_ERR(check_content(hunk, TRUE,
                        "## -1,2 +1,2 ##" NL
                        "## -1,5 -0,0 ##" NL
                        "@@ -1,5 -0,0 @@" NL
                        "Modified: prop_mod" NL,
                        pool));

  SVN_ERR(check_content(hunk, FALSE,
                        "## -1,3 +1,3 ##" NL
                        "## -1,5 -0,0 ##" NL
                        "@@ -1,5 -0,0 @@" NL
                        "Modified: prop_mod" NL,
                        pool));

  hunk = APR_ARRAY_IDX(hunks, 1 , svn_diff_hunk_t *);

  SVN_ERR(check_content(hunk, TRUE,
                        "context" NL
                        "context" NL
                        "context" NL
                        "## -0,0 +1 ##" NL,
                        pool));

  SVN_ERR(check_content(hunk, FALSE,
                        "context" NL
                        "context" NL
                        "context" NL
                        "## -1,2 +1,4 ##" NL,
                        pool));

  SVN_ERR(svn_diff_close_patch_file(patch_file, pool));
  return SVN_NO_ERROR;
}
Пример #25
0
/* The main dumper. */
svn_error_t *
svn_repos_dump_fs3(svn_repos_t *repos,
                   svn_stream_t *stream,
                   svn_revnum_t start_rev,
                   svn_revnum_t end_rev,
                   svn_boolean_t incremental,
                   svn_boolean_t use_deltas,
                   svn_repos_notify_func_t notify_func,
                   void *notify_baton,
                   svn_cancel_func_t cancel_func,
                   void *cancel_baton,
                   apr_pool_t *pool)
{
  const svn_delta_editor_t *dump_editor;
  void *dump_edit_baton = NULL;
  svn_revnum_t i;
  svn_fs_t *fs = svn_repos_fs(repos);
  apr_pool_t *subpool = svn_pool_create(pool);
  svn_revnum_t youngest;
  const char *uuid;
  int version;
  svn_boolean_t found_old_reference = FALSE;
  svn_boolean_t found_old_mergeinfo = FALSE;
  svn_repos_notify_t *notify;

  /* Determine the current youngest revision of the filesystem. */
  SVN_ERR(svn_fs_youngest_rev(&youngest, fs, pool));

  /* Use default vals if necessary. */
  if (! SVN_IS_VALID_REVNUM(start_rev))
    start_rev = 0;
  if (! SVN_IS_VALID_REVNUM(end_rev))
    end_rev = youngest;
  if (! stream)
    stream = svn_stream_empty(pool);

  /* Validate the revisions. */
  if (start_rev > end_rev)
    return svn_error_createf(SVN_ERR_REPOS_BAD_ARGS, NULL,
                             _("Start revision %ld"
                               " is greater than end revision %ld"),
                             start_rev, end_rev);
  if (end_rev > youngest)
    return svn_error_createf(SVN_ERR_REPOS_BAD_ARGS, NULL,
                             _("End revision %ld is invalid "
                               "(youngest revision is %ld)"),
                             end_rev, youngest);
  if ((start_rev == 0) && incremental)
    incremental = FALSE; /* revision 0 looks the same regardless of
                            whether or not this is an incremental
                            dump, so just simplify things. */

  /* Write out the UUID. */
  SVN_ERR(svn_fs_get_uuid(fs, &uuid, pool));

  /* If we're not using deltas, use the previous version, for
     compatibility with svn 1.0.x. */
  version = SVN_REPOS_DUMPFILE_FORMAT_VERSION;
  if (!use_deltas)
    version--;

  /* Write out "general" metadata for the dumpfile.  In this case, a
     magic header followed by a dumpfile format version. */
  SVN_ERR(svn_stream_printf(stream, pool,
                            SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n\n",
                            version));
  SVN_ERR(svn_stream_printf(stream, pool, SVN_REPOS_DUMPFILE_UUID
                            ": %s\n\n", uuid));

  /* Create a notify object that we can reuse in the loop. */
  if (notify_func)
    notify = svn_repos_notify_create(svn_repos_notify_dump_rev_end,
                                     pool);

  /* Main loop:  we're going to dump revision i.  */
  for (i = start_rev; i <= end_rev; i++)
    {
      svn_revnum_t from_rev, to_rev;
      svn_fs_root_t *to_root;
      svn_boolean_t use_deltas_for_rev;

      svn_pool_clear(subpool);

      /* Check for cancellation. */
      if (cancel_func)
        SVN_ERR(cancel_func(cancel_baton));

      /* Special-case the initial revision dump: it needs to contain
         *all* nodes, because it's the foundation of all future
         revisions in the dumpfile. */
      if ((i == start_rev) && (! incremental))
        {
          /* Special-special-case a dump of revision 0. */
          if (i == 0)
            {
              /* Just write out the one revision 0 record and move on.
                 The parser might want to use its properties. */
              SVN_ERR(write_revision_record(stream, fs, 0, subpool));
              to_rev = 0;
              goto loop_end;
            }

          /* Compare START_REV to revision 0, so that everything
             appears to be added.  */
          from_rev = 0;
          to_rev = i;
        }
      else
        {
          /* In the normal case, we want to compare consecutive revs. */
          from_rev = i - 1;
          to_rev = i;
        }

      /* Write the revision record. */
      SVN_ERR(write_revision_record(stream, fs, to_rev, subpool));

      /* Fetch the editor which dumps nodes to a file.  Regardless of
         what we've been told, don't use deltas for the first rev of a
         non-incremental dump. */
      use_deltas_for_rev = use_deltas && (incremental || i != start_rev);
      SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton, fs, to_rev,
                              "", stream, notify_func, notify_baton,
                              start_rev, use_deltas_for_rev, FALSE, subpool));

      /* Drive the editor in one way or another. */
      SVN_ERR(svn_fs_revision_root(&to_root, fs, to_rev, subpool));

      /* If this is the first revision of a non-incremental dump,
         we're in for a full tree dump.  Otherwise, we want to simply
         replay the revision.  */
      if ((i == start_rev) && (! incremental))
        {
          svn_fs_root_t *from_root;
          SVN_ERR(svn_fs_revision_root(&from_root, fs, from_rev, subpool));
          SVN_ERR(svn_repos_dir_delta2(from_root, "", "",
                                       to_root, "",
                                       dump_editor, dump_edit_baton,
                                       NULL,
                                       NULL,
                                       FALSE, /* don't send text-deltas */
                                       svn_depth_infinity,
                                       FALSE, /* don't send entry props */
                                       FALSE, /* don't ignore ancestry */
                                       subpool));
        }
      else
        {
          SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
                                    dump_editor, dump_edit_baton,
                                    NULL, NULL, subpool));
        }

    loop_end:
      if (notify_func)
        {
          notify->revision = to_rev;
          notify_func(notify_baton, notify, subpool);
        }

      if (dump_edit_baton) /* We never get an edit baton for r0. */
        {
          if (((struct edit_baton *)dump_edit_baton)->found_old_reference)
            found_old_reference = TRUE;
          if (((struct edit_baton *)dump_edit_baton)->found_old_mergeinfo)
            found_old_mergeinfo = TRUE;
        }
    }

  if (notify_func)
    {
      /* Did we issue any warnings about references to revisions older than
         the oldest dumped revision?  If so, then issue a final generic
         warning, since the inline warnings already issued might easily be
         missed. */

      notify = svn_repos_notify_create(svn_repos_notify_dump_end, subpool);
      notify_func(notify_baton, notify, subpool);

      if (found_old_reference)
        {
          notify = svn_repos_notify_create(svn_repos_notify_warning, subpool);

          notify->warning = svn_repos_notify_warning_found_old_reference;
          notify->warning_str = _("The range of revisions dumped "
                                  "contained references to "
                                  "copy sources outside that "
                                  "range.");
          notify_func(notify_baton, notify, subpool);
        }

      /* Ditto if we issued any warnings about old revisions referenced
         in dumped mergeinfo. */
      if (found_old_mergeinfo)
        {
          notify = svn_repos_notify_create(svn_repos_notify_warning, subpool);

          notify->warning = svn_repos_notify_warning_found_old_mergeinfo;
          notify->warning_str = _("The range of revisions dumped "
                                  "contained mergeinfo "
                                  "which reference revisions outside "
                                  "that range.");
          notify_func(notify_baton, notify, subpool);
        }
    }

  svn_pool_destroy(subpool);

  return SVN_NO_ERROR;
}
Пример #26
0
svn_error_t *
svn_fs_x__dag_clone_child(dag_node_t **child_p,
                          dag_node_t *parent,
                          const char *parent_path,
                          const char *name,
                          const svn_fs_x__id_part_t *copy_id,
                          const svn_fs_x__id_part_t *txn_id,
                          svn_boolean_t is_parent_copyroot,
                          apr_pool_t *pool)
{
  dag_node_t *cur_entry; /* parent's current entry named NAME */
  const svn_fs_id_t *new_node_id; /* node id we'll put into NEW_NODE */
  svn_fs_t *fs = svn_fs_x__dag_get_fs(parent);
  apr_pool_t *subpool = svn_pool_create(pool);

  /* First check that the parent is mutable. */
  if (! svn_fs_x__dag_check_mutable(parent))
    return svn_error_createf
      (SVN_ERR_FS_NOT_MUTABLE, NULL,
       "Attempted to clone child of non-mutable node");

  /* Make sure that NAME is a single path component. */
  if (! svn_path_is_single_path_component(name))
    return svn_error_createf
      (SVN_ERR_FS_NOT_SINGLE_PATH_COMPONENT, NULL,
       "Attempted to make a child clone with an illegal name '%s'", name);

  /* Find the node named NAME in PARENT's entries list if it exists. */
  SVN_ERR(svn_fs_x__dag_open(&cur_entry, parent, name, pool, subpool));

  /* Check for mutability in the node we found.  If it's mutable, we
     don't need to clone it. */
  if (svn_fs_x__dag_check_mutable(cur_entry))
    {
      /* This has already been cloned */
      new_node_id = cur_entry->id;
    }
  else
    {
      node_revision_t *noderev, *parent_noderev;

      /* Go get a fresh NODE-REVISION for current child node. */
      SVN_ERR(get_node_revision(&noderev, cur_entry));

      if (is_parent_copyroot)
        {
          SVN_ERR(get_node_revision(&parent_noderev, parent));
          noderev->copyroot_rev = parent_noderev->copyroot_rev;
          noderev->copyroot_path = apr_pstrdup(pool,
                                               parent_noderev->copyroot_path);
        }

      noderev->copyfrom_path = NULL;
      noderev->copyfrom_rev = SVN_INVALID_REVNUM;

      noderev->predecessor_id = svn_fs_x__id_copy(cur_entry->id, pool);
      if (noderev->predecessor_count != -1)
        noderev->predecessor_count++;
      noderev->created_path = svn_fspath__join(parent_path, name, pool);

      SVN_ERR(svn_fs_x__create_successor(&new_node_id, fs, cur_entry->id,
                                          noderev, copy_id, txn_id, pool));

      /* Replace the ID in the parent's ENTRY list with the ID which
         refers to the mutable clone of this child. */
      SVN_ERR(set_entry(parent, name, new_node_id, noderev->kind, txn_id,
                        pool));
    }

  /* Initialize the youngster. */
  svn_pool_destroy(subpool);
  return svn_fs_x__dag_get_node(child_p, fs, new_node_id, pool);
}
Пример #27
0
static svn_error_t *
end_element(void *baton, int state, const char *nspace, const char *elt_name)
{
  replay_baton_t *rb = baton;

  const svn_ra_neon__xml_elm_t *elm
    = svn_ra_neon__lookup_xml_elem(editor_report_elements, nspace, elt_name);

  if (! elm)
    return SVN_NO_ERROR;

  switch (elm->id)
    {
    case ELEM_editor_report:
      if (rb->dirs->nelts)
        svn_pool_destroy(APR_ARRAY_IDX(rb->dirs, 0, dir_item_t).pool);

      return SVN_NO_ERROR;
      break;

    case ELEM_apply_textdelta:
      SVN_ERR(svn_stream_close(rb->base64_decoder));

      rb->whandler = NULL;
      rb->whandler_baton = NULL;
      rb->svndiff_decoder = NULL;
      rb->base64_decoder = NULL;
      break;

    case ELEM_change_file_prop:
    case ELEM_change_dir_prop:
      {
        const svn_string_t *decoded_value;

        if (rb->prop_accum)
          {
            const svn_string_t *prop;

            prop = svn_stringbuf__morph_into_string(rb->prop_accum);
            decoded_value = svn_base64_decode_string(prop, rb->prop_pool);
          }
        else
          decoded_value = NULL; /* It's a delete */

        if (elm->id == ELEM_change_dir_prop)
          SVN_ERR(rb->editor->change_dir_prop(TOP_DIR(rb).baton,
                                              rb->prop_name,
                                              decoded_value,
                                              TOP_DIR(rb).pool));
        else
          SVN_ERR(rb->editor->change_file_prop(rb->file_baton,
                                               rb->prop_name,
                                               decoded_value,
                                               TOP_DIR(rb).file_pool));
      }
      break;

    default:
      break;
    }

  return SVN_NO_ERROR;
}
Пример #28
0
svn_error_t *
svn_wc__internal_translated_file(const char **xlated_abspath,
                                 const char *src_abspath,
                                 svn_wc__db_t *db,
                                 const char *versioned_abspath,
                                 apr_uint32_t flags,
                                 svn_cancel_func_t cancel_func,
                                 void *cancel_baton,
                                 apr_pool_t *result_pool,
                                 apr_pool_t *scratch_pool)
{
  svn_subst_eol_style_t style;
  const char *eol;
  apr_hash_t *keywords;
  svn_boolean_t special;

  SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath));
  SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_abspath));
  SVN_ERR(svn_wc__get_translate_info(&style, &eol,
                                     &keywords,
                                     &special,
                                     db, versioned_abspath, NULL, FALSE,
                                     scratch_pool, scratch_pool));

  if (! svn_subst_translation_required(style, eol, keywords, special, TRUE)
      && (! (flags & SVN_WC_TRANSLATE_FORCE_COPY)))
    {
      /* Translation would be a no-op, so return the original file. */
      *xlated_abspath = src_abspath;
    }
  else  /* some translation (or copying) is necessary */
    {
      const char *tmp_dir;
      const char *tmp_vfile;
      svn_boolean_t repair_forced
          = (flags & SVN_WC_TRANSLATE_FORCE_EOL_REPAIR) != 0;
      svn_boolean_t expand = (flags & SVN_WC_TRANSLATE_TO_NF) == 0;

      if (flags & SVN_WC_TRANSLATE_USE_GLOBAL_TMP)
        tmp_dir = NULL;
      else
        SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmp_dir, db, versioned_abspath,
                                               scratch_pool, scratch_pool));

      SVN_ERR(svn_io_open_unique_file3(NULL, &tmp_vfile, tmp_dir,
                (flags & SVN_WC_TRANSLATE_NO_OUTPUT_CLEANUP)
                  ? svn_io_file_del_none
                  : svn_io_file_del_on_pool_cleanup,
                result_pool, scratch_pool));

      /* ### ugh. the repair behavior does NOT match the docstring. bleah.
         ### all of these translation functions are crap and should go
         ### away anyways. we'll just deprecate most of the functions and
         ### properly document the survivors */

      if (expand)
        {
          /* from normal form */

          repair_forced = TRUE;
        }
      else
        {
          /* to normal form */

          if (style == svn_subst_eol_style_native)
            eol = SVN_SUBST_NATIVE_EOL_STR;
          else if (style == svn_subst_eol_style_fixed)
            repair_forced = TRUE;
          else if (style != svn_subst_eol_style_none)
            return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL);
        }

      SVN_ERR(svn_subst_copy_and_translate4(src_abspath, tmp_vfile,
                                            eol, repair_forced,
                                            keywords,
                                            expand,
                                            special,
                                            cancel_func, cancel_baton,
                                            result_pool));

      *xlated_abspath = tmp_vfile;
    }

  return SVN_NO_ERROR;
}
Пример #29
0
/* This implements the `svn_opt_subcommand_t' interface. */
svn_error_t *
svn_cl__list(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 *subpool = svn_pool_create(pool);
  apr_uint32_t dirent_fields;
  struct print_baton pb;
  svn_boolean_t seen_nonexistent_target = FALSE;
  svn_error_t *err;

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

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

  if (opt_state->xml)
    {
      /* The XML output contains all the information, so "--verbose"
         does not apply. */
      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("lists", pool));
    }
  else
    {
      if (opt_state->incremental)
        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                _("'incremental' option only valid in XML "
                                  "mode"));
    }

  if (opt_state->verbose || opt_state->xml)
    dirent_fields = SVN_DIRENT_ALL;
  else
    dirent_fields = SVN_DIRENT_KIND; /* the only thing we actually need... */

  pb.ctx = ctx;
  pb.verbose = opt_state->verbose;

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

  /* For each target, try to list it. */
  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_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));

      if (opt_state->xml)
        {
          svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
          svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "list",
                                "path", truepath[0] == '\0' ? "." : truepath,
                                NULL);
          SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
        }

      err = svn_client_list2(truepath, &peg_revision,
                             &(opt_state->start_revision),
                             opt_state->depth,
                             dirent_fields,
                             (opt_state->xml || opt_state->verbose),
                             opt_state->xml ? print_dirent_xml : print_dirent,
                             &pb, ctx, subpool);

      if (err)
        {
          /* If one of the targets is a non-existent URL or wc-entry,
             don't bail out.  Just warn and move on to the next target. */
          if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND ||
              err->apr_err == SVN_ERR_FS_NOT_FOUND)
              svn_handle_warning2(stderr, err, "svn: ");
          else
              return svn_error_trace(err);

          svn_error_clear(err);
          err = NULL;
          seen_nonexistent_target = TRUE;
        }

      if (opt_state->xml)
        {
          svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
          svn_xml_make_close_tag(&sb, pool, "list");
          SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
        }
    }

  svn_pool_destroy(subpool);

  if (opt_state->xml && ! opt_state->incremental)
    SVN_ERR(svn_cl__xml_print_footer("lists", pool));

  if (seen_nonexistent_target)
    return svn_error_create(
      SVN_ERR_ILLEGAL_TARGET, NULL,
      _("Could not list all targets because some targets don't exist"));
  else
    return SVN_NO_ERROR;
}
Пример #30
0
static svn_error_t *
mkdir_urls(svn_commit_info_t **commit_info_p,
           const apr_array_header_t *urls,
           svn_boolean_t make_parents,
           const apr_hash_t *revprop_table,
           svn_client_ctx_t *ctx,
           apr_pool_t *pool)
{
  svn_ra_session_t *ra_session = NULL;
  const svn_delta_editor_t *editor;
  void *edit_baton;
  void *commit_baton;
  const char *log_msg;
  apr_array_header_t *targets;
  apr_hash_t *targets_hash;
  apr_hash_t *commit_revprops;
  svn_error_t *err;
  const char *common;
  int i;

  /* Find any non-existent parent directories */
  if (make_parents)
    {
      apr_array_header_t *all_urls = apr_array_make(pool, urls->nelts,
                                                    sizeof(const char *));
      const char *first_url = APR_ARRAY_IDX(urls, 0, const char *);
      apr_pool_t *iterpool = svn_pool_create(pool);

      SVN_ERR(svn_client__open_ra_session_internal(&ra_session, first_url,
                                                   NULL, NULL, NULL, FALSE,
                                                   TRUE, ctx, pool));

      for (i = 0; i < urls->nelts; i++)
        {
          const char *url = APR_ARRAY_IDX(urls, i, const char *);

          svn_pool_clear(iterpool);
          SVN_ERR(add_url_parents(ra_session, url, all_urls, iterpool, pool));
        }

      svn_pool_destroy(iterpool);

      urls = all_urls;
    }

  /* Condense our list of mkdir targets. */
  SVN_ERR(svn_path_condense_targets(&common, &targets, urls, FALSE, pool));
  SVN_ERR(svn_hash_from_cstring_keys(&targets_hash, targets, pool));
  SVN_ERR(svn_hash_keys(&targets, targets_hash, pool));

  if (! targets->nelts)
    {
      const char *bname;
      svn_path_split(common, &common, &bname, pool);
      APR_ARRAY_PUSH(targets, const char *) = bname;
    }
  else
    {
      svn_boolean_t resplit = FALSE;

      /* We can't "mkdir" the root of an editor drive, so if one of
         our targets is the empty string, we need to back everything
         up by a path component. */
      for (i = 0; i < targets->nelts; i++)
        {
          const char *path = APR_ARRAY_IDX(targets, i, const char *);
          if (! *path)
            {
              resplit = TRUE;
              break;
            }
        }
      if (resplit)
        {
          const char *bname;
          svn_path_split(common, &common, &bname, pool);
          for (i = 0; i < targets->nelts; i++)
            {
              const char *path = APR_ARRAY_IDX(targets, i, const char *);
              path = svn_path_join(bname, path, pool);
              APR_ARRAY_IDX(targets, i, const char *) = path;
            }
        }
    }
  qsort(targets->elts, targets->nelts, targets->elt_size, 
        svn_sort_compare_paths);

  /* Create new commit items and add them to the array. */
  if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx))
    {
      svn_client_commit_item3_t *item;
      const char *tmp_file;
      apr_array_header_t *commit_items
        = apr_array_make(pool, targets->nelts, sizeof(item));

      for (i = 0; i < targets->nelts; i++)
        {
          const char *path = APR_ARRAY_IDX(targets, i, const char *);
          SVN_ERR(svn_client_commit_item_create
                  ((const svn_client_commit_item3_t **) &item, pool));
          item->url = svn_path_join(common, path, pool);
          item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
          APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
        }

      SVN_ERR(svn_client__get_log_msg(&log_msg, &tmp_file, commit_items,
                                      ctx, pool));

      if (! log_msg)
        return SVN_NO_ERROR;
    }
  else