static svn_error_t * multistatus_opened(svn_ra_serf__xml_estate_t *xes, void *baton, int entered_state, const svn_ra_serf__dav_props_t *tag, apr_pool_t *scratch_pool) { /*struct svn_ra_serf__server_error_t *server_error = baton;*/ const char *propname; switch (entered_state) { case MS_PROPSTAT_PROP_NAME: if (strcmp(tag->xmlns, SVN_DAV_PROP_NS_SVN) == 0) propname = apr_pstrcat(scratch_pool, SVN_PROP_PREFIX, tag->name, SVN_VA_NULL); else propname = tag->name; svn_ra_serf__xml_note(xes, MS_PROPSTAT, "propname", propname); break; case S_ERROR: /* This toggles an has error boolean in libsvn_ra_neon in 1.7 */ break; } return SVN_NO_ERROR; }
/* Conforms to svn_ra_serf__xml_opened_t */ static svn_error_t * propfind_opened(svn_ra_serf__xml_estate_t *xes, void *baton, int entered_state, const svn_ra_serf__dav_props_t *tag, apr_pool_t *scratch_pool) { propfind_context_t *ctx = baton; if (entered_state == PROPVAL) { svn_ra_serf__xml_note(xes, PROPVAL, "ns", tag->xmlns); svn_ra_serf__xml_note(xes, PROPVAL, "name", tag->name); } else if (entered_state == PROPSTAT) { ctx->ps_props = apr_hash_make(svn_ra_serf__xml_state_pool(xes)); } return SVN_NO_ERROR; }
/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * mergeinfo_closed(svn_ra_serf__xml_estate_t *xes, void *baton, int leaving_state, const svn_string_t *cdata, apr_hash_t *attrs, apr_pool_t *scratch_pool) { mergeinfo_context_t *mergeinfo_ctx = baton; if (leaving_state == MERGEINFO_ITEM) { /* Placed here from the child elements. */ const char *path = apr_hash_get(attrs, "path", APR_HASH_KEY_STRING); const char *info = apr_hash_get(attrs, "info", APR_HASH_KEY_STRING); if (path != NULL && info != NULL) { svn_mergeinfo_t path_mergeinfo; /* Correct for naughty servers that send "relative" paths with leading slashes! */ if (path[0] == '/') ++path; SVN_ERR(svn_mergeinfo_parse(&path_mergeinfo, info, mergeinfo_ctx->pool)); apr_hash_set(mergeinfo_ctx->result_catalog, apr_pstrdup(mergeinfo_ctx->pool, path), APR_HASH_KEY_STRING, path_mergeinfo); } } else { SVN_ERR_ASSERT(leaving_state == MERGEINFO_PATH || leaving_state == MERGEINFO_INFO); /* Stash the value onto the parent MERGEINFO_ITEM. */ svn_ra_serf__xml_note(xes, MERGEINFO_ITEM, leaving_state == MERGEINFO_PATH ? "path" : "info", cdata->data); } return SVN_NO_ERROR; }
/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * propfind_closed(svn_ra_serf__xml_estate_t *xes, void *baton, int leaving_state, const svn_string_t *cdata, apr_hash_t *attrs, apr_pool_t *scratch_pool) { propfind_context_t *ctx = baton; if (leaving_state == MULTISTATUS) { /* We've gathered all the data from the reponse. Add this item onto the "done list". External callers will then know this request has been completed (tho stray response bytes may still arrive). */ } else if (leaving_state == HREF) { const char *path; if (strcmp(ctx->depth, "1") == 0) path = svn_urlpath__canonicalize(cdata->data, scratch_pool); else path = ctx->path; svn_ra_serf__xml_note(xes, RESPONSE, "path", path); SVN_ERR(ctx->prop_func(ctx->prop_func_baton, path, D_, "href", cdata, scratch_pool)); } else if (leaving_state == COLLECTION) { svn_ra_serf__xml_note(xes, PROPVAL, "altvalue", "collection"); } else if (leaving_state == HREF_VALUE) { svn_ra_serf__xml_note(xes, PROPVAL, "altvalue", cdata->data); } else if (leaving_state == STATUS) { /* Parse the status field, and remember if this is a property that we wish to ignore. (Typically, if it's not a 200, the status will be 404 to indicate that a property we specifically requested from the server doesn't exist.) */ apr_int64_t status = parse_status_code(cdata->data); if (status != 200) svn_ra_serf__xml_note(xes, PROPSTAT, "ignore-prop", "*"); } else if (leaving_state == PROPVAL) { const char *encoding; const svn_string_t *val_str; const char *ns; const char *name; const char *altvalue; if ((altvalue = svn_hash_gets(attrs, "altvalue")) != NULL) { val_str = svn_string_create(altvalue, scratch_pool); } else if ((encoding = svn_hash_gets(attrs, "V:encoding")) != NULL) { if (strcmp(encoding, "base64") != 0) return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL, _("Got unrecognized encoding '%s'"), encoding); /* Decode into the right pool. */ val_str = svn_base64_decode_string(cdata, scratch_pool); } else { /* Copy into the right pool. */ val_str = cdata; } /* The current path sits on the RESPONSE state. Now, it would be nice if we could, at this point, know that the status code for this property indicated a problem -- then we could simply bail out here and ignore the property. Sadly, though, we might get the status code *after* we get the property value. So we'll carry on with our processing here, setting the property and value as expected. Once we know for sure the status code associate with the property, we'll decide its fate. */ ns = svn_hash_gets(attrs, "ns"); name = svn_hash_gets(attrs, "name"); set_ns_prop(ctx->ps_props, ns, name, val_str, apr_hash_pool_get(ctx->ps_props)); } else { apr_hash_t *gathered; SVN_ERR_ASSERT(leaving_state == PROPSTAT); gathered = svn_ra_serf__xml_gather_since(xes, RESPONSE); /* If we've squirreled away a note that says we want to ignore these properties, we'll do so. Otherwise, we need to copy them from the temporary hash into the ctx->ret_props hash. */ if (! svn_hash_gets(gathered, "ignore-prop")) { apr_hash_index_t *hi_ns; const char *path; apr_pool_t *iterpool = svn_pool_create(scratch_pool); path = svn_hash_gets(gathered, "path"); if (!path) path = ctx->path; for (hi_ns = apr_hash_first(scratch_pool, ctx->ps_props); hi_ns; hi_ns = apr_hash_next(hi_ns)) { const char *ns = apr_hash_this_key(hi_ns); apr_hash_t *props = apr_hash_this_val(hi_ns); apr_hash_index_t *hi_prop; svn_pool_clear(iterpool); for (hi_prop = apr_hash_first(iterpool, props); hi_prop; hi_prop = apr_hash_next(hi_prop)) { const char *name = apr_hash_this_key(hi_prop); const svn_string_t *value = apr_hash_this_val(hi_prop); SVN_ERR(ctx->prop_func(ctx->prop_func_baton, path, ns, name, value, iterpool)); } } svn_pool_destroy(iterpool); } ctx->ps_props = NULL; /* Allocated in PROPSTAT state pool */ } return SVN_NO_ERROR; }
static svn_error_t * multistatus_closed(svn_ra_serf__xml_estate_t *xes, void *baton, int leaving_state, const svn_string_t *cdata, apr_hash_t *attrs, apr_pool_t *scratch_pool) { struct svn_ra_serf__server_error_t *server_error = baton; const char *errcode; const char *status; switch (leaving_state) { case MS_RESPONSE_HREF: { apr_status_t result; apr_uri_t uri; result = apr_uri_parse(scratch_pool, cdata->data, &uri); if (result) return svn_ra_serf__wrap_err(result, NULL); svn_ra_serf__xml_note(xes, MS_RESPONSE, "path", svn_urlpath__canonicalize(uri.path, scratch_pool)); } break; case MS_RESPONSE_STATUS: svn_ra_serf__xml_note(xes, MS_RESPONSE, "status", cdata->data); break; case MS_RESPONSE_ERROR_HUMANREADABLE: svn_ra_serf__xml_note(xes, MS_RESPONSE, "human-readable", cdata->data); errcode = svn_hash_gets(attrs, "errcode"); if (errcode) svn_ra_serf__xml_note(xes, MS_RESPONSE, "errcode", errcode); break; case MS_RESPONSE: if ((status = svn_hash__get_cstring(attrs, "status", NULL)) != NULL) { error_item_t *item; item = apr_pcalloc(server_error->pool, sizeof(*item)); item->path = apr_pstrdup(server_error->pool, svn_hash_gets(attrs, "path")); SVN_ERR(parse_status_line(&item->http_status, &item->http_reason, status, server_error->pool, scratch_pool)); /* Do we have a mod_dav specific message? */ item->message = svn_hash_gets(attrs, "human-readable"); if (item->message) { if ((errcode = svn_hash_gets(attrs, "errcode")) != NULL) { apr_int64_t val; SVN_ERR(svn_cstring_atoi64(&val, errcode)); item->apr_err = (apr_status_t)val; } item->message = apr_pstrdup(server_error->pool, item->message); } else item->message = apr_pstrdup(server_error->pool, svn_hash_gets(attrs, "description")); APR_ARRAY_PUSH(server_error->items, error_item_t *) = item; } break; case MS_PROPSTAT_STATUS: svn_ra_serf__xml_note(xes, MS_PROPSTAT, "status", cdata->data); break; case MS_PROPSTAT_ERROR_HUMANREADABLE: svn_ra_serf__xml_note(xes, MS_PROPSTAT, "human-readable", cdata->data); errcode = svn_hash_gets(attrs, "errcode"); if (errcode) svn_ra_serf__xml_note(xes, MS_PROPSTAT, "errcode", errcode); break; case MS_PROPSTAT_RESPONSEDESCRIPTION: svn_ra_serf__xml_note(xes, MS_PROPSTAT, "description", cdata->data); break; case MS_PROPSTAT: if ((status = svn_hash__get_cstring(attrs, "status", NULL)) != NULL) { apr_hash_t *response_attrs; error_item_t *item; response_attrs = svn_ra_serf__xml_gather_since(xes, MS_RESPONSE); item = apr_pcalloc(server_error->pool, sizeof(*item)); item->path = apr_pstrdup(server_error->pool, svn_hash_gets(response_attrs, "path")); item->propname = apr_pstrdup(server_error->pool, svn_hash_gets(attrs, "propname")); SVN_ERR(parse_status_line(&item->http_status, &item->http_reason, status, server_error->pool, scratch_pool)); /* Do we have a mod_dav specific message? */ item->message = svn_hash_gets(attrs, "human-readable"); if (item->message) { if ((errcode = svn_hash_gets(attrs, "errcode")) != NULL) { apr_int64_t val; SVN_ERR(svn_cstring_atoi64(&val, errcode)); item->apr_err = (apr_status_t)val; } item->message = apr_pstrdup(server_error->pool, item->message); } else item->message = apr_pstrdup(server_error->pool, svn_hash_gets(attrs, "description")); APR_ARRAY_PUSH(server_error->items, error_item_t *) = item; }
/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * blame_closed(svn_ra_serf__xml_estate_t *xes, void *baton, int leaving_state, const svn_string_t *cdata, apr_hash_t *attrs, apr_pool_t *scratch_pool) { blame_context_t *blame_ctx = baton; if (leaving_state == FILE_REV) { /* Note that we test STREAM, but any pointer is currently invalid. It was closed when left the TXDELTA state. */ if (blame_ctx->stream == NULL) { const char *path; const char *rev; path = svn_hash_gets(attrs, "path"); rev = svn_hash_gets(attrs, "rev"); /* Send a "no content" notification. */ SVN_ERR(blame_ctx->file_rev(blame_ctx->file_rev_baton, path, SVN_STR_TO_REV(rev), blame_ctx->rev_props, FALSE /* result_of_merge */, NULL, NULL, /* txdelta / baton */ blame_ctx->prop_diffs, scratch_pool)); } } else if (leaving_state == MERGED_REVISION) { svn_ra_serf__xml_note(xes, FILE_REV, "merged-revision", "*"); } else if (leaving_state == TXDELTA) { SVN_ERR(svn_stream_close(blame_ctx->stream)); } else { const char *name; const svn_string_t *value; SVN_ERR_ASSERT(leaving_state == REV_PROP || leaving_state == SET_PROP || leaving_state == REMOVE_PROP); name = apr_pstrdup(blame_ctx->state_pool, svn_hash_gets(attrs, "name")); if (leaving_state == REMOVE_PROP) { value = NULL; } else { const char *encoding = svn_hash_gets(attrs, "encoding"); if (encoding && strcmp(encoding, "base64") == 0) value = svn_base64_decode_string(cdata, blame_ctx->state_pool); else value = svn_string_dup(cdata, blame_ctx->state_pool); } if (leaving_state == REV_PROP) { svn_hash_sets(blame_ctx->rev_props, name, value); } else { svn_prop_t *prop = apr_array_push(blame_ctx->prop_diffs); prop->name = name; prop->value = value; } } return SVN_NO_ERROR; }
/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * merge_closed(svn_ra_serf__xml_estate_t *xes, void *baton, int leaving_state, const svn_string_t *cdata, apr_hash_t *attrs, apr_pool_t *scratch_pool) { merge_context_t *merge_ctx = baton; if (leaving_state == RESPONSE) { const char *rtype; rtype = svn_hash_gets(attrs, "resourcetype"); /* rtype can only be "baseline" or "collection" (or NULL). We can keep this check simple. */ if (rtype && *rtype == 'b') { const char *rev_str; rev_str = svn_hash_gets(attrs, "revision"); if (rev_str) { apr_int64_t rev; SVN_ERR(svn_cstring_atoi64(&rev, rev_str)); merge_ctx->commit_info->revision = (svn_revnum_t)rev; } else merge_ctx->commit_info->revision = SVN_INVALID_REVNUM; merge_ctx->commit_info->date = apr_pstrdup(merge_ctx->pool, svn_hash_gets(attrs, "date")); merge_ctx->commit_info->author = apr_pstrdup(merge_ctx->pool, svn_hash_gets(attrs, "author")); merge_ctx->commit_info->post_commit_err = apr_pstrdup(merge_ctx->pool, svn_hash_gets(attrs, "post-commit-err")); } else { const char *href; href = svn_urlpath__skip_ancestor( merge_ctx->merge_url, svn_hash_gets(attrs, "href")); if (href == NULL) return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL, _("A MERGE response for '%s' is not " "a child of the destination ('%s')"), href, merge_ctx->merge_url); /* We now need to dive all the way into the WC to update the base VCC url. */ if (!SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(merge_ctx->session) && merge_ctx->session->wc_callbacks->push_wc_prop) { const char *checked_in; svn_string_t checked_in_str; checked_in = svn_hash_gets(attrs, "checked-in"); checked_in_str.data = checked_in; checked_in_str.len = strlen(checked_in); SVN_ERR(merge_ctx->session->wc_callbacks->push_wc_prop( merge_ctx->session->wc_callback_baton, href, SVN_RA_SERF__WC_CHECKED_IN_URL, &checked_in_str, scratch_pool)); } } } else if (leaving_state == BASELINE) { svn_ra_serf__xml_note(xes, RESPONSE, "resourcetype", "baseline"); } else if (leaving_state == COLLECTION) { svn_ra_serf__xml_note(xes, RESPONSE, "resourcetype", "collection"); } else { const char *name; const char *value = cdata->data; if (leaving_state == HREF) { name = "href"; value = svn_urlpath__canonicalize(value, scratch_pool); } else if (leaving_state == CHECKED_IN) { name = "checked-in"; value = svn_urlpath__canonicalize(value, scratch_pool); } else if (leaving_state == VERSION_NAME) name = "revision"; else if (leaving_state == DATE) name = "date"; else if (leaving_state == AUTHOR) name = "author"; else if (leaving_state == POST_COMMIT_ERR) name = "post-commit-err"; else SVN_ERR_MALFUNCTION(); svn_ra_serf__xml_note(xes, RESPONSE, name, value); } return SVN_NO_ERROR; }
/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * getlocks_closed(svn_ra_serf__xml_estate_t *xes, void *baton, int leaving_state, const svn_string_t *cdata, apr_hash_t *attrs, apr_pool_t *scratch_pool) { lock_context_t *lock_ctx = baton; if (leaving_state == LOCK) { const char *path = svn_hash_gets(attrs, "path"); svn_boolean_t save_lock = FALSE; /* Filter out unwanted paths. Since Subversion only allows locks on files, we can treat depth=immediates the same as depth=files for filtering purposes. Meaning, we'll keep this lock if: a) its path is the very path we queried, or b) we've asked for a fully recursive answer, or c) we've asked for depth=files or depth=immediates, and this lock is on an immediate child of our query path. */ if (strcmp(lock_ctx->path, path) == 0 || lock_ctx->requested_depth == svn_depth_infinity) { save_lock = TRUE; } else if (lock_ctx->requested_depth == svn_depth_files || lock_ctx->requested_depth == svn_depth_immediates) { const char *relpath = svn_fspath__skip_ancestor(lock_ctx->path, path); if (relpath && (svn_path_component_count(relpath) == 1)) save_lock = TRUE; } if (save_lock) { /* We get to put the structure on the stack rather than using svn_lock_create(). Bwahahaha.... */ svn_lock_t lock = { 0 }; const char *date; svn_lock_t *result_lock; /* Note: these "attributes" came from child elements. Some of them may have not been sent, so the value will be NULL. */ lock.path = path; lock.token = svn_hash_gets(attrs, "token"); lock.owner = svn_hash_gets(attrs, "owner"); lock.comment = svn_hash_gets(attrs, "comment"); date = svn_hash_gets(attrs, SVN_DAV__CREATIONDATE); if (date) SVN_ERR(svn_time_from_cstring(&lock.creation_date, date, scratch_pool)); date = svn_hash_gets(attrs, "expirationdate"); if (date) SVN_ERR(svn_time_from_cstring(&lock.expiration_date, date, scratch_pool)); result_lock = svn_lock_dup(&lock, lock_ctx->pool); svn_hash_sets(lock_ctx->hash, result_lock->path, result_lock); } } else { const char *name; SVN_ERR_ASSERT(cdata != NULL); if (leaving_state == PATH) name = "path"; else if (leaving_state == TOKEN) name = "token"; else if (leaving_state == OWNER) name = "owner"; else if (leaving_state == COMMENT) name = "comment"; else if (leaving_state == CREATION_DATE) name = SVN_DAV__CREATIONDATE; else if (leaving_state == EXPIRATION_DATE) name = "expirationdate"; else SVN_ERR_MALFUNCTION(); /* Store the lock information onto the LOCK elemstate. */ svn_ra_serf__xml_note(xes, LOCK, name, cdata->data); } return SVN_NO_ERROR; }
/* Conforms to svn_ra_serf__xml_closed_t */ static svn_error_t * log_closed(svn_ra_serf__xml_estate_t *xes, void *baton, int leaving_state, const svn_string_t *cdata, apr_hash_t *attrs, apr_pool_t *scratch_pool) { log_context_t *log_ctx = baton; if (leaving_state == ITEM) { svn_log_entry_t *log_entry; const char *rev_str; if (log_ctx->limit && (log_ctx->nest_level == 0) && (++log_ctx->count > log_ctx->limit)) { return SVN_NO_ERROR; } log_entry = svn_log_entry_create(scratch_pool); /* Pick up the paths from the context. These have the same lifetime as this state. That is long enough for us to pass the paths to the receiver callback. */ if (apr_hash_count(log_ctx->collect_paths) > 0) { log_entry->changed_paths = log_ctx->collect_paths; log_entry->changed_paths2 = log_ctx->collect_paths; } /* ... and same story for the collected revprops. */ log_entry->revprops = log_ctx->collect_revprops; log_entry->has_children = svn_hash__get_bool(attrs, "has-children", FALSE); log_entry->subtractive_merge = svn_hash__get_bool(attrs, "subtractive-merge", FALSE); rev_str = apr_hash_get(attrs, "revision", APR_HASH_KEY_STRING); if (rev_str) log_entry->revision = SVN_STR_TO_REV(rev_str); else log_entry->revision = SVN_INVALID_REVNUM; /* Give the info to the reporter */ SVN_ERR(log_ctx->receiver(log_ctx->receiver_baton, log_entry, scratch_pool)); if (log_entry->has_children) { log_ctx->nest_level++; } if (! SVN_IS_VALID_REVNUM(log_entry->revision)) { SVN_ERR_ASSERT(log_ctx->nest_level); log_ctx->nest_level--; } /* These hash tables are going to be unusable once this state's pool is destroyed. But let's not leave stale pointers in structures that have a longer life. */ log_ctx->collect_revprops = NULL; log_ctx->collect_paths = NULL; } else if (leaving_state == VERSION) { svn_ra_serf__xml_note(xes, ITEM, "revision", cdata->data); } else if (leaving_state == CREATOR) { if (log_ctx->want_author) { SVN_ERR(collect_revprop(log_ctx->collect_revprops, SVN_PROP_REVISION_AUTHOR, cdata, apr_hash_get(attrs, "encoding", APR_HASH_KEY_STRING))); } } else if (leaving_state == DATE) { if (log_ctx->want_date) { SVN_ERR(collect_revprop(log_ctx->collect_revprops, SVN_PROP_REVISION_DATE, cdata, apr_hash_get(attrs, "encoding", APR_HASH_KEY_STRING))); } } else if (leaving_state == COMMENT) { if (log_ctx->want_message) { SVN_ERR(collect_revprop(log_ctx->collect_revprops, SVN_PROP_REVISION_LOG, cdata, apr_hash_get(attrs, "encoding", APR_HASH_KEY_STRING))); } } else if (leaving_state == REVPROP) { apr_pool_t *result_pool = apr_hash_pool_get(log_ctx->collect_revprops); SVN_ERR(collect_revprop( log_ctx->collect_revprops, apr_pstrdup(result_pool, apr_hash_get(attrs, "name", APR_HASH_KEY_STRING)), cdata, apr_hash_get(attrs, "encoding", APR_HASH_KEY_STRING) )); } else if (leaving_state == HAS_CHILDREN) { svn_ra_serf__xml_note(xes, ITEM, "has-children", "yes"); } else if (leaving_state == SUBTRACTIVE_MERGE) { svn_ra_serf__xml_note(xes, ITEM, "subtractive-merge", "yes"); } else { char action; if (leaving_state == ADDED_PATH) action = 'A'; else if (leaving_state == REPLACED_PATH) action = 'R'; else if (leaving_state == DELETED_PATH) action = 'D'; else { SVN_ERR_ASSERT(leaving_state == MODIFIED_PATH); action = 'M'; } SVN_ERR(collect_path(log_ctx->collect_paths, action, cdata, attrs)); } return SVN_NO_ERROR; }