Ejemplo n.º 1
0
svn_error_t *
svn_fs_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path,
            const char *token, const char *comment,
            svn_boolean_t is_dav_comment, apr_time_t expiration_date,
            svn_revnum_t current_rev, svn_boolean_t steal_lock,
            apr_pool_t *pool)
{
  /* Enforce that the comment be xml-escapable. */
  if (comment)
    {
      if (! svn_xml_is_xml_safe(comment, strlen(comment)))
        return svn_error_create
          (SVN_ERR_XML_UNESCAPABLE_DATA, NULL,
           _("Lock comment contains illegal characters"));
    }

  /* Enforce that the token be an XML-safe URI. */
  if (token)
    {
      const char *c;

      if (strncmp(token, "opaquelocktoken:", 16))
        return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
                                 _("Lock token URI '%s' has bad scheme; "
                                   "expected '%s'"),
                                 token, "opaquelocktoken");

      for (c = token; *c; c++)
        if (! svn_ctype_isascii(*c))
          return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
                                   _("Lock token '%s' is not ASCII "
                                     "at byte %u"),
                                   token, (unsigned)(c - token));

      /* strlen(token) == c - token. */
      if (! svn_xml_is_xml_safe(token, c - token))
        return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
                                 _("Lock token URI '%s' is not XML-safe"),
                                 token);
    }

  if (expiration_date < 0)
        return svn_error_create
          (SVN_ERR_INCORRECT_PARAMS, NULL,
           _("Negative expiration date passed to svn_fs_lock"));

  return svn_error_trace(fs->vtable->lock(lock, fs, path, token, comment,
                                          is_dav_comment, expiration_date,
                                          current_rev, steal_lock, pool));
}
Ejemplo n.º 2
0
/* Send a property named NAME with value VAL in an element named ELEM_NAME.
   Quote NAME and base64-encode VAL if necessary. */
static svn_error_t *
send_prop(struct file_rev_baton *frb,
          const char *elem_name,
          const char *name,
          const svn_string_t *val,
          apr_pool_t *pool)
{
  name = apr_xml_quote_string(pool, name, 1);

  if (svn_xml_is_xml_safe(val->data, val->len))
    {
      svn_stringbuf_t *tmp = NULL;
      svn_xml_escape_cdata_string(&tmp, val, pool);
      val = svn_string_create(tmp->data, pool);
      SVN_ERR(dav_svn__brigade_printf(frb->bb, frb->output,
                                      "<S:%s name=\"%s\">%s</S:%s>" DEBUG_CR,
                                      elem_name, name, val->data, elem_name));
    }
  else
    {
      val = svn_base64_encode_string2(val, TRUE, pool);
      SVN_ERR(dav_svn__brigade_printf(frb->bb, frb->output,
                                      "<S:%s name=\"%s\" encoding=\"base64\">"
                                      "%s</S:%s>" DEBUG_CR,
                                      elem_name, name, val->data, elem_name));
    }

  return SVN_NO_ERROR;
}
Ejemplo n.º 3
0
svn_error_t *svn_ra_lock(svn_ra_session_t *session,
                         apr_hash_t *path_revs,
                         const char *comment,
                         svn_boolean_t steal_lock,
                         svn_ra_lock_callback_t lock_func,
                         void *lock_baton,
                         apr_pool_t *pool)
{
  apr_hash_index_t *hi;

  for (hi = apr_hash_first(pool, path_revs); hi; hi = apr_hash_next(hi))
    {
      const char *path = svn__apr_hash_index_key(hi);

      SVN_ERR_ASSERT(*path != '/');
    }

  if (comment && ! svn_xml_is_xml_safe(comment, strlen(comment)))
    return svn_error_create
      (SVN_ERR_XML_UNESCAPABLE_DATA, NULL,
       _("Lock comment contains illegal characters"));

  return session->vtable->lock(session, path_revs, comment, steal_lock,
                               lock_func, lock_baton, pool);
}
Ejemplo n.º 4
0
/* Helper function for svn_ra_neon__do_proppatch() below. */
static void
append_setprop(svn_stringbuf_t *body,
               const char *name,
               const svn_string_t *value,
               apr_pool_t *pool)
{
  const char *encoding = "";
  const char *xml_safe;
  const char *xml_tag_name;

  /* Map property names to namespaces */
#define NSLEN (sizeof(SVN_PROP_PREFIX) - 1)
  if (strncmp(name, SVN_PROP_PREFIX, NSLEN) == 0)
    {
      xml_tag_name = apr_pstrcat(pool, "S:", name + NSLEN, NULL);
    }
#undef NSLEN
  else
    {
      xml_tag_name = apr_pstrcat(pool, "C:", name, NULL);
    }

  /* If there is no value, just generate an empty tag and get outta
     here. */
  if (! value)
    {
      svn_stringbuf_appendcstr(body,
                               apr_psprintf(pool, "<%s />", xml_tag_name));
      return;
    }

  /* If a property is XML-safe, XML-encode it.  Else, base64-encode
     it. */
  if (svn_xml_is_xml_safe(value->data, value->len))
    {
      svn_stringbuf_t *xml_esc = NULL;
      svn_xml_escape_cdata_string(&xml_esc, value, pool);
      xml_safe = xml_esc->data;
    }
  else
    {
      const svn_string_t *base64ed = svn_base64_encode_string2(value, TRUE,
                                                               pool);
      encoding = " V:encoding=\"base64\"";
      xml_safe = base64ed->data;
    }

  svn_stringbuf_appendcstr(body,
                           apr_psprintf(pool,"<%s %s>%s</%s>",
                                        xml_tag_name, encoding,
                                        xml_safe, xml_tag_name));
  return;
}
Ejemplo n.º 5
0
dav_error *
dav_svn__get_inherited_props_report(const dav_resource *resource,
                                    const apr_xml_doc *doc,
                                    ap_filter_t *output)
{
  svn_error_t *serr;
  dav_error *derr = NULL;
  apr_xml_elem *child;
  apr_array_header_t *inherited_props;
  dav_svn__authz_read_baton arb;
  int ns;
  apr_bucket_brigade *bb;
  const char *path = "/";
  svn_fs_root_t *root;
  int i;
  svn_revnum_t rev = SVN_INVALID_REVNUM;
  apr_pool_t *iterpool;

  /* Sanity check. */
  if (!resource->info->repos_path)
    return dav_svn__new_error(resource->pool, HTTP_BAD_REQUEST, 0,
                              "The request does not specify a repository path");
  ns = dav_svn__find_ns(doc->namespaces, SVN_XML_NAMESPACE);
  if (ns == -1)
    {
      return dav_svn__new_error_svn(resource->pool, HTTP_BAD_REQUEST, 0,
                                    "The request does not contain the 'svn:' "
                                    "namespace, so it is not going to have "
                                    "certain required elements");
    }

  iterpool = svn_pool_create(resource->pool);

  for (child = doc->root->first_child;
       child != NULL;
       child = child->next)
    {
      /* if this element isn't one of ours, then skip it */
      if (child->ns != ns)
        continue;

      if (strcmp(child->name, SVN_DAV__REVISION) == 0)
        {
          rev = SVN_STR_TO_REV(dav_xml_get_cdata(child, iterpool, 1));
        }
      else if (strcmp(child->name, SVN_DAV__PATH) == 0)
        {
          path = dav_xml_get_cdata(child, resource->pool, 0);
          if ((derr = dav_svn__test_canonical(path, iterpool)))
            return derr;
          path = svn_fspath__join(resource->info->repos_path, path,
                                  resource->pool);
        }
      /* else unknown element; skip it */
    }

  /* Build authz read baton */
  arb.r = resource->info->r;
  arb.repos = resource->info->repos;

  /* Build inherited property brigade */
  bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);

  serr = svn_fs_revision_root(&root, resource->info->repos->fs,
                              rev, resource->pool);
  if (serr != NULL)
    return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                "couldn't retrieve revision root",
                                resource->pool);

  serr = svn_repos_fs_get_inherited_props(&inherited_props, root, path, NULL,
                                          dav_svn__authz_read_func(&arb),
                                          &arb, resource->pool, iterpool);
  if (serr)
    {
      derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, NULL,
                                  resource->pool);
      goto cleanup;
    }

  serr = dav_svn__brigade_puts(bb, output,
                               DAV_XML_HEADER DEBUG_CR
                               "<S:" SVN_DAV__INHERITED_PROPS_REPORT " "
                               "xmlns:S=\"" SVN_XML_NAMESPACE "\" "
                               "xmlns:D=\"DAV:\">" DEBUG_CR);
  if (serr)
    {
      derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, NULL,
                                  resource->pool);
      goto cleanup;
    }

  for (i = 0; i < inherited_props->nelts; i++)
    {
      svn_prop_inherited_item_t *elt =
        APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *);

      svn_pool_clear(iterpool);

      serr = dav_svn__brigade_printf(
        bb, output,
        "<S:" SVN_DAV__IPROP_ITEM ">"
        DEBUG_CR
        "<S:" SVN_DAV__IPROP_PATH ">%s</S:" SVN_DAV__IPROP_PATH ">"
        DEBUG_CR,
        apr_xml_quote_string(resource->pool, elt->path_or_url, 0));

      if (!serr)
        {
          apr_hash_index_t *hi;

          for (hi = apr_hash_first(resource->pool, elt->prop_hash);
               hi;
               hi = apr_hash_next(hi))
            {
              const char *propname = apr_hash_this_key(hi);
              svn_string_t *propval = apr_hash_this_val(hi);
              const char *xml_safe;

              serr = dav_svn__brigade_printf(
                bb, output,
                "<S:" SVN_DAV__IPROP_PROPNAME ">%s</S:"
                SVN_DAV__IPROP_PROPNAME ">" DEBUG_CR,
                apr_xml_quote_string(iterpool, propname, 0));

              if (!serr)
                {
                  if (svn_xml_is_xml_safe(propval->data, propval->len))
                    {
                      svn_stringbuf_t *tmp = NULL;
                      svn_xml_escape_cdata_string(&tmp, propval,
                                                  iterpool);
                      xml_safe = tmp->data;
                      serr = dav_svn__brigade_printf(
                        bb, output,
                        "<S:" SVN_DAV__IPROP_PROPVAL ">%s</S:"
                        SVN_DAV__IPROP_PROPVAL ">" DEBUG_CR, xml_safe);
                    }
                  else
                    {
                      xml_safe = svn_base64_encode_string2(
                        propval, TRUE, iterpool)->data;
                      serr = dav_svn__brigade_printf(
                        bb, output,
                        "<S:" SVN_DAV__IPROP_PROPVAL
                        " encoding=\"base64\"" ">%s</S:"
                        SVN_DAV__IPROP_PROPVAL ">" DEBUG_CR, xml_safe);
                    }
                }

              if (serr)
                break;
            }
          if (!serr)
            serr = dav_svn__brigade_printf(bb, output,
                                           "</S:" SVN_DAV__IPROP_ITEM ">"
                                           DEBUG_CR);
        }

      if (serr)
        {
          derr = dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                      "Error ending REPORT response.",
                                      resource->pool);
          goto cleanup;
        }
    }

  if ((serr = dav_svn__brigade_puts(bb, output,
                                    "</S:" SVN_DAV__INHERITED_PROPS_REPORT ">"
                                    DEBUG_CR)))
    {
      derr = dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
                                  "Error ending REPORT response.",
                                  resource->pool);
      goto cleanup;
    }

 cleanup:

  /* Log this 'high level' svn action. */
  dav_svn__operational_log(resource->info,
                           svn_log__get_inherited_props(path, rev,
                                                        resource->pool));
  svn_pool_destroy(iterpool);
  return dav_svn__final_flush_or_error(resource->info->r, bb, output,
                                       derr, resource->pool);
}
Ejemplo n.º 6
0
static dav_error *
db_output_value(dav_db *db,
                const dav_prop_name *name,
                dav_xmlns_info *xi,
                apr_text_header *phdr,
                int *found)
{
  const char *prefix;
  const char *s;
  svn_string_t *propval;
  dav_error *err;
  apr_pool_t *pool = db->resource->pool;

  if ((err = get_value(db, name, &propval)) != NULL)
    return err;

  /* return whether the prop was found, then punt or handle it. */
  *found = (propval != NULL);
  if (propval == NULL)
    return NULL;

  if (strcmp(name->ns, SVN_DAV_PROP_NS_CUSTOM) == 0)
    prefix = "C:";
  else
    prefix = "S:";

  if (propval->len == 0)
    {
      /* empty value. add an empty elem. */
      s = apr_psprintf(pool, "<%s%s/>" DEBUG_CR, prefix, name->name);
      apr_text_append(pool, phdr, s);
    }
  else
    {
      /* add <prefix:name [V:encoding="base64"]>value</prefix:name> */
      const char *xml_safe;
      const char *encoding = "";

      /* Ensure XML-safety of our property values before sending them
         across the wire. */
      if (! svn_xml_is_xml_safe(propval->data, propval->len))
        {
          const svn_string_t *enc_propval
            = svn_base64_encode_string2(propval, TRUE, pool);
          xml_safe = enc_propval->data;
          encoding = " V:encoding=\"base64\"";
        }
      else
        {
          svn_stringbuf_t *xmlval = NULL;
          svn_xml_escape_cdata_string(&xmlval, propval, pool);
          xml_safe = xmlval->data;
        }

      s = apr_psprintf(pool, "<%s%s%s>", prefix, name->name, encoding);
      apr_text_append(pool, phdr, s);

      /* the value is in our pool which means it has the right lifetime. */
      /* ### at least, per the current mod_dav architecture/API */
      apr_text_append(pool, phdr, xml_safe);

      s = apr_psprintf(pool, "</%s%s>" DEBUG_CR, prefix, name->name);
      apr_text_append(pool, phdr, s);
    }

  return NULL;
}
Ejemplo n.º 7
0
/* Transmit LOCKS (a hash of Subversion filesystem locks keyed by
   path) across OUTPUT using BB.  Use POOL for necessary allocations.

   NOTE:  As written, this function currently returns one of only two
   status values -- "success", and "we had trouble writing out to the
   output stream".  If you need to return something more interesting,
   you'll probably want to generate dav_error's here instead of
   passing back only apr_status_t's.  */
static apr_status_t
send_get_lock_response(apr_hash_t *locks,
                       ap_filter_t *output,
                       apr_bucket_brigade *bb,
                       apr_pool_t *pool)
{
  apr_pool_t *subpool;
  apr_hash_index_t *hi;

  /* start sending report */
  SVN_APR_ERR(ap_fprintf(output, bb,
                         DAV_XML_HEADER DEBUG_CR
                         "<S:get-locks-report xmlns:S=\"" SVN_XML_NAMESPACE
                         "\" xmlns:D=\"DAV:\">" DEBUG_CR));

  /* stream the locks */
  subpool = svn_pool_create(pool);
  for (hi = apr_hash_first(pool, locks); hi; hi = apr_hash_next(hi))
    {
      void *val;
      const svn_lock_t *lock;

      svn_pool_clear(subpool);
      apr_hash_this(hi, NULL, NULL, &val);
      lock = val;

      /* Begin the <S:lock> tag, transmitting the path, token, and
         creation date. */
      SVN_APR_ERR(ap_fprintf(output, bb,
                             "<S:lock>" DEBUG_CR
                             "<S:path>%s</S:path>" DEBUG_CR
                             "<S:token>%s</S:token>" DEBUG_CR
                             "<S:creationdate>%s</S:creationdate>" DEBUG_CR,
                             apr_xml_quote_string(subpool, lock->path, 1),
                             apr_xml_quote_string(subpool, lock->token, 1),
                             svn_time_to_cstring(lock->creation_date,
                                                 subpool)));

      /* Got expiration date?  Tell the client. */
      if (lock->expiration_date)
        SVN_APR_ERR(ap_fprintf(output, bb,
                               "<S:expirationdate>%s</S:expirationdate>"
                               DEBUG_CR,
                               svn_time_to_cstring(lock->expiration_date,
                                                   subpool)));

      /* Transmit the lock ownership information. */
      if (lock->owner)
        {
          const char *owner;
          svn_boolean_t owner_base64 = FALSE;

          if (svn_xml_is_xml_safe(lock->owner, strlen(lock->owner)))
            {
              owner = apr_xml_quote_string(subpool, lock->owner, 1);
            }
          else
            {
              svn_string_t owner_string;
              const svn_string_t *encoded_owner;

              owner_string.data = lock->owner;
              owner_string.len = strlen(lock->owner);
              encoded_owner = svn_base64_encode_string2(&owner_string, TRUE,
                                                        subpool);
              owner = encoded_owner->data;
              owner_base64 = TRUE;
            }
          SVN_APR_ERR(ap_fprintf(output, bb,
                                 "<S:owner %s>%s</S:owner>" DEBUG_CR,
                                 owner_base64 ? "encoding=\"base64\"" : "",
                                 owner));
        }

      /* If the lock carries a comment, transmit that, too. */
      if (lock->comment)
        {
          const char *comment;
          svn_boolean_t comment_base64 = FALSE;

          if (svn_xml_is_xml_safe(lock->comment, strlen(lock->comment)))
            {
              comment = apr_xml_quote_string(subpool, lock->comment, 1);
            }
          else
            {
              svn_string_t comment_string;
              const svn_string_t *encoded_comment;

              comment_string.data = lock->comment;
              comment_string.len = strlen(lock->comment);
              encoded_comment = svn_base64_encode_string2(&comment_string,
                                                          TRUE, subpool);
              comment = encoded_comment->data;
              comment_base64 = TRUE;
            }
          SVN_APR_ERR(ap_fprintf(output, bb,
                                 "<S:comment %s>%s</S:comment>" DEBUG_CR,
                                 comment_base64 ? "encoding=\"base64\"" : "",
                                 comment));
        }

      /* Okay, finish up this lock by closing the <S:lock> tag. */
      SVN_APR_ERR(ap_fprintf(output, bb, "</S:lock>" DEBUG_CR));
    }
  svn_pool_destroy(subpool);

  /* Finish the report */
  SVN_APR_ERR(ap_fprintf(output, bb, "</S:get-locks-report>" DEBUG_CR));

  return APR_SUCCESS;
}
Ejemplo n.º 8
0
/* This implements `svn_log_entry_receiver_t'.
   BATON is a `struct log_receiver_baton *'.  */
static svn_error_t *
log_receiver(void *baton,
             svn_log_entry_t *log_entry,
             apr_pool_t *pool)
{
  struct log_receiver_baton *lrb = baton;
  apr_pool_t *iterpool = svn_pool_create(pool);

  SVN_ERR(maybe_send_header(lrb));

  if (log_entry->revision == SVN_INVALID_REVNUM)
    {
      /* If the stack depth is zero, we've seen the last revision, so don't
         send it, just return.  The footer will be sent later. */
      if (lrb->stack_depth == 0)
        return SVN_NO_ERROR;
      else
        lrb->stack_depth--;
    }

  SVN_ERR(dav_svn__brigade_printf(lrb->bb, lrb->output,
                                  "<S:log-item>" DEBUG_CR "<D:version-name>%ld"
                                  "</D:version-name>" DEBUG_CR,
                                  log_entry->revision));

  if (log_entry->revprops)
    {
      apr_hash_index_t *hi;
      for (hi = apr_hash_first(pool, log_entry->revprops);
           hi != NULL;
           hi = apr_hash_next(hi))
        {
          char *name;
          void *val;
          const svn_string_t *value;
          const char *encoding_str = "";

          svn_pool_clear(iterpool);
          apr_hash_this(hi, (void *)&name, NULL, &val);
          value = val;

          /* If the client is okay with us encoding binary (or really,
             any non-XML-safe) property values, do so as necessary. */
          if (lrb->encode_binary_props)
            {
              if (! svn_xml_is_xml_safe(value->data, value->len))
                {
                  value = svn_base64_encode_string2(value, TRUE, iterpool);
                  encoding_str = " encoding=\"base64\"";
                }
            }

          if (strcmp(name, SVN_PROP_REVISION_AUTHOR) == 0)
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     "<D:creator-displayname%s>%s</D:creator-displayname>"
                     DEBUG_CR, encoding_str,
                     apr_xml_quote_string(iterpool, value->data, 0)));
          else if (strcmp(name, SVN_PROP_REVISION_DATE) == 0)
            /* ### this should be DAV:creation-date, but we need to format
               ### that date a bit differently */
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     "<S:date%s>%s</S:date>" DEBUG_CR, encoding_str,
                     apr_xml_quote_string(iterpool, value->data, 0)));
          else if (strcmp(name, SVN_PROP_REVISION_LOG) == 0)
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     "<D:comment%s>%s</D:comment>" DEBUG_CR, encoding_str,
                     apr_xml_quote_string(pool,
                                          svn_xml_fuzzy_escape(value->data,
                                                               iterpool), 0)));
          else
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     "<S:revprop name=\"%s\"%s>%s</S:revprop>" DEBUG_CR,
                     apr_xml_quote_string(iterpool, name, 0), encoding_str,
                     apr_xml_quote_string(iterpool, value->data, 0)));
        }
    }

  if (log_entry->has_children)
    {
      SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output, "<S:has-children/>"));
      lrb->stack_depth++;
    }

  if (log_entry->subtractive_merge)
    SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                  "<S:subtractive-merge/>"));

  if (log_entry->changed_paths2)
    {
      apr_hash_index_t *hi;
      char *path;

      for (hi = apr_hash_first(pool, log_entry->changed_paths2);
           hi != NULL;
           hi = apr_hash_next(hi))
        {
          void *val;
          svn_log_changed_path2_t *log_item;
          const char *close_element = NULL;

          svn_pool_clear(iterpool);
          apr_hash_this(hi, (void *) &path, NULL, &val);
          log_item = val;

          /* ### todo: is there a D: namespace equivalent for
             `changed-path'?  Should use it if so. */
          switch (log_item->action)
            {
            case 'A':
              if (log_item->copyfrom_path
                  && SVN_IS_VALID_REVNUM(log_item->copyfrom_rev))
                SVN_ERR(dav_svn__brigade_printf
                        (lrb->bb, lrb->output,
                         "<S:added-path copyfrom-path=\"%s\""
                         " copyfrom-rev=\"%ld\"",
                         apr_xml_quote_string(iterpool,
                                              log_item->copyfrom_path,
                                              1), /* escape quotes */
                         log_item->copyfrom_rev));
              else
                SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                              "<S:added-path"));

              close_element = "S:added-path";
              break;

            case 'R':
              if (log_item->copyfrom_path
                  && SVN_IS_VALID_REVNUM(log_item->copyfrom_rev))
                SVN_ERR(dav_svn__brigade_printf
                        (lrb->bb, lrb->output,
                         "<S:replaced-path copyfrom-path=\"%s\""
                         " copyfrom-rev=\"%ld\"",
                         apr_xml_quote_string(iterpool,
                                              log_item->copyfrom_path,
                                              1), /* escape quotes */
                         log_item->copyfrom_rev));
              else
                SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                              "<S:replaced-path"));

              close_element = "S:replaced-path";
              break;

            case 'D':
              SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                            "<S:deleted-path"));
              close_element = "S:deleted-path";
              break;

            case 'M':
              SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                            "<S:modified-path"));
              close_element = "S:modified-path";
              break;

            default:
              break;
            }

          /* If we need to close the element, then send the attributes
             that apply to all changed items and then close the element. */
          if (close_element)
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     " node-kind=\"%s\""
                     " text-mods=\"%s\""
                     " prop-mods=\"%s\">%s</%s>" DEBUG_CR,
                     svn_node_kind_to_word(log_item->node_kind),
                     svn_tristate__to_word(log_item->text_modified),
                     svn_tristate__to_word(log_item->props_modified),
                     apr_xml_quote_string(iterpool, path, 0),
                     close_element));
        }
    }

  svn_pool_destroy(iterpool);

  SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                "</S:log-item>" DEBUG_CR));

  return SVN_NO_ERROR;
}
Ejemplo n.º 9
0
/* This implements `svn_log_entry_receiver_t'.
   BATON is a `struct log_receiver_baton *'.  */
static svn_error_t *
log_receiver(void *baton,
             svn_log_entry_t *log_entry,
             apr_pool_t *pool)
{
  struct log_receiver_baton *lrb = baton;
  apr_pool_t *iterpool = svn_pool_create(pool);

  SVN_ERR(maybe_send_header(lrb));

  if (log_entry->revision == SVN_INVALID_REVNUM)
    {
      /* If the stack depth is zero, we've seen the last revision, so don't
         send it, just return.  The footer will be sent later. */
      if (lrb->stack_depth == 0)
        return SVN_NO_ERROR;
      else
        lrb->stack_depth--;
    }

  SVN_ERR(dav_svn__brigade_printf(lrb->bb, lrb->output,
                                  "<S:log-item>" DEBUG_CR "<D:version-name>%ld"
                                  "</D:version-name>" DEBUG_CR,
                                  log_entry->revision));

  if (log_entry->revprops)
    {
      apr_hash_index_t *hi;
      for (hi = apr_hash_first(pool, log_entry->revprops);
           hi != NULL;
           hi = apr_hash_next(hi))
        {
          char *name;
          void *val;
          const svn_string_t *value;
          const char *encoding_str = "";

          svn_pool_clear(iterpool);
          apr_hash_this(hi, (void *)&name, NULL, &val);
          value = val;

          /* If the client is okay with us encoding binary (or really,
             any non-XML-safe) property values, do so as necessary. */
          if (lrb->encode_binary_props)
            {
              if (! svn_xml_is_xml_safe(value->data, value->len))
                {
                  value = svn_base64_encode_string2(value, TRUE, iterpool);
                  encoding_str = " encoding=\"base64\"";
                }
            }

          if (strcmp(name, SVN_PROP_REVISION_AUTHOR) == 0)
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     "<D:creator-displayname%s>%s</D:creator-displayname>"
                     DEBUG_CR, encoding_str,
                     apr_xml_quote_string(iterpool, value->data, 0)));
          else if (strcmp(name, SVN_PROP_REVISION_DATE) == 0)
            /* ### this should be DAV:creation-date, but we need to format
               ### that date a bit differently */
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     "<S:date%s>%s</S:date>" DEBUG_CR, encoding_str,
                     apr_xml_quote_string(iterpool, value->data, 0)));
          else if (strcmp(name, SVN_PROP_REVISION_LOG) == 0)
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     "<D:comment%s>%s</D:comment>" DEBUG_CR, encoding_str,
                     apr_xml_quote_string(pool,
                                          svn_xml_fuzzy_escape(value->data,
                                                               iterpool), 0)));
          else
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     "<S:revprop name=\"%s\"%s>%s</S:revprop>" DEBUG_CR,
                     apr_xml_quote_string(iterpool, name, 0), encoding_str,
                     apr_xml_quote_string(iterpool, value->data, 0)));
        }
    }

  if (log_entry->has_children)
    {
      SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output, "<S:has-children/>"));
      lrb->stack_depth++;
    }

  if (log_entry->subtractive_merge)
    SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                  "<S:subtractive-merge/>"));

  if (log_entry->changed_paths2)
    {
      apr_hash_index_t *hi;
      char *path;

      for (hi = apr_hash_first(pool, log_entry->changed_paths2);
           hi != NULL;
           hi = apr_hash_next(hi))
        {
          void *val;
          svn_log_changed_path2_t *log_item;
          const char *close_element = NULL;

          svn_pool_clear(iterpool);
          apr_hash_this(hi, (void *) &path, NULL, &val);
          log_item = val;

          /* ### todo: is there a D: namespace equivalent for
             `changed-path'?  Should use it if so. */
          switch (log_item->action)
            {
            case 'A':
            case 'R':
              SVN_ERR(start_path_with_copy_from(&close_element, lrb,
                                                log_item, iterpool));
              break;

            case 'D':
              SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                            "<S:deleted-path"));
              close_element = "S:deleted-path";
              break;

            case 'M':
              SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                            "<S:modified-path"));
              close_element = "S:modified-path";
              break;

            default:
              break;
            }

          /* If we need to close the element, then send the attributes
             that apply to all changed items and then close the element. */
          if (close_element)
            SVN_ERR(dav_svn__brigade_printf
                    (lrb->bb, lrb->output,
                     " node-kind=\"%s\""
                     " text-mods=\"%s\""
                     " prop-mods=\"%s\">%s</%s>" DEBUG_CR,
                     svn_node_kind_to_word(log_item->node_kind),
                     svn_tristate__to_word(log_item->text_modified),
                     svn_tristate__to_word(log_item->props_modified),
                     apr_xml_quote_string(iterpool, path, 0),
                     close_element));
        }
    }

  svn_pool_destroy(iterpool);

  SVN_ERR(dav_svn__brigade_puts(lrb->bb, lrb->output,
                                "</S:log-item>" DEBUG_CR));

  /* In general APR will flush the brigade every 8000 bytes through the filter
     stack, but log items may not be generated that fast, especially in
     combination with authz and busy servers. We now explictly flush after
     log-item 4, 16, 64 and 256 to produce a few results fast.

     This introduces 4 full flushes of our brigade and the installed output
     filters at growing intervals and then falls back to the standard
     buffering of 8000 bytes + whatever buffers are added in output filters. */
  lrb->result_count++;
  if (lrb->result_count == lrb->next_forced_flush)
    {
      apr_status_t apr_err;

      /* This flush is similar to that in dav_svn__final_flush_or_error().

         Compared to using ap_filter_flush(), which we use in other place
         this adds a flush frame before flushing the brigade, to make output
         filters perform a flush as well */

      /* No brigade empty check. We want output filters to flush anyway */
      apr_err = ap_fflush(lrb->output, lrb->bb);
      if (apr_err)
        return svn_error_create(apr_err, NULL, NULL);

      /* Check for an aborted connection, just like our brigade write
         helper functions, since the brigade functions don't appear to
         be return useful errors when the connection is dropped. */
      if (lrb->output->c->aborted)
        return svn_error_create(SVN_ERR_APMOD_CONNECTION_ABORTED,
                                NULL, NULL);

      if (lrb->result_count < 256)
        lrb->next_forced_flush = lrb->next_forced_flush * 4;
    }

  return SVN_NO_ERROR;
}