Index: serf.c
===================================================================
--- serf.c (revision 22857)
+++ serf.c (working copy)
@@ -251,15 +251,6 @@
}
static svn_error_t *
-svn_ra_serf__get_dated_revision(svn_ra_session_t *session,
- svn_revnum_t *revision,
- apr_time_t tm,
- apr_pool_t *pool)
-{
- abort();
-}
-
-static svn_error_t *
svn_ra_serf__rev_proplist(svn_ra_session_t *ra_session,
svn_revnum_t rev,
apr_hash_t **ret_props,
Index: locks.c
===================================================================
--- locks.c (revision 22857)
+++ locks.c (working copy)
@@ -52,6 +52,7 @@
DEPTH,
TIMEOUT,
LOCK_TOKEN,
+ COMMENT,
} lock_state_e;
typedef struct {
@@ -66,18 +67,14 @@
svn_lock_t *lock;
- const char *owner;
- const char *creation_date;
- const char *lock_token;
- const char *comment;
-
svn_boolean_t force;
svn_revnum_t revision;
svn_boolean_t read_headers;
- /* Our HTTP status code. */
+ /* Our HTTP status code and reason. */
int status_code;
+ const char *reason;
/* The currently collected value as we build it up */
const char *tmp;
@@ -86,6 +83,8 @@
/* are we done? */
svn_boolean_t done;
+ /* Any errors. */
+ svn_error_t *error;
} lock_info_t;
@@ -102,6 +101,7 @@
case DEPTH:
case TIMEOUT:
case LOCK_TOKEN:
+ case COMMENT:
parser->state->private = apr_pcalloc(parser->state->pool,
sizeof(lock_prop_info_t));
break;
@@ -162,6 +162,10 @@
{
push_state(parser, ctx, LOCK_TOKEN);
}
+ else if (strcmp(name.name, "owner") == 0)
+ {
+ push_state(parser, ctx, COMMENT);
+ }
}
else if (state == LOCK_TYPE)
{
@@ -261,7 +265,18 @@
/* We don't actually need the lock token. */
svn_ra_serf__xml_pop_state(parser);
}
+ else if (state == COMMENT &&
+ strcmp(name.name, "owner") == 0)
+ {
+ lock_prop_info_t *info = parser->state->private;
+ if (info->len)
+ {
+ ctx->lock->comment = apr_pstrndup(ctx->pool, info->data, info->len);
+ }
+ svn_ra_serf__xml_pop_state(parser);
+ }
+
return SVN_NO_ERROR;
}
@@ -285,6 +300,7 @@
case DEPTH:
case TIMEOUT:
case LOCK_TOKEN:
+ case COMMENT:
svn_ra_serf__expand_string(&info->data, &info->len,
data, len, parser->state->pool);
break;
@@ -344,17 +360,14 @@
rv = serf_bucket_response_status(response, &sl);
ctx->status_code = sl.code;
+ ctx->reason = sl.reason;
/* 423 == Locked */
if (sl.code == 423)
{
- svn_error_t *err;
-
- err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
- _("Lock request failed: %d %s"),
- sl.code, sl.reason);
- xml_ctx->error = err;
- return err->apr_err;
+ ctx->error = svn_ra_serf__handle_server_error(request, response,
+ pool);
+ return ctx->error->apr_err;
}
headers = serf_bucket_response_get_headers(response);
@@ -389,6 +402,9 @@
if (APR_STATUS_IS_EOF(status))
{
ctx->done = TRUE;
+ ctx->error = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+ _("Lock request failed: %d %s"),
+ ctx->status_code, ctx->reason);
}
}
else
@@ -437,13 +453,13 @@
svn_ra_serf__add_tag_buckets(buckets, "locktype", "", alloc);
- if (ctx->comment)
+ if (ctx->lock->comment)
{
svn_stringbuf_t *xml_esc = NULL;
svn_string_t val;
- val.data = ctx->comment;
- val.len = strlen(ctx->comment);
+ val.data = ctx->lock->comment;
+ val.len = strlen(ctx->lock->comment);
svn_xml_escape_cdata_string(&xml_esc, &val, pool);
svn_ra_serf__add_tag_buckets(buckets, "owner", xml_esc->data, alloc);
@@ -465,7 +481,6 @@
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, *tmp;
lock_info_t *lock_ctx;
const char *req_url;
svn_error_t *err;
@@ -551,7 +566,6 @@
lock_ctx->path = key;
lock_ctx->revision = *((svn_revnum_t*)val);
lock_ctx->lock = svn_lock_create(subpool);
- lock_ctx->comment = comment;
lock_ctx->lock->path = key;
lock_ctx->lock->comment = comment;
@@ -587,10 +601,12 @@
svn_ra_serf__request_create(handler);
error = svn_ra_serf__context_run_wait(&lock_ctx->done, session, subpool);
+ SVN_ERR(lock_ctx->error);
+ SVN_ERR(parser_ctx->error);
if (error)
{
- SVN_ERR(parser_ctx->error);
- return error;
+ return svn_error_create(SVN_ERR_RA_DAV_REQUEST_FAILED, error,
+ _("Lock request failed"));
}
SVN_ERR(lock_func(lock_baton, lock_ctx->path, TRUE, lock_ctx->lock, NULL,
@@ -641,7 +657,6 @@
svn_ra_serf__handler_t *handler;
svn_ra_serf__simple_request_context_t *ctx;
const char *req_url, *path, *token;
- lock_info_t *lock_ctx;
const void *key;
void *val;
struct unlock_context_t unlock_ctx;
Index: getdate.c
===================================================================
--- getdate.c (revision 0)
+++ getdate.c (revision 0)
@@ -0,0 +1,243 @@
+/*
+ * getdate.c : entry point for get_dated_revision for ra_serf
+ *
+ * ====================================================================
+ * Copyright (c) 2006 CollabNet. All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://subversion.tigris.org/license-1.html.
+ * If newer versions of this license are posted there, you may use a
+ * newer version instead, at your option.
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals. For exact contribution history, see the revision
+ * history and logs, available at http://subversion.tigris.org/.
+ * ====================================================================
+ */
+
+
+
+#include
+
+#include
+
+#include
+
+#include "svn_pools.h"
+#include "svn_ra.h"
+#include "svn_dav.h"
+#include "svn_xml.h"
+#include "../libsvn_ra/ra_loader.h"
+#include "svn_config.h"
+#include "svn_delta.h"
+#include "svn_version.h"
+#include "svn_path.h"
+#include "svn_time.h"
+#include "svn_private_config.h"
+
+#include "ra_serf.h"
+
+
+/*
+ * This enum represents the current state of our XML parsing for a REPORT.
+ */
+typedef enum {
+ NONE = 0,
+ VERSION_NAME,
+} date_state_e;
+
+typedef struct {
+ /* The currently collected value as we build it up */
+ const char *tmp;
+ apr_size_t tmp_len;
+} date_info_t;
+
+typedef struct {
+ apr_pool_t *pool;
+
+ /* The time asked about. */
+ apr_time_t time;
+
+ /* What was the youngest revision at that time? */
+ svn_revnum_t *revision;
+
+ /* are we done? */
+ svn_boolean_t done;
+
+} date_context_t;
+
+
+static date_info_t *
+push_state(svn_ra_serf__xml_parser_t *parser,
+ date_context_t *date_ctx,
+ date_state_e state)
+{
+ svn_ra_serf__xml_push_state(parser, state);
+
+ if (state == VERSION_NAME)
+ {
+ date_info_t *info;
+
+ info = apr_pcalloc(parser->state->pool, sizeof(*info));
+
+ parser->state->private = info;
+ }
+
+ return parser->state->private;
+}
+
+static svn_error_t *
+start_getdate(svn_ra_serf__xml_parser_t *parser,
+ void *userData,
+ svn_ra_serf__dav_props_t name,
+ const char **attrs)
+{
+ date_context_t *date_ctx = userData;
+ date_state_e state;
+
+ state = parser->state->current_state;
+
+ if (state == NONE &&
+ strcmp(name.name, "version-name") == 0)
+ {
+ push_state(parser, date_ctx, VERSION_NAME);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+end_getdate(svn_ra_serf__xml_parser_t *parser,
+ void *userData,
+ svn_ra_serf__dav_props_t name)
+{
+ date_context_t *date_ctx = userData;
+ date_state_e state;
+ date_info_t *info;
+
+ state = parser->state->current_state;
+ info = parser->state->private;
+
+ if (state == VERSION_NAME &&
+ strcmp(name.name, "version-name") == 0)
+ {
+ *date_ctx->revision = SVN_STR_TO_REV(info->tmp);
+ svn_ra_serf__xml_pop_state(parser);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+cdata_getdate(svn_ra_serf__xml_parser_t *parser,
+ void *userData,
+ const char *data,
+ apr_size_t len)
+{
+ date_context_t *date_ctx = userData;
+ date_state_e state;
+ date_info_t *info;
+
+ state = parser->state->current_state;
+ info = parser->state->private;
+
+ switch (state)
+ {
+ case VERSION_NAME:
+ svn_ra_serf__expand_string(&info->tmp, &info->tmp_len,
+ data, len, parser->state->pool);
+ break;
+ default:
+ break;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+#define GETDATE_HEADER ""
+#define GETDATE_FOOTER ""
+
+static serf_bucket_t*
+create_getdate_body(void *baton,
+ serf_bucket_alloc_t *alloc,
+ apr_pool_t *pool)
+{
+ serf_bucket_t *buckets, *tmp;
+ date_context_t *date_ctx = baton;
+
+ buckets = serf_bucket_aggregate_create(alloc);
+
+ tmp = SERF_BUCKET_SIMPLE_STRING_LEN(GETDATE_HEADER,
+ sizeof(GETDATE_HEADER) - 1,
+ alloc);
+ serf_bucket_aggregate_append(buckets, tmp);
+
+ svn_ra_serf__add_tag_buckets(buckets,
+ "D:creationdate",
+ svn_time_to_cstring(date_ctx->time, pool),
+ alloc);
+
+ tmp = SERF_BUCKET_SIMPLE_STRING_LEN(GETDATE_FOOTER,
+ sizeof(GETDATE_FOOTER)-1,
+ alloc);
+ serf_bucket_aggregate_append(buckets, tmp);
+
+ return buckets;
+}
+
+svn_error_t *
+svn_ra_serf__get_dated_revision(svn_ra_session_t *ra_session,
+ svn_revnum_t *revision,
+ apr_time_t tm,
+ apr_pool_t *pool)
+{
+ date_context_t *date_ctx;
+ svn_ra_serf__session_t *session = ra_session->priv;
+ svn_ra_serf__handler_t *handler;
+ svn_ra_serf__xml_parser_t *parser_ctx;
+ const char *vcc_url;
+ int status_code;
+
+ date_ctx = apr_pcalloc(pool, sizeof(*date_ctx));
+ date_ctx->pool = pool;
+ date_ctx->time = tm;
+ date_ctx->revision = revision;
+ date_ctx->done = FALSE;
+
+ SVN_ERR(svn_ra_serf__discover_root(&vcc_url, NULL,
+ session, session->conns[0],
+ session->repos_url.path, pool));
+
+ handler = apr_pcalloc(pool, sizeof(*handler));
+
+ handler->method = "REPORT";
+ handler->path = vcc_url;
+ 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 = date_ctx;
+ parser_ctx->start = start_getdate;
+ parser_ctx->end = end_getdate;
+ parser_ctx->cdata = cdata_getdate;
+ parser_ctx->done = &date_ctx->done;
+ parser_ctx->status_code = &status_code;
+
+ handler->body_delegate = create_getdate_body;
+ handler->body_delegate_baton = date_ctx;
+
+ handler->response_handler = svn_ra_serf__handle_xml_parser;
+ handler->response_baton = parser_ctx;
+
+ svn_ra_serf__request_create(handler);
+
+ *date_ctx->revision = SVN_INVALID_REVNUM;
+
+ SVN_ERR(svn_ra_serf__context_run_wait(&date_ctx->done, session, pool));
+
+ return SVN_NO_ERROR;
+}
Index: util.c
===================================================================
--- util.c (revision 22857)
+++ util.c (working copy)
@@ -41,8 +41,8 @@
serf_bucket_t *
svn_ra_serf__conn_setup(apr_socket_t *sock,
- void *baton,
- apr_pool_t *pool)
+ void *baton,
+ apr_pool_t *pool)
{
serf_bucket_t *bucket;
svn_ra_serf__connection_t *conn = baton;
@@ -63,9 +63,9 @@
serf_bucket_t*
svn_ra_serf__accept_response(serf_request_t *request,
- serf_bucket_t *stream,
- void *acceptor_baton,
- apr_pool_t *pool)
+ serf_bucket_t *stream,
+ void *acceptor_baton,
+ apr_pool_t *pool)
{
serf_bucket_t *c;
serf_bucket_alloc_t *bkt_alloc;
@@ -95,9 +95,9 @@
void
svn_ra_serf__conn_closed(serf_connection_t *conn,
- void *closed_baton,
- apr_status_t why,
- apr_pool_t *pool)
+ void *closed_baton,
+ apr_status_t why,
+ apr_pool_t *pool)
{
svn_ra_serf__connection_t *our_conn = closed_baton;
@@ -118,6 +118,15 @@
svn_ra_serf__session_t *serf_sess = data;
int i;
+ /* If we are cleaning up due to an error, don't call connection_close
+ * as we're already on our way out of here and we'll defer to serf's
+ * cleanups.
+ */
+ if (serf_sess->pending_error)
+ {
+ return APR_SUCCESS;
+ }
+
for (i = 0; i < serf_sess->num_conns; i++)
{
if (serf_sess->conns[i])
@@ -309,9 +318,9 @@
apr_status_t
svn_ra_serf__handle_discard_body(serf_request_t *request,
- serf_bucket_t *response,
- void *baton,
- apr_pool_t *pool)
+ serf_bucket_t *response,
+ void *baton,
+ apr_pool_t *pool)
{
apr_status_t status;
svn_ra_serf__server_error_t *server_err = baton;
@@ -654,7 +663,26 @@
xml_status = XML_Parse(ctx->xmlp, data, len, 0);
if (xml_status == XML_STATUS_ERROR && ctx->ignore_errors == FALSE)
{
- abort();
+ XML_ParserFree(ctx->xmlp);
+
+ if (!ctx->status_code)
+ {
+ abort();
+ }
+ if (*ctx->done == FALSE)
+ {
+ *ctx->done = TRUE;
+ if (ctx->done_list)
+ {
+ ctx->done_item->data = ctx->user_data;
+ ctx->done_item->next = *ctx->done_list;
+ *ctx->done_list = ctx->done_item;
+ }
+ }
+ ctx->error = svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ "XML parsing failed: (%d %s)",
+ sl.code, sl.reason);
+ return ctx->error->apr_err;
}
if (ctx->error && ctx->ignore_errors == FALSE)
@@ -697,8 +725,38 @@
/* not reached */
}
+svn_error_t *
+svn_ra_serf__handle_server_error(serf_request_t *request,
+ serf_bucket_t *response,
+ apr_pool_t *pool)
+{
+ svn_ra_serf__server_error_t server_err;
+ apr_status_t status;
+
+ memset(&server_err, 0, sizeof(server_err));
+ status = svn_ra_serf__handle_discard_body(request, response,
+ &server_err, pool);
+
+ if (APR_STATUS_IS_EOF(status))
+ {
+ status = svn_ra_serf__is_conn_closing(response);
+ if (status == SERF_ERROR_CLOSING)
+ {
+ serf_connection_reset(serf_request_get_conn(request));
+ }
+ }
+
+ SVN_ERR(server_err.error);
+
+ return svn_error_create(APR_EGENERAL, NULL, _("Unspecified error message"));
+}
+
+/* Implements the serf_response_handler_t interface. Wait for HTTP
+ response status and headers, and invoke CTX->response_handler() to
+ carry out operation-specific processing. Afterwards, check for
+ connection close. */
static apr_status_t
-handler_default(serf_request_t *request,
+handle_response(serf_request_t *request,
serf_bucket_t *response,
void *baton,
apr_pool_t *pool)
@@ -707,9 +765,9 @@
serf_status_line sl;
apr_status_t status;
- /* Uh-oh. Our connection died. Requeue. */
if (!response)
{
+ /* Uh-oh. Our connection died. Requeue. */
if (ctx->response_error)
{
status = ctx->response_error(request, response, 0,
@@ -725,6 +783,12 @@
return APR_SUCCESS;
}
+ status = serf_bucket_response_status(response, &sl);
+ if (SERF_BUCKET_READ_ERROR(status))
+ {
+ return status;
+ }
+
status = serf_bucket_response_wait_for_headers(response);
if (status)
{
@@ -732,11 +796,16 @@
{
return status;
}
- /* If we got an EOF here when we're not a HEAD request,
- * something went really wrong: either the server closed on us
- * early or we're reading too much. Either way, scream loudly.
+
+ /* Cases where a lack of a response body (via EOF) is okay:
+ * - A HEAD request
+ * - 204/304 response
+ *
+ * Otherwise, if we get an EOF here, something went really wrong: either
+ * the server closed on us early or we're reading too much. Either way,
+ * scream loudly.
*/
- if (strcmp(ctx->method, "HEAD") != 0)
+ if (strcmp(ctx->method, "HEAD") != 0 && sl.code != 204 && sl.code != 304)
{
ctx->session->pending_error =
svn_error_create(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
@@ -745,12 +814,6 @@
}
}
- status = serf_bucket_response_status(response, &sl);
- if (status)
- {
- return status;
- }
-
if (ctx->conn->last_status_code == 401 && sl.code < 400)
{
svn_auth_save_credentials(ctx->session->auth_state, ctx->session->pool);
@@ -768,31 +831,9 @@
}
else if (sl.code >= 500)
{
- svn_ra_serf__server_error_t server_err;
- apr_status_t status;
-
- memset(&server_err, 0, sizeof(server_err));
- status = svn_ra_serf__handle_discard_body(request, response,
- &server_err, pool);
-
- if (APR_STATUS_IS_EOF(status))
- {
- status = svn_ra_serf__is_conn_closing(response);
- if (status == SERF_ERROR_CLOSING)
- {
- serf_connection_reset(ctx->conn->conn);
- }
- }
-
- if (server_err.error)
- {
- ctx->session->pending_error = server_err.error;
- return server_err.error->apr_err;
- }
- else
- {
- return APR_EGENERAL;
- }
+ ctx->session->pending_error =
+ svn_ra_serf__handle_server_error(request, response, pool);
+ return ctx->session->pending_error->apr_err;
}
else
{
@@ -800,16 +841,23 @@
pool);
}
- if (APR_STATUS_IS_EOF(status)) {
+ if (APR_STATUS_IS_EOF(status))
+ {
status = svn_ra_serf__is_conn_closing(response);
- }
+ }
return status;
-
}
+/* Implements the serf_request_setup_t interface (which sets up both a
+ request and its response handler callback). If the CTX->delegate()
+ callback is non-NULL, invoke it to carry out the majority of the
+ serf_request_setup_t implementation. Otherwise, perform default
+ setup, with special handling for HEAD requests, and finer-grained
+ callbacks invoked (if non-NULL) to produce the request headers and
+ body. */
static apr_status_t
-setup_default(serf_request_t *request,
+setup_request(serf_request_t *request,
void *setup_baton,
serf_bucket_t **req_bkt,
serf_response_acceptor_t *acceptor,
@@ -864,17 +912,17 @@
}
}
- *handler = handler_default;
+ *handler = handle_response;
*handler_baton = ctx;
return APR_SUCCESS;
}
-serf_request_t*
+serf_request_t *
svn_ra_serf__request_create(svn_ra_serf__handler_t *handler)
{
return serf_connection_request_create(handler->conn->conn,
- setup_default, handler);
+ setup_request, handler);
}
svn_error_t *
Index: log.c
===================================================================
--- log.c (revision 22857)
+++ log.c (working copy)
@@ -49,6 +49,10 @@
CREATOR,
DATE,
COMMENT,
+ ADDED_PATH,
+ REPLACED_PATH,
+ DELETED_PATH,
+ MODIFIED_PATH,
} log_state_e;
typedef struct {
@@ -58,9 +62,11 @@
const char *tmp;
apr_size_t tmp_len;
+ /* Temporary change path - ultimately inserted into changed_paths hash. */
+ svn_log_changed_path_t *tmp_path;
+
/* Hashtable of paths */
- /* TODO implement changed-paths support */
- apr_hash_t *paths;
+ apr_hash_t *changed_paths;
/* Other log fields */
svn_revnum_t version;
@@ -105,6 +111,20 @@
parser->state->private = info;
}
+ if (state == ADDED_PATH || state == REPLACED_PATH ||
+ state == DELETED_PATH || state == MODIFIED_PATH)
+ {
+ log_info_t *info = parser->state->private;
+
+ if (!info->changed_paths)
+ {
+ info->changed_paths = apr_hash_make(info->pool);
+ }
+
+ info->tmp_path = apr_pcalloc(info->pool, sizeof(*info->tmp_path));
+ info->tmp_path->copyfrom_rev = SVN_INVALID_REVNUM;
+ }
+
return parser->state->private;
}
@@ -137,6 +157,8 @@
}
else if (state == ITEM)
{
+ log_info_t *info;
+
if (strcmp(name.name, "version-name") == 0)
{
push_state(parser, log_ctx, VERSION);
@@ -153,6 +175,60 @@
{
push_state(parser, log_ctx, COMMENT);
}
+ else if (strcmp(name.name, "added-path") == 0)
+ {
+ const char *copy_path, *copy_rev_str;
+
+ info = push_state(parser, log_ctx, ADDED_PATH);
+ info->tmp_path->action = 'A';
+
+ copy_path = svn_ra_serf__find_attr(attrs, "copyfrom-path");
+ copy_rev_str = svn_ra_serf__find_attr(attrs, "copyfrom-rev");
+ if (copy_path && copy_rev_str)
+ {
+ svn_revnum_t copy_rev;
+
+ copy_rev = SVN_STR_TO_REV(copy_rev_str);
+ if (SVN_IS_VALID_REVNUM(copy_rev))
+ {
+ info->tmp_path->copyfrom_path = apr_pstrdup(info->pool,
+ copy_path);
+ info->tmp_path->copyfrom_rev = copy_rev;
+ }
+ }
+ }
+ else if (strcmp(name.name, "replaced-path") == 0)
+ {
+ const char *copy_path, *copy_rev_str;
+
+ info = push_state(parser, log_ctx, REPLACED_PATH);
+ info->tmp_path->action = 'R';
+
+ copy_path = svn_ra_serf__find_attr(attrs, "copyfrom-path");
+ copy_rev_str = svn_ra_serf__find_attr(attrs, "copyfrom-rev");
+ if (copy_path && copy_rev_str)
+ {
+ svn_revnum_t copy_rev;
+
+ copy_rev = SVN_STR_TO_REV(copy_rev_str);
+ if (SVN_IS_VALID_REVNUM(copy_rev))
+ {
+ info->tmp_path->copyfrom_path = apr_pstrdup(info->pool,
+ copy_path);
+ info->tmp_path->copyfrom_rev = copy_rev;
+ }
+ }
+ }
+ else if (strcmp(name.name, "deleted-path") == 0)
+ {
+ info = push_state(parser, log_ctx, DELETED_PATH);
+ info->tmp_path->action = 'D';
+ }
+ else if (strcmp(name.name, "modified-path") == 0)
+ {
+ info = push_state(parser, log_ctx, MODIFIED_PATH);
+ info->tmp_path->action = 'M';
+ }
}
return SVN_NO_ERROR;
@@ -180,7 +256,7 @@
{
/* Give the info to the reporter */
SVN_ERR(log_ctx->receiver(log_ctx->receiver_baton,
- info->paths,
+ info->changed_paths,
info->version,
info->creator,
info->date,
@@ -217,7 +293,25 @@
info->tmp_len = 0;
svn_ra_serf__xml_pop_state(parser);
}
+ else if ((state == ADDED_PATH &&
+ strcmp(name.name, "added-path") == 0) ||
+ (state == DELETED_PATH &&
+ strcmp(name.name, "deleted-path") == 0) ||
+ (state == MODIFIED_PATH &&
+ strcmp(name.name, "modified-path") == 0) ||
+ (state == REPLACED_PATH &&
+ strcmp(name.name, "replaced-path") == 0))
+ {
+ char *path;
+ path = apr_pstrmemdup(info->pool, info->tmp, info->tmp_len);
+ info->tmp_len = 0;
+
+ apr_hash_set(info->changed_paths, path, APR_HASH_KEY_STRING,
+ info->tmp_path);
+ svn_ra_serf__xml_pop_state(parser);
+ }
+
return SVN_NO_ERROR;
}
@@ -240,6 +334,10 @@
case CREATOR:
case DATE:
case COMMENT:
+ case ADDED_PATH:
+ case REPLACED_PATH:
+ case DELETED_PATH:
+ case MODIFIED_PATH:
svn_ra_serf__expand_string(&info->tmp, &info->tmp_len,
data, len, parser->state->pool);
break;
Index: update.c
===================================================================
--- update.c (revision 22857)
+++ update.c (working copy)
@@ -384,7 +384,7 @@
apr_pool_create(&new_info->pool, info_parent_pool);
new_info->file_baton = NULL;
new_info->lock_token = NULL;
- new_info->fetch_file = FALSE;
+ new_info->fetch_file = FALSE;
/* Point at our parent's directory state. */
new_info->dir = info->dir;
@@ -932,6 +932,9 @@
if (sl.code == 404)
{
fetch_ctx->done = TRUE;
+ fetch_ctx->err = svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, NULL,
+ "'%s' path not found",
+ fetch_ctx->info->name);
return svn_ra_serf__handle_discard_body(request, response, NULL, pool);
}
@@ -1072,7 +1075,6 @@
static void fetch_file(report_context_t *ctx, report_info_t *info)
{
- const char *checked_in_url;
svn_ra_serf__connection_t *conn;
svn_ra_serf__handler_t *handler;
@@ -1388,6 +1390,8 @@
abort();
}
+ info = parser->state->private;
+
SVN_ERR(open_dir(info->dir));
ctx->update_editor->absent_directory(file_name,
@@ -2203,16 +2207,18 @@
(!cur_dir->fetch_props ||
svn_ra_serf__propfind_is_done(cur_dir->propfind)))
{
+ report_dir_t *parent = cur_dir->parent_dir;
+
SVN_ERR(close_dir(cur_dir));
- if (cur_dir->parent_dir)
+ if (parent)
{
- cur_dir->parent_dir->ref_count--;
+ parent->ref_count--;
}
else
{
closed_root = TRUE;
}
- cur_dir = cur_dir->parent_dir;
+ cur_dir = parent;
}
}
report->done_fetches = NULL;
@@ -2529,6 +2535,8 @@
stream_ctx->target_stream = stream;
stream_ctx->sess = session;
stream_ctx->conn = conn;
+ stream_ctx->info = apr_pcalloc(pool, sizeof(*stream_ctx->info));
+ stream_ctx->info->name = fetch_url;
handler = apr_pcalloc(pool, sizeof(*handler));
handler->method = "GET";
@@ -2545,6 +2553,7 @@
svn_ra_serf__request_create(handler);
SVN_ERR(svn_ra_serf__context_run_wait(&stream_ctx->done, session, pool));
+ SVN_ERR(stream_ctx->err);
}
return SVN_NO_ERROR;
Index: property.c
===================================================================
--- property.c (revision 22857)
+++ property.c (working copy)
@@ -96,6 +96,9 @@
/* Are we done issuing the PROPFIND? */
svn_boolean_t done;
+ /* Context from XML stream */
+ svn_ra_serf__xml_parser_t *parser_ctx;
+
/* If not-NULL, add us to this list when we're done. */
svn_ra_serf__list_t **done_list;
@@ -413,7 +416,7 @@
apr_pool_t *pool)
{
svn_ra_serf__propfind_context_t *ctx = setup_baton;
- svn_ra_serf__xml_parser_t *parser_ctx;
+ svn_ra_serf__xml_parser_t *parser_ctx = ctx->parser_ctx;
*req_bkt =
svn_ra_serf__bucket_propfind_create(ctx->conn, ctx->path, ctx->label,
@@ -433,8 +436,6 @@
}
}
- parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
-
parser_ctx->pool = pool;
parser_ctx->user_data = ctx;
parser_ctx->start = start_propfind;
@@ -560,6 +561,9 @@
new_prop_ctx->handler = handler;
+ new_prop_ctx->parser_ctx = apr_pcalloc(pool,
+ sizeof(*new_prop_ctx->parser_ctx));
+
*prop_ctx = new_prop_ctx;
}
@@ -590,7 +594,11 @@
svn_ra_serf__session_t *sess,
apr_pool_t *pool)
{
- return svn_ra_serf__context_run_wait(&prop_ctx->done, sess, pool);
+ svn_error_t *err;
+
+ err = svn_ra_serf__context_run_wait(&prop_ctx->done, sess, pool);
+ SVN_ERR(prop_ctx->parser_ctx->error);
+ return err;
}
/*
Index: ra_serf.h
===================================================================
--- ra_serf.h (revision 22857)
+++ ra_serf.h (working copy)
@@ -267,7 +267,7 @@
serf_bucket_alloc_t *alloc,
apr_pool_t *pool);
-/* Callback for when a request headers are needed. */
+/* Callback for when request headers are needed. */
typedef apr_status_t
(*svn_ra_serf__request_header_delegate_t)(serf_bucket_t *headers,
void *baton,
@@ -545,6 +545,17 @@
apr_pool_t *pool);
/*
+ * Handler that retrieves the embedded XML error response from the
+ * the @a response body associated with a @a request.
+ *
+ * All temporary allocations will be made in a @a pool.
+ */
+svn_error_t *
+svn_ra_serf__handle_server_error(serf_request_t *request,
+ serf_bucket_t *response,
+ apr_pool_t *pool);
+
+/*
* This function will feed the RESPONSE body into XMLP. When parsing is
* completed (i.e. an EOF is received), *DONE is set to TRUE.
*
@@ -942,6 +953,12 @@
apr_pool_t *pool);
svn_error_t *
+svn_ra_serf__get_dated_revision(svn_ra_session_t *session,
+ svn_revnum_t *revision,
+ apr_time_t tm,
+ apr_pool_t *pool);
+
+svn_error_t *
svn_ra_serf__get_commit_editor(svn_ra_session_t *session,
const svn_delta_editor_t **editor,
void **edit_baton,
Index: commit.c
===================================================================
--- commit.c (revision 22857)
+++ commit.c (working copy)
@@ -293,8 +293,6 @@
if (dir->parent_dir)
{
- SVN_ERR(checkout_dir(dir->parent_dir));
-
/* Is our parent a copy? If so, we're already implicitly checked out. */
if (apr_hash_get(dir->commit->copied_entries,
dir->parent_dir->name, APR_HASH_KEY_STRING))
@@ -366,7 +364,7 @@
return_response_err(handler,
&checkout_ctx->progress),
_("Path '%s' not present"),
- svn_path_local_style(dir->name, dir->pool));
+ dir->name);
}
return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND,
@@ -427,7 +425,7 @@
return_response_err(handler,
&file->checkout->progress),
_("Path '%s' not present"),
- svn_path_local_style(file->name, file->pool));
+ file->name);
}
return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND,
@@ -733,9 +731,13 @@
/* We need to flush the file, make it unbuffered (so that it can be
* zero-copied via mmap), and reset the position before attempting to
* deliver the file.
+ *
+ * N.B. If we have APR 1.3+, we can unbuffer the file to let us use mmap
+ * and zero-copy the PUT body. However, on older APR versions, we can't
+ * check the buffer status; but serf will fall through and create a file
+ * bucket for us on the buffered svndiff handle.
*/
apr_file_flush(ctx->svndiff);
- apr_file_buffer_set(ctx->svndiff, NULL, 0);
offset = 0;
apr_file_seek(ctx->svndiff, APR_SET, &offset);
@@ -846,7 +848,6 @@
apr_pool_t *pool)
{
delete_context_t *ctx = baton;
- const char *lock_tokens;
serf_bucket_headers_set(headers, SVN_DAV_VERSION_NAME_HEADER,
apr_ltoa(pool, ctx->revision));
@@ -1043,7 +1044,6 @@
dir_context_t *dir = parent_baton;
delete_context_t *delete_ctx;
svn_ra_serf__handler_t *handler;
- const char *lock_token;
svn_error_t *err;
/* Ensure our directory has been checked out */
@@ -1096,7 +1096,7 @@
SVN_ERR(svn_ra_serf__context_run_wait(&delete_ctx->progress.done,
dir->commit->session, pool));
}
- else
+ else if (err)
{
return err;
}
@@ -1207,7 +1207,11 @@
if (add_dir_ctx->status != 201)
{
- abort();
+ SVN_ERR(add_dir_ctx->server_error.error);
+ return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+ _("Add directory failed: %s on %s (%d)"),
+ handler->method, handler->path,
+ add_dir_ctx->status);
}
*child_baton = dir;
@@ -1755,7 +1759,7 @@
svn_delta_editor_t *editor;
commit_context_t *ctx;
- ctx = apr_pcalloc(pool, sizeof(commit_context_t));
+ ctx = apr_pcalloc(pool, sizeof(*ctx));
ctx->pool = pool;
Index: replay.c
===================================================================
--- replay.c (revision 22857)
+++ replay.c (working copy)
@@ -135,9 +135,9 @@
static svn_error_t *
start_replay(svn_ra_serf__xml_parser_t *parser,
- void *userData,
- svn_ra_serf__dav_props_t name,
- const char **attrs)
+ void *userData,
+ svn_ra_serf__dav_props_t name,
+ const char **attrs)
{
replay_context_t *ctx = userData;
replay_state_e state;
@@ -336,6 +336,10 @@
info = push_state(parser, ctx, APPLY_TEXTDELTA);
checksum = svn_ra_serf__find_attr(attrs, "checksum");
+ if (checksum)
+ {
+ checksum = apr_pstrdup(info->pool, checksum);
+ }
SVN_ERR(ctx->editor->apply_textdelta(info->baton, checksum,
info->pool,
@@ -350,9 +354,13 @@
strcmp(name.name, "close-file") == 0)
{
replay_info_t *info = parser->state->private;
+ const char *checksum;
- SVN_ERR(ctx->editor->close_file(info->baton, NULL, parser->state->pool));
+ checksum = svn_ra_serf__find_attr(attrs, "checksum");
+ SVN_ERR(ctx->editor->close_file(info->baton, checksum,
+ parser->state->pool));
+
svn_ra_serf__xml_pop_state(parser);
}
else if (((state == OPEN_FILE || state == ADD_FILE) &&
@@ -362,7 +370,6 @@
{
const char *prop_name;
prop_info_t *info;
- svn_boolean_t del_prop;
prop_name = svn_ra_serf__find_attr(attrs, "name");
if (!prop_name)
@@ -393,8 +400,8 @@
static svn_error_t *
end_replay(svn_ra_serf__xml_parser_t *parser,
- void *userData,
- svn_ra_serf__dav_props_t name)
+ void *userData,
+ svn_ra_serf__dav_props_t name)
{
replay_context_t *ctx = userData;
replay_state_e state;
@@ -468,9 +475,9 @@
static svn_error_t *
cdata_replay(svn_ra_serf__xml_parser_t *parser,
- void *userData,
- const char *data,
- apr_size_t len)
+ void *userData,
+ const char *data,
+ apr_size_t len)
{
replay_context_t *replay_ctx = userData;
replay_state_e state;
@@ -515,8 +522,6 @@
svn_ra_serf__handler_t *handler;
svn_ra_serf__xml_parser_t *parser_ctx;
serf_bucket_t *buckets, *tmp;
- apr_hash_t *props;
- svn_revnum_t peg_rev;
replay_ctx = apr_pcalloc(pool, sizeof(*replay_ctx));
replay_ctx->pool = pool;
@@ -559,8 +564,6 @@
session->bkt_alloc);
serf_bucket_aggregate_append(buckets, tmp);
- props = apr_hash_make(pool);
-
handler = apr_pcalloc(pool, sizeof(*handler));
handler->method = "REPORT";