📄 props.c
字号:
svn_error_t *svn_ra_dav__get_baseline_info(svn_boolean_t *is_dir, svn_string_t *bc_url, svn_string_t *bc_relative, svn_revnum_t *latest_rev, ne_session *sess, const char *url, svn_revnum_t revision, apr_pool_t *pool){ svn_ra_dav_resource_t *baseline_rsrc, *rsrc; const svn_string_t *my_bc_url; svn_string_t my_bc_rel; /* Go fetch a BASELINE_RSRC that contains specific properties we want. This routine will also fill in BC_RELATIVE as best it can. */ SVN_ERR(svn_ra_dav__get_baseline_props(&my_bc_rel, &baseline_rsrc, sess, url, revision, baseline_props, /* specific props */ pool)); /* baseline_rsrc now points at the Baseline. We will checkout from the DAV:baseline-collection. The revision we are checking out is in DAV:version-name */ /* Allocate our own copy of bc_url regardless. */ my_bc_url = apr_hash_get(baseline_rsrc->propset, SVN_RA_DAV__PROP_BASELINE_COLLECTION, APR_HASH_KEY_STRING); if (my_bc_url == NULL) { /* ### better error reporting... */ /* ### need an SVN_ERR here */ return svn_error_create(APR_EGENERAL, NULL, _("'DAV:baseline-collection' was not present " "on the baseline resource")); } /* maybe return bc_url to the caller */ if (bc_url) *bc_url = *my_bc_url; if (latest_rev != NULL) { const svn_string_t *vsn_name= apr_hash_get(baseline_rsrc->propset, SVN_RA_DAV__PROP_VERSION_NAME, APR_HASH_KEY_STRING); if (vsn_name == NULL) { /* ### better error reporting... */ /* ### need an SVN_ERR here */ return svn_error_create(APR_EGENERAL, NULL, _("'DAV:version-name' was not present" " on the baseline resource")); } *latest_rev = SVN_STR_TO_REV(vsn_name->data); } if (is_dir != NULL) { /* query the DAV:resourcetype of the full, assembled URL. */ const char *full_bc_url = svn_path_url_add_component(my_bc_url->data, my_bc_rel.data, pool); SVN_ERR(svn_ra_dav__get_props_resource(&rsrc, sess, full_bc_url, NULL, starting_props, pool)); *is_dir = rsrc->is_collection; } if (bc_relative) *bc_relative = my_bc_rel; return SVN_NO_ERROR;}/* Helper function for svn_ra_dav__do_proppatch() below. */static voiddo_setprop(ne_buffer *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) { ne_buffer_concat(body, "<", xml_tag_name, "/>", NULL); 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_string(value, pool); encoding = " V:encoding=\"base64\""; xml_safe = base64ed->data; } ne_buffer_concat(body, "<", xml_tag_name, encoding, ">", xml_safe, "</", xml_tag_name, ">", NULL); return;}svn_error_t *svn_ra_dav__do_proppatch(svn_ra_dav__session_t *ras, const char *url, apr_hash_t *prop_changes, apr_array_header_t *prop_deletes, apr_hash_t *extra_headers, apr_pool_t *pool){ ne_request *req; int code; ne_buffer *body; /* ### using an ne_buffer because it can realloc */ svn_error_t *err; /* just punt if there are no changes to make. */ if ((prop_changes == NULL || (! apr_hash_count(prop_changes))) && (prop_deletes == NULL || prop_deletes->nelts == 0)) return SVN_NO_ERROR; /* easier to roll our own PROPPATCH here than use ne_proppatch(), which * doesn't really do anything clever. */ body = ne_buffer_create(); ne_buffer_zappend(body, "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" DEBUG_CR "<D:propertyupdate xmlns:D=\"DAV:\" xmlns:V=\"" SVN_DAV_PROP_NS_DAV "\" xmlns:C=\"" SVN_DAV_PROP_NS_CUSTOM "\" xmlns:S=\"" SVN_DAV_PROP_NS_SVN "\">"); /* Handle property changes. */ if (prop_changes) { apr_hash_index_t *hi; apr_pool_t *subpool = svn_pool_create(pool); ne_buffer_zappend(body, "<D:set><D:prop>"); for (hi = apr_hash_first(pool, prop_changes); hi; hi = apr_hash_next(hi)) { const void *key; void *val; svn_pool_clear(subpool); apr_hash_this(hi, &key, NULL, &val); do_setprop(body, key, val, subpool); } ne_buffer_zappend(body, "</D:prop></D:set>"); svn_pool_destroy(subpool); } /* Handle property deletions. */ if (prop_deletes) { int n; ne_buffer_zappend(body, "<D:remove><D:prop>"); for (n = 0; n < prop_deletes->nelts; n++) { const char *name = APR_ARRAY_IDX(prop_deletes, n, const char *); do_setprop(body, name, NULL, pool); } ne_buffer_zappend(body, "</D:prop></D:remove>"); } /* Finish up the body. */ ne_buffer_zappend(body, "</D:propertyupdate>"); req = ne_request_create(ras->sess, "PROPPATCH", url); ne_set_request_body_buffer(req, body->data, ne_buffer_size(body)); ne_add_request_header(req, "Content-Type", "text/xml; charset=UTF-8"); /* add any extra headers passed in by caller. */ if (extra_headers != NULL) { apr_hash_index_t *hi; for (hi = apr_hash_first(pool, extra_headers); hi; hi = apr_hash_next(hi)) { const void *key; void *val; apr_hash_this(hi, &key, NULL, &val); ne_add_request_header(req, (const char *) key, (const char *) val); } } code = ne_simple_request(ras->sess, req); if (code == NE_OK) { err = SVN_NO_ERROR; } else { /* WebDAV spec says that if any part of a PROPPATCH fails, the entire 'commit' is rejected. */ err = svn_error_create (SVN_ERR_RA_DAV_PROPPATCH_FAILED, NULL, _("At least one property change failed; repository is unchanged")); } ne_buffer_destroy(body); return err;}svn_error_t *svn_ra_dav__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_dav__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_dav__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_dav__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_dav__get_baseline_info(&is_dir, NULL, NULL, NULL, ras->sess, 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_RA_DAV_PATH_NOT_FOUND) { svn_error_clear(err); *kind = svn_node_none; return SVN_NO_ERROR; } return err;}svn_error_t *svn_ra_dav__do_stat(svn_ra_session_t *session, const char *path, svn_revnum_t revision, svn_dirent_t **dirent, apr_pool_t *pool){ svn_ra_dav__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_dav__get_baseline_info(NULL, &bc_url, &bc_relative, NULL, ras->sess, url, revision, pool); if (err) { if (err->apr_err == SVN_ERR_RA_DAV_PATH_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_dav__get_props(&resources, ras->sess, final_url, NE_DEPTH_ZERO, NULL, NULL /* all props */, pool); if (err) { if (err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND) { /* easy out: */ svn_error_clear(err); *dirent = NULL; return SVN_NO_ERROR; } else return err; } /* Copying parsing code from svn_ra_dav__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)) { const void *key; void *val; const char *childname; svn_ra_dav_resource_t *resource; const svn_string_t *propval; apr_hash_index_t *h; svn_dirent_t *entry; apr_hash_this(hi, &key, NULL, &val); childname = key; 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_DAV__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; void *vval; apr_hash_this(h, &kkey, NULL, &vval); 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_DAV__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_DAV__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_DAV__PROP_CREATOR_DISPLAYNAME, APR_HASH_KEY_STRING); if (propval != NULL) entry->last_author = propval->data; *dirent = entry; } return SVN_NO_ERROR;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -