📄 props.c
字号:
/* There is an encoding on this property, handle it. * the braces are needed to allocate "in" on the stack. */ { svn_string_t in; in.data = cdata; in.len = strlen(cdata); value = svn_base64_decode_string(&in, pc->pool); } pc->encoding = NULL; /* Reset encoding for future attribute(s). */ } /*** Handling resource properties from here out. ***/ /* Add properties to the temporary propbuffer. At the end of the <propstat>, we'll either dump the props as invalid or move them into the resource's property hash. */ apr_hash_set(pc->propbuffer, name, APR_HASH_KEY_STRING, value); return SVN_RA_DAV__XML_VALID;}static void set_parser(ne_xml_parser *parser, void *baton){ propfind_ctx_t *pc = baton; pc->parser = parser;} svn_error_t * svn_ra_dav__get_props(apr_hash_t **results, ne_session *sess, const char *url, int depth, const char *label, const ne_propname *which_props, apr_pool_t *pool){ svn_error_t *err = SVN_NO_ERROR; propfind_ctx_t pc; ne_buffer *body; apr_hash_t *extra_headers = apr_hash_make(pool); /* Add a Depth header. */ if (depth == NE_DEPTH_ZERO) apr_hash_set(extra_headers, "Depth", 5, "0"); else if (depth == NE_DEPTH_ONE) apr_hash_set(extra_headers, "Depth", 5, "1"); else if (depth == NE_DEPTH_INFINITE) apr_hash_set(extra_headers, "Depth", 5, "infinite"); else abort(); /* somebody passed some poo to our function. */ /* If we have a label, use it. */ if (label != NULL) apr_hash_set(extra_headers, "Label", 5, label); /* It's easier to roll our own PROPFIND here than use neon's current interfaces. */ body = ne_buffer_create(); /* The start of the request body is fixed: */ ne_buffer_zappend(body, "<?xml version=\"1.0\" encoding=\"utf-8\"?>" DEBUG_CR "<propfind xmlns=\"DAV:\">" DEBUG_CR); /* Are we asking for specific propert(y/ies), or just all of them? */ if (which_props) { int n; ne_buffer_zappend(body, "<prop>" DEBUG_CR); for (n = 0; which_props[n].name != NULL; n++) { ne_buffer_concat(body, "<", which_props[n].name, " xmlns=\"", which_props[n].nspace, "\"/>" DEBUG_CR, NULL); } ne_buffer_zappend(body, "</prop></propfind>" DEBUG_CR); } else { ne_buffer_zappend(body, "<allprop/></propfind>" DEBUG_CR); } /* Initialize our baton. */ memset(&pc, 0, sizeof(pc)); pc.pool = pool; pc.propbuffer = apr_hash_make(pool); pc.props = apr_hash_make(pool); /* Create and dispatch the request! */ err = svn_ra_dav__parsed_request_compat(sess, "PROPFIND", url, body->data, 0, set_parser, propfind_elements, validate_element, start_element, end_element, &pc, extra_headers, NULL, FALSE, pool); ne_buffer_destroy(body); *results = pc.props; return err;}svn_error_t * svn_ra_dav__get_props_resource(svn_ra_dav_resource_t **rsrc, ne_session *sess, const char *url, const char *label, const ne_propname *which_props, apr_pool_t *pool){ apr_hash_t *props; char * url_path = apr_pstrdup(pool, url); int len = strlen(url); /* Clean up any trailing slashes. */ if (len > 1 && url[len - 1] == '/') url_path[len - 1] = '\0'; SVN_ERR(svn_ra_dav__get_props(&props, sess, url_path, NE_DEPTH_ZERO, label, which_props, pool)); /* ### HACK. We need to have the client canonicalize paths, get rid of double slashes and such. This check is just a check against non-SVN servers; in the long run we want to re-enable this. */ if (1 || label != NULL) { /* pick out the first response: the URL requested will not match * the response href. */ apr_hash_index_t *hi = apr_hash_first(pool, props); if (hi) { void *ent; apr_hash_this(hi, NULL, NULL, &ent); *rsrc = ent; } else *rsrc = NULL; } else { *rsrc = apr_hash_get(props, url_path, APR_HASH_KEY_STRING); } if (*rsrc == NULL) { /* ### hmmm, should have been in there... */ return svn_error_createf(APR_EGENERAL, NULL, _("Failed to find label '%s' for URL '%s'"), label ? label : "NULL", url_path); } return SVN_NO_ERROR;}svn_error_t * svn_ra_dav__get_one_prop(const svn_string_t **propval, ne_session *sess, const char *url, const char *label, const ne_propname *propname, apr_pool_t *pool){ svn_ra_dav_resource_t *rsrc; ne_propname props[2] = { { 0 } }; const char *name; const svn_string_t *value; props[0] = *propname; SVN_ERR(svn_ra_dav__get_props_resource(&rsrc, sess, url, label, props, pool)); name = apr_pstrcat(pool, propname->nspace, propname->name, NULL); value = apr_hash_get(rsrc->propset, name, APR_HASH_KEY_STRING); if (value == NULL) { /* ### need an SVN_ERR here */ return svn_error_createf(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL, _("'%s' was not present on the resource"), name); } *propval = value; return SVN_NO_ERROR;}svn_error_t * svn_ra_dav__get_starting_props(svn_ra_dav_resource_t **rsrc, ne_session *sess, const char *url, const char *label, apr_pool_t *pool){ return svn_ra_dav__get_props_resource(rsrc, sess, url, label, starting_props, pool);}svn_error_t * svn_ra_dav__search_for_starting_props(svn_ra_dav_resource_t **rsrc, const char **missing_path, ne_session *sess, const char *url, apr_pool_t *pool){ svn_error_t *err = SVN_NO_ERROR; apr_size_t len; svn_stringbuf_t *path_s; ne_uri parsed_url; const char *lopped_path = ""; /* Split the url into its component pieces (scheme, host, path, etc). We want the path part. */ ne_uri_parse(url, &parsed_url); if (parsed_url.path == NULL) { return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, _("Neon was unable to parse URL '%s'"), url); } path_s = svn_stringbuf_create(parsed_url.path, pool); /* Try to get the starting_props from the public url. If the resource no longer exists in HEAD, we'll get a failure. That's fine: just keep removing components and trying to get the starting_props from parent directories. */ while (! svn_path_is_empty(path_s->data)) { err = svn_ra_dav__get_starting_props(rsrc, sess, path_s->data, NULL, pool); if (! err) break; /* found an existing parent! */ if (err->apr_err != SVN_ERR_RA_DAV_PATH_NOT_FOUND) goto error; /* found a _real_ error */ /* else... lop off the basename and try again. */ lopped_path = svn_path_join(svn_path_basename(path_s->data, pool), lopped_path, pool); len = path_s->len; svn_path_remove_component(path_s); /* if we detect an infinite loop, get out. */ if (path_s->len == len) { err = svn_error_quick_wrap (err, _("The path was not part of a repository")); goto error; } svn_error_clear(err); } /* error out if entire URL was bogus (not a single part of it exists in the repository!) */ if (svn_path_is_empty(path_s->data)) { err = svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, _("No part of path '%s' was found in " "repository HEAD"), parsed_url.path); goto error; } *missing_path = lopped_path; error: ne_uri_free(&parsed_url); return err;}svn_error_t *svn_ra_dav__get_vcc(const char **vcc, ne_session *sess, const char *url, apr_pool_t *pool){ svn_ra_dav_resource_t *rsrc; const char *lopped_path; const svn_string_t *vcc_s; /* ### Someday, possibly look for memory-cached VCC in the RA session. */ /* ### Someday, possibly look for disk-cached VCC via get_wcprop callback. */ /* Finally, resort to a set of PROPFINDs up parent directories. */ SVN_ERR(svn_ra_dav__search_for_starting_props(&rsrc, &lopped_path, sess, url, pool)); vcc_s = apr_hash_get(rsrc->propset, SVN_RA_DAV__PROP_VCC, APR_HASH_KEY_STRING); if (! vcc_s) return svn_error_create(APR_EGENERAL, NULL, _("The VCC property was not found on the " "resource")); *vcc = vcc_s->data; return SVN_NO_ERROR;}svn_error_t *svn_ra_dav__get_baseline_props(svn_string_t *bc_relative, svn_ra_dav_resource_t **bln_rsrc, ne_session *sess, const char *url, svn_revnum_t revision, const ne_propname *which_props, apr_pool_t *pool){ svn_ra_dav_resource_t *rsrc; const svn_string_t *vcc; const svn_string_t *relative_path; const char *my_bc_relative; const char *lopped_path; /* ### we may be able to replace some/all of this code with an ### expand-property REPORT when that is available on the server. */ /* ------------------------------------------------------------------- STEP 1 Fetch the following properties from the given URL (or, if URL no longer exists in HEAD, get the properties from the nearest still-existing parent resource): *) DAV:version-controlled-configuration so that we can reach the baseline information. *) svn:baseline-relative-path so that we can find this resource within a Baseline Collection. If we need to search up parent directories, then the relative path is this property value *plus* any trailing components we had to chop off. *) DAV:resourcetype so that we can identify whether this resource is a collection or not -- assuming we never had to search up parent directories. */ SVN_ERR(svn_ra_dav__search_for_starting_props(&rsrc, &lopped_path, sess, url, pool)); vcc = apr_hash_get(rsrc->propset, SVN_RA_DAV__PROP_VCC, APR_HASH_KEY_STRING); if (vcc == NULL) { /* ### better error reporting... */ /* ### need an SVN_ERR here */ return svn_error_create(APR_EGENERAL, NULL, _("The VCC property was not found on the " "resource")); } /* Allocate our own bc_relative path. */ relative_path = apr_hash_get(rsrc->propset, SVN_RA_DAV__PROP_BASELINE_RELPATH, APR_HASH_KEY_STRING); if (relative_path == NULL) { /* ### better error reporting... */ /* ### need an SVN_ERR here */ return svn_error_create(APR_EGENERAL, NULL, _("The relative-path property was not " "found on the resource")); } /* don't forget to tack on the parts we lopped off in order to find the VCC... We are expected to return a URI decoded relative path, so decode the lopped path first. */ my_bc_relative = svn_path_join(relative_path->data, svn_path_uri_decode(lopped_path, pool), pool); /* if they want the relative path (could be, they're just trying to find the baseline collection), then return it */ if (bc_relative) { bc_relative->data = my_bc_relative; bc_relative->len = strlen(my_bc_relative); } /* ------------------------------------------------------------------- STEP 2 We have the Version Controlled Configuration (VCC). From here, we need to reach the Baseline for specified revision. If the revision is SVN_INVALID_REVNUM, then we're talking about the HEAD revision. We have one extra step to reach the Baseline: *) Fetch the DAV:checked-in from the VCC; it points to the Baseline. If we have a specific revision, then we use a Label header when fetching props from the VCC. This will direct us to the Baseline with that label (in this case, the label == the revision number). From the Baseline, we fetch the following properties: *) DAV:baseline-collection, which is a complete tree of the Baseline (in SVN terms, this tree is rooted at a specific revision) *) DAV:version-name to get the revision of the Baseline that we are querying. When asking about the HEAD, this tells us its revision. */ if (revision == SVN_INVALID_REVNUM) { /* Fetch the latest revision */ const svn_string_t *baseline; /* Get the Baseline from the DAV:checked-in value, then fetch its DAV:baseline-collection property. */ /* ### should wrap this with info about rsrc==VCC */ SVN_ERR(svn_ra_dav__get_one_prop(&baseline, sess, vcc->data, NULL, &svn_ra_dav__checked_in_prop, pool)); /* ### do we want to optimize the props we fetch, based on what the ### user asked for? i.e. omit version-name if latest_rev is NULL */ SVN_ERR(svn_ra_dav__get_props_resource(&rsrc, sess, baseline->data, NULL, which_props, pool)); } else { /* Fetch a specific revision */ char label[20]; /* ### send Label hdr, get DAV:baseline-collection [from the baseline] */ apr_snprintf(label, sizeof(label), "%ld", revision); /* ### do we want to optimize the props we fetch, based on what the ### user asked for? i.e. omit version-name if latest_rev is NULL */ SVN_ERR(svn_ra_dav__get_props_resource(&rsrc, sess, vcc->data, label, which_props, pool)); } /* Return the baseline rsrc, which now contains whatever set of props the caller wanted. */ *bln_rsrc = rsrc; return SVN_NO_ERROR;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -