svn_error_t *
svn_ra_neon__get_location_segments(svn_ra_session_t *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)

{
  svn_ra_neon__session_t *ras = session->priv;
  svn_stringbuf_t *request_body;
  svn_error_t *err;
  get_location_segments_baton_t request_baton;
  const char *bc_url;
  const char *bc_relative;
  const char *bc;
  int status_code = 0;
  apr_pool_t *subpool = svn_pool_create(pool);

  /* Build the request body. */
  request_body = svn_stringbuf_create("", subpool);
  svn_stringbuf_appendcstr(request_body,
                           "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
                           DEBUG_CR "<S:get-location-segments xmlns:S=\""
                           SVN_XML_NAMESPACE "\" xmlns:D=\"DAV:\">" DEBUG_CR);

  /* Tack on the path... */
  svn_stringbuf_appendcstr(request_body, "<S:path>");
  svn_stringbuf_appendcstr(request_body, apr_xml_quote_string(subpool, path, 0));
  svn_stringbuf_appendcstr(request_body, "</S:path>" DEBUG_CR);

  /* ...and maybe a peg revision... */
  if (SVN_IS_VALID_REVNUM(peg_revision))
    svn_stringbuf_appendcstr
      (request_body, apr_psprintf(subpool,
                                  "<S:peg-revision>%ld</S:peg-revision>"
                                  DEBUG_CR, peg_revision));

  /* ...and maybe a start revision... */
  if (SVN_IS_VALID_REVNUM(start_rev))
    svn_stringbuf_appendcstr
      (request_body, apr_psprintf(subpool,
                                  "<S:start-revision>%ld</S:start-revision>"
                                  DEBUG_CR, start_rev));

  /* ...and maybe an end revision. */
  if (SVN_IS_VALID_REVNUM(end_rev))
    svn_stringbuf_appendcstr
      (request_body, apr_psprintf(subpool,
                                  "<S:end-revision>%ld</S:end-revision>"
                                  DEBUG_CR, end_rev));

  svn_stringbuf_appendcstr(request_body, "</S:get-location-segments>");

  request_baton.receiver = receiver;
  request_baton.receiver_baton = receiver_baton;
  request_baton.subpool = svn_pool_create(subpool);

  /* ras's URL may not exist in HEAD, and thus it's not safe to send
     it as the main argument to the REPORT request; it might cause
     dav_get_resource() to choke on the server.  So instead, we pass a
     baseline-collection URL, which we get from the PEG_REVISION.  */
  SVN_ERR(svn_ra_neon__get_baseline_info(&bc_url, &bc_relative, NULL, ras,
                                         ras->url->data, peg_revision,
                                         subpool));
  bc = svn_path_url_add_component2(bc_url, bc_relative, subpool);

  err = svn_ra_neon__parsed_request(ras, "REPORT", bc,
                                    request_body->data, NULL, NULL,
                                    gls_start_element, NULL, NULL,
                                    &request_baton, NULL, &status_code,
                                    FALSE, subpool);
  svn_pool_destroy(request_baton.subpool);
  svn_pool_destroy(subpool);

  /* Map status 501: Method Not Implemented to our not implemented error.
     1.0.x servers and older don't support this report. */
  if (status_code == 501)
    return svn_error_createf(SVN_ERR_RA_NOT_IMPLEMENTED, err,
                             _("'%s' REPORT not implemented"),
                             "get-location-segments");

  return err;
}
svn_error_t *
svn_ra_neon__get_locations(svn_ra_session_t *session,
                           apr_hash_t **locations,
                           const char *relative_path,
                           svn_revnum_t peg_revision,
                           const apr_array_header_t *location_revisions,
                           apr_pool_t *pool)
{
  svn_ra_neon__session_t *ras = session->priv;
  svn_stringbuf_t *request_body;
  svn_error_t *err;
  get_locations_baton_t request_baton;
  const char *relative_path_quoted;
  const char *bc_url;
  const char *bc_relative;
  const char *final_bc_url;
  int i;
  int status_code = 0;

  *locations = apr_hash_make(pool);

  request_body = svn_stringbuf_create("", pool);
  svn_stringbuf_appendcstr(request_body,
                           "<?xml version=\"1.0\" encoding=\"utf-8\"?>" DEBUG_CR
                           "<S:get-locations xmlns:S=\"" SVN_XML_NAMESPACE
                           "\" xmlns:D=\"DAV:\">" DEBUG_CR);

  svn_stringbuf_appendcstr(request_body, "<S:path>");
  /* We need to escape the path XML-wise. */
  relative_path_quoted = apr_xml_quote_string(pool, relative_path, 0);
  svn_stringbuf_appendcstr(request_body, relative_path_quoted);
  svn_stringbuf_appendcstr(request_body, "</S:path>" DEBUG_CR);
  svn_stringbuf_appendcstr(request_body,
                           apr_psprintf(pool,
                                        "<S:peg-revision>%ld"
                                        "</S:peg-revision>" DEBUG_CR,
                                        peg_revision));

  for (i = 0; i < location_revisions->nelts; ++i)
    {
      svn_revnum_t rev = APR_ARRAY_IDX(location_revisions, i, svn_revnum_t);
      svn_stringbuf_appendcstr(request_body,
                               apr_psprintf(pool,
                                            "<S:location-revision>%ld"
                                            "</S:location-revision>" DEBUG_CR,
                                            rev));
    }

  svn_stringbuf_appendcstr(request_body, "</S:get-locations>");

  request_baton.ras = ras;
  request_baton.hash = *locations;
  request_baton.pool = pool;

  /* ras's URL may not exist in HEAD, and thus it's not safe to send
     it as the main argument to the REPORT request; it might cause
     dav_get_resource() to choke on the server.  So instead, we pass a
     baseline-collection URL, which we get from the peg revision.  */
  SVN_ERR(svn_ra_neon__get_baseline_info(&bc_url, &bc_relative, NULL, ras,
                                         ras->url->data, peg_revision, pool));
  final_bc_url = svn_path_url_add_component2(bc_url, bc_relative, pool);

  err = svn_ra_neon__parsed_request(ras, "REPORT", final_bc_url,
                                    request_body->data, NULL, NULL,
                                    gloc_start_element, NULL, NULL,
                                    &request_baton, NULL, &status_code,
                                    FALSE, pool);

  /* Map status 501: Method Not Implemented to our not implemented error.
     1.0.x servers and older don't support this report. */
  if (status_code == 501)
    return svn_error_createf(SVN_ERR_RA_NOT_IMPLEMENTED, err,
                             _("'%s' REPORT not implemented"), "get-locations");

  return err;
}
Пример #3
0
svn_error_t *
svn_ra_neon__do_stat(svn_ra_session_t *session,
                     const char *path,
                     svn_revnum_t revision,
                     svn_dirent_t **dirent,
                     apr_pool_t *pool)
{
  svn_ra_neon__session_t *ras = session->priv;
  const char *url = ras->url->data;
  const char *final_url;
  apr_hash_t *resources;
  apr_hash_index_t *hi;
  svn_error_t *err;

  /* If we were given a relative path to append, append it. */
  if (path)
    url = svn_path_url_add_component(url, path, pool);

  /* Invalid revision means HEAD, which is just the public URL. */
  if (! SVN_IS_VALID_REVNUM(revision))
    {
      final_url = url;
    }
  else
    {
      /* Else, convert (rev, path) into an opaque server-generated URL. */
      svn_string_t bc_url, bc_relative;

      err = svn_ra_neon__get_baseline_info(NULL, &bc_url, &bc_relative,
                                           NULL, ras,
                                           url, revision, pool);
      if (err)
        {
          if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
            {
              /* easy out: */
              svn_error_clear(err);
              *dirent = NULL;
              return SVN_NO_ERROR;
            }
          else
            return err;
        }

      final_url = svn_path_url_add_component(bc_url.data, bc_relative.data,
                                             pool);
    }

  /* Depth-zero PROPFIND is the One True DAV Way. */
  err = svn_ra_neon__get_props(&resources, ras, final_url,
                               SVN_RA_NEON__DEPTH_ZERO,
                               NULL, NULL /* all props */, pool);
  if (err)
    {
      if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
        {
          /* easy out: */
          svn_error_clear(err);
          *dirent = NULL;
          return SVN_NO_ERROR;
        }
      else
        return err;
    }

  /* Copying parsing code from svn_ra_neon__get_dir() here.  The hash
     of resources only contains one item, but there's no other way to
     get the item. */
  for (hi = apr_hash_first(pool, resources); hi; hi = apr_hash_next(hi))
    {
      void *val;
      svn_ra_neon__resource_t *resource;
      const svn_string_t *propval;
      apr_hash_index_t *h;
      svn_dirent_t *entry;

      apr_hash_this(hi, NULL, NULL, &val);
      resource = val;

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

      entry->kind = resource->is_collection ? svn_node_dir : svn_node_file;

      /* entry->size is already 0 by virtue of pcalloc(). */
      if (entry->kind == svn_node_file)
        {
          propval = apr_hash_get(resource->propset,
                                 SVN_RA_NEON__PROP_GETCONTENTLENGTH,
                                 APR_HASH_KEY_STRING);
          if (propval)
            entry->size = svn__atoui64(propval->data);
        }

      /* does this resource contain any 'dead' properties? */
      for (h = apr_hash_first(pool, resource->propset);
           h; h = apr_hash_next(h))
        {
          const void *kkey;
          apr_hash_this(h, &kkey, NULL, NULL);

          if (strncmp((const char *)kkey, SVN_DAV_PROP_NS_CUSTOM,
                      sizeof(SVN_DAV_PROP_NS_CUSTOM) - 1) == 0)
            entry->has_props = TRUE;

          else if (strncmp((const char *)kkey, SVN_DAV_PROP_NS_SVN,
                           sizeof(SVN_DAV_PROP_NS_SVN) - 1) == 0)
            entry->has_props = TRUE;
        }

      /* created_rev & friends */
      propval = apr_hash_get(resource->propset,
                             SVN_RA_NEON__PROP_VERSION_NAME,
                             APR_HASH_KEY_STRING);
      if (propval != NULL)
        entry->created_rev = SVN_STR_TO_REV(propval->data);

      propval = apr_hash_get(resource->propset,
                             SVN_RA_NEON__PROP_CREATIONDATE,
                             APR_HASH_KEY_STRING);
      if (propval != NULL)
        SVN_ERR(svn_time_from_cstring(&(entry->time),
                                      propval->data, pool));

      propval = apr_hash_get(resource->propset,
                             SVN_RA_NEON__PROP_CREATOR_DISPLAYNAME,
                             APR_HASH_KEY_STRING);
      if (propval != NULL)
        entry->last_author = propval->data;

      *dirent = entry;
    }

  return SVN_NO_ERROR;
}
/* Request a mergeinfo-report from the URL attached to SESSION,
   and fill in the CATALOG with the results.  */
svn_error_t *
svn_ra_neon__get_mergeinfo(svn_ra_session_t *session,
                           svn_mergeinfo_catalog_t *catalog,
                           const apr_array_header_t *paths,
                           svn_revnum_t revision,
                           svn_mergeinfo_inheritance_t inherit,
                           svn_boolean_t include_descendants,
                           apr_pool_t *pool)
{
  svn_ra_neon__session_t *ras = session->priv;
  svn_stringbuf_t *request_body = svn_stringbuf_create("", pool);
  struct mergeinfo_baton mb;
  const char *bc_url;
  const char *bc_relative;
  const char *final_bc_url;

  static const char minfo_report_head[] =
    "<S:" SVN_DAV__MERGEINFO_REPORT " xmlns:S=\"" SVN_XML_NAMESPACE "\">"
    DEBUG_CR;

  static const char minfo_report_tail[] =
    "</S:" SVN_DAV__MERGEINFO_REPORT ">" DEBUG_CR;

  *catalog = NULL;

  /* Construct the request body. */
  svn_stringbuf_appendcstr(request_body, minfo_report_head);
  svn_stringbuf_appendcstr(request_body,
                           apr_psprintf(pool,
                                        "<S:revision>%ld"
                                        "</S:revision>", revision));
  svn_stringbuf_appendcstr(request_body,
                           apr_psprintf(pool,
                                        "<S:inherit>%s"
                                        "</S:inherit>",
                                        svn_inheritance_to_word(inherit)));

  if (include_descendants)
    {
      /* Send it only if true; server will default to "no". */
      svn_stringbuf_appendcstr(request_body,
                               "<S:include-descendants>yes"
                               "</S:include-descendants>");
    }

  if (paths)
    {
      int i;

      for (i = 0; i < paths->nelts; i++)
        {
          const char *this_path =
            apr_xml_quote_string(pool,
                                 ((const char **)paths->elts)[i],
                                 0);
          svn_stringbuf_appendcstr(request_body, "<S:path>");
          svn_stringbuf_appendcstr(request_body, this_path);
          svn_stringbuf_appendcstr(request_body, "</S:path>");
        }
    }

  svn_stringbuf_appendcstr(request_body, minfo_report_tail);

  mb.pool = pool;
  mb.curr_path = svn_stringbuf_create("", pool);
  mb.curr_info = svn_stringbuf_create("", pool);
  mb.catalog = apr_hash_make(pool);
  mb.err = SVN_NO_ERROR;

  /* ras's URL may not exist in HEAD, and thus it's not safe to send
     it as the main argument to the REPORT request; it might cause
     dav_get_resource() to choke on the server.  So instead, we pass a
     baseline-collection URL, which we get from END. */
  SVN_ERR(svn_ra_neon__get_baseline_info(&bc_url, &bc_relative, NULL, ras,
                                         ras->url->data, revision, pool));
  final_bc_url = svn_path_url_add_component2(bc_url, bc_relative, pool);

  SVN_ERR(svn_ra_neon__parsed_request(ras,
                                      "REPORT",
                                      final_bc_url,
                                      request_body->data,
                                      NULL, NULL,
                                      start_element,
                                      cdata_handler,
                                      end_element,
                                      &mb,
                                      NULL,
                                      NULL,
                                      FALSE,
                                      pool));

  if (mb.err == SVN_NO_ERROR && apr_hash_count(mb.catalog))
    *catalog = mb.catalog;

  return mb.err;
}
Пример #5
0
svn_error_t *
svn_ra_neon__do_check_path(svn_ra_session_t *session,
                           const char *path,
                           svn_revnum_t revision,
                           svn_node_kind_t *kind,
                           apr_pool_t *pool)
{
  svn_ra_neon__session_t *ras = session->priv;
  const char *url = ras->url->data;
  svn_error_t *err;
  svn_boolean_t is_dir;

  /* ### For now, using svn_ra_neon__get_baseline_info() works because
     we only have three possibilities: dir, file, or none.  When we
     add symlinks, we will need to do something different.  Here's one
     way described by Greg Stein:

       That is a PROPFIND (Depth:0) for the DAV:resourcetype property.

       You can use the svn_ra_neon__get_one_prop() function to fetch
       it. If the PROPFIND fails with a 404, then you have
       svn_node_none. If the resulting property looks like:

           <D:resourcetype>
             <D:collection/>
           </D:resourcetype>

       Then it is a collection (directory; svn_node_dir). Otherwise,
       it is a regular resource (svn_node_file).

       The harder part is parsing the resourcetype property. "Proper"
       parsing means treating it as an XML property and looking for
       the DAV:collection element in there. To do that, however, means
       that get_one_prop() can't be used. I think there may be some
       Neon functions for parsing XML properties; we'd need to
       look. That would probably be the best approach. (an alternative
       is to use apr_xml_* parsing functions on the returned string;
       get back a DOM-like thing, and look for the element).
  */

  /* If we were given a relative path to append, append it. */
  if (path)
    url = svn_path_url_add_component(url, path, pool);

  err = svn_ra_neon__get_baseline_info(&is_dir, NULL, NULL, NULL,
                                       ras, url, revision, pool);

  if (err == SVN_NO_ERROR)
    {
      if (is_dir)
        *kind = svn_node_dir;
      else
        *kind = svn_node_file;
    }
  else if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
    {

      svn_error_clear(err);
      err = SVN_NO_ERROR;
      *kind = svn_node_none;
    }

  return err;
}