📄 fetch.c
字号:
*/static svn_error_t *filter_props(apr_hash_t *props, svn_ra_dav_resource_t *rsrc, svn_boolean_t add_entry_props, apr_pool_t *pool){ apr_hash_index_t *hi; for (hi = apr_hash_first(pool, rsrc->propset); hi; hi = apr_hash_next(hi)) { const void *key; const char *name; void *val; const svn_string_t *value; apr_hash_this(hi, &key, NULL, &val); name = key; value = svn_string_dup(val, pool); /* If the property is in the 'custom' namespace, then it's a normal user-controlled property coming from the fs. Just strip off this prefix and add to the hash. */#define NSLEN (sizeof(SVN_DAV_PROP_NS_CUSTOM) - 1) if (strncmp(name, SVN_DAV_PROP_NS_CUSTOM, NSLEN) == 0) { apr_hash_set(props, name + NSLEN, APR_HASH_KEY_STRING, value); continue; }#undef NSLEN /* If the property is in the 'svn' namespace, then it's a normal user-controlled property coming from the fs. Just strip off the URI prefix, add an 'svn:', and add to the hash. */#define NSLEN (sizeof(SVN_DAV_PROP_NS_SVN) - 1) if (strncmp(name, SVN_DAV_PROP_NS_SVN, NSLEN) == 0) { apr_hash_set(props, apr_pstrcat(pool, SVN_PROP_PREFIX, name + NSLEN, NULL), APR_HASH_KEY_STRING, value); continue; }#undef NSLEN else if (strcmp(name, SVN_RA_DAV__PROP_CHECKED_IN) == 0) { /* For files, we currently only have one 'wc' prop. */ apr_hash_set(props, SVN_RA_DAV__LP_VSN_URL, APR_HASH_KEY_STRING, value); } else { /* If it's one of the 'entry' props, this func will recognize the DAV: name & add it to the hash mapped to a new name recognized by libsvn_wc. */ if (add_entry_props) SVN_ERR(set_special_wc_prop(name, value, add_prop_to_hash, props, pool)); } } return SVN_NO_ERROR;}svn_error_t *svn_ra_dav__get_file(svn_ra_session_t *session, const char *path, svn_revnum_t revision, svn_stream_t *stream, svn_revnum_t *fetched_rev, apr_hash_t **props, apr_pool_t *pool){ svn_ra_dav_resource_t *rsrc; const char *final_url; svn_ra_dav__session_t *ras = session->priv; const char *url = svn_path_url_add_component(ras->url->data, path, pool); /* If the revision is invalid (head), then we're done. Just fetch the public URL, because that will always get HEAD. */ if ((! SVN_IS_VALID_REVNUM(revision)) && (fetched_rev == NULL)) final_url = url; /* If the revision is something specific, we need to create a bc_url. */ else { svn_revnum_t got_rev; svn_string_t bc_url, bc_relative; SVN_ERR(svn_ra_dav__get_baseline_info(NULL, &bc_url, &bc_relative, &got_rev, ras->sess, url, revision, pool)); final_url = svn_path_url_add_component(bc_url.data, bc_relative.data, pool); if (fetched_rev != NULL) *fetched_rev = got_rev; } if (stream) { svn_error_t *err; const svn_string_t *expected_checksum = NULL; file_write_ctx_t fwc; ne_propname md5_propname = { SVN_DAV_PROP_NS_DAV, "md5-checksum" }; unsigned char digest[APR_MD5_DIGESTSIZE]; const char *hex_digest; /* Only request a checksum if we're getting the file contents. */ /* ### We should arrange for the checksum to be returned in the svn_ra_dav__get_baseline_info() call above; that will prevent the extra round trip, at least some of the time. */ err = svn_ra_dav__get_one_prop(&expected_checksum, ras->sess, final_url, NULL, &md5_propname, pool); /* Older servers don't serve this prop, but that's okay. */ /* ### temporary hack for 0.17. if the server doesn't have the prop, ### then __get_one_prop returns an empty string. deal with it. */ if ((err && (err->apr_err == SVN_ERR_RA_DAV_PROPS_NOT_FOUND)) || (expected_checksum && (*expected_checksum->data == '\0'))) { fwc.do_checksum = FALSE; svn_error_clear(err); } else if (err) return err; else fwc.do_checksum = TRUE; fwc.stream = stream; if (fwc.do_checksum) apr_md5_init(&(fwc.md5_context)); /* Fetch the file, shoving it at the provided stream. */ SVN_ERR(custom_get_request(ras->sess, final_url, path, get_file_reader, &fwc, ras->callbacks->get_wc_prop, ras->callback_baton, FALSE, pool)); if (fwc.do_checksum) { apr_md5_final(digest, &(fwc.md5_context)); hex_digest = svn_md5_digest_to_cstring_display(digest, pool); if (strcmp(hex_digest, expected_checksum->data) != 0) return svn_error_createf (SVN_ERR_CHECKSUM_MISMATCH, NULL, _("Checksum mismatch for '%s':\n" " expected checksum: %s\n" " actual checksum: %s\n"), path, expected_checksum->data, hex_digest); } } if (props) { SVN_ERR(svn_ra_dav__get_props_resource(&rsrc, ras->sess, final_url, NULL, NULL /* all props */, pool)); *props = apr_hash_make(pool); SVN_ERR(filter_props(*props, rsrc, TRUE, pool)); } return SVN_NO_ERROR;}/* The property we need to fetch to see whether the server we are connected to supports the deadprop-count property. */static const ne_propname deadprop_count_support_props[] ={ { SVN_DAV_PROP_NS_DAV, "deadprop-count" }, { NULL }};svn_error_t *svn_ra_dav__get_dir(svn_ra_session_t *session, apr_hash_t **dirents, svn_revnum_t *fetched_rev, apr_hash_t **props, const char *path, svn_revnum_t revision, apr_uint32_t dirent_fields, apr_pool_t *pool){ svn_ra_dav_resource_t *rsrc; apr_hash_index_t *hi; apr_hash_t *resources; const char *final_url; apr_size_t final_url_n_components; svn_boolean_t supports_deadprop_count; svn_ra_dav__session_t *ras = session->priv; const char *url = svn_path_url_add_component(ras->url->data, path, pool); /* If the revision is invalid (head), then we're done. Just fetch the public URL, because that will always get HEAD. */ if ((! SVN_IS_VALID_REVNUM(revision)) && (fetched_rev == NULL)) final_url = url; /* If the revision is something specific, we need to create a bc_url. */ else { svn_revnum_t got_rev; svn_string_t bc_url, bc_relative; SVN_ERR(svn_ra_dav__get_baseline_info(NULL, &bc_url, &bc_relative, &got_rev, ras->sess, url, revision, pool)); final_url = svn_path_url_add_component(bc_url.data, bc_relative.data, pool); if (fetched_rev != NULL) *fetched_rev = got_rev; } /* For issue 2151: See if we are dealing with a server that understands the deadprop-count property. If it doesn't, we'll need to do an allprop PROPFIND. If it does, we'll execute a more targeted PROPFIND. */ { const svn_string_t *deadprop_count; SVN_ERR(svn_ra_dav__get_props_resource(&rsrc, ras->sess, final_url, NULL, deadprop_count_support_props, pool)); deadprop_count = apr_hash_get(rsrc->propset, SVN_RA_DAV__PROP_DEADPROP_COUNT, APR_HASH_KEY_STRING); supports_deadprop_count = (deadprop_count != NULL); } if (dirents) { ne_propname *which_props; /* if we didn't ask for the has_props field, we can get individual properties. */ if ((SVN_DIRENT_HAS_PROPS & dirent_fields) == 0 || supports_deadprop_count) { int num_props = 1; /* start with one for the final NULL */ if (dirent_fields & SVN_DIRENT_KIND) ++num_props; if (dirent_fields & SVN_DIRENT_SIZE) ++num_props; if (dirent_fields & SVN_DIRENT_HAS_PROPS) ++num_props; if (dirent_fields & SVN_DIRENT_CREATED_REV) ++num_props; if (dirent_fields & SVN_DIRENT_TIME) ++num_props; if (dirent_fields & SVN_DIRENT_LAST_AUTHOR) ++num_props; which_props = apr_pcalloc(pool, num_props * sizeof(ne_propname)); --num_props; /* damn zero based arrays... */ /* first, null out the end... */ which_props[num_props].nspace = NULL; which_props[num_props--].name = NULL; /* Now, go through and fill in the ones we care about, moving along the array as we go. */ if (dirent_fields & SVN_DIRENT_KIND) { which_props[num_props].nspace = "DAV:"; which_props[num_props--].name = "resourcetype"; } if (dirent_fields & SVN_DIRENT_SIZE) { which_props[num_props].nspace = "DAV:"; which_props[num_props--].name = "getcontentlength"; } if (dirent_fields & SVN_DIRENT_HAS_PROPS) { which_props[num_props].nspace = SVN_DAV_PROP_NS_DAV; which_props[num_props--].name = "deadprop-count"; } if (dirent_fields & SVN_DIRENT_CREATED_REV) { which_props[num_props].nspace = "DAV:"; which_props[num_props--].name = "version-name"; } if (dirent_fields & SVN_DIRENT_TIME) { which_props[num_props].nspace = "DAV:"; which_props[num_props--].name = "creationdate"; } if (dirent_fields & SVN_DIRENT_LAST_AUTHOR) { which_props[num_props].nspace = "DAV:"; which_props[num_props--].name = "creator-displayname"; } assert(num_props == -1); } else { /* get all props, since we need them all to do has_props */ which_props = NULL; } /* Just like Nautilus, Cadaver, or any other browser, we do a PROPFIND on the directory of depth 1. */ SVN_ERR(svn_ra_dav__get_props(&resources, ras->sess, final_url, NE_DEPTH_ONE, NULL, which_props, pool)); /* Count the number of path components in final_url. */ final_url_n_components = svn_path_component_count(final_url); /* Now we have a hash that maps a bunch of url children to resource objects. Each resource object contains the properties of the child. Parse these resources into svn_dirent_t structs. */ *dirents = apr_hash_make(pool); 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; /* Skip the effective '.' entry that comes back from NE_DEPTH_ONE. The children must have one more component then final_url. Note that we can't just strcmp the URLs because of URL encoding differences (i.e. %3c vs. %3C etc.) */ if (svn_path_component_count(childname) == final_url_n_components) continue; entry = apr_pcalloc(pool, sizeof(*entry)); if (dirent_fields & SVN_DIRENT_KIND) { /* node kind */ entry->kind = resource->is_collection ? svn_node_dir : svn_node_file; } if (dirent_fields & SVN_DIRENT_SIZE) { /* size */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -