📄 fetch.c
字号:
}#undef NSLEN else { /* If we get here, then we have a property that is neither in the 'custom' space, nor in the 'svn' space. So it must be either in the 'network' space or 'DAV:' space. The following routine converts a handful of DAV: props into 'svn:wc:' or 'svn:entry:' props that libsvn_wc wants. */ SVN_ERR(set_special_wc_prop(key, val, setter, baton, pool)); } } return SVN_NO_ERROR;} #ifdef SVN_NEON_0_25/* This implements the svn_ra_dav__request_interrogator() interface. USERDATA is 'ne_content_type *'. */static svn_error_t *interrogate_for_content_type(ne_request *request, int dispatch_return_val, void *userdata){ ne_content_type *ctype = userdata; if (ne_get_content_type(request, ctype) != 0) return svn_error_createf (SVN_ERR_RA_DAV_RESPONSE_HEADER_BADNESS, NULL, _("Could not get content-type from response")); return SVN_NO_ERROR;}#endif /* SVN_NEON_0_25 */static svn_error_t *custom_get_request(ne_session *sess, const char *url, const char *relpath, ne_block_reader reader, void *subctx, svn_ra_get_wc_prop_func_t get_wc_prop, void *cb_baton, svn_boolean_t use_base, apr_pool_t *pool){ custom_get_ctx_t cgc = { 0 }; const char *delta_base; ne_request *req; ne_decompress *decompress; svn_error_t *err;#ifndef SVN_NEON_0_25 int decompress_rv;#endif /* ! SVN_NEON_0_25 */ svn_ra_dav__session_t *ras = ne_get_session_private(sess, SVN_RA_NE_SESSION_ID); if (use_base) { /* See if we can get a version URL for this resource. This will refer to what we already have in the working copy, thus we can get a diff against this particular resource. */ SVN_ERR(get_delta_base(&delta_base, relpath, get_wc_prop, cb_baton, pool)); } else { delta_base = NULL; } req = ne_request_create(sess, "GET", url); if (req == NULL) { return svn_error_createf(SVN_ERR_RA_DAV_CREATING_REQUEST, NULL, _("Could not create a GET request for '%s'"), url); }#ifndef SVN_NEON_0_25 /* we want to get the Content-Type so that we can figure out whether this is an svndiff or a fulltext */ ne_add_response_header_handler(req, "Content-Type", ne_content_type_handler, &cgc.ctype);#endif /* ! SVN_NEON_0_25 */ if (delta_base) { /* The HTTP delta draft uses an If-None-Match header holding an entity tag corresponding to the copy we have. It is much more natural for us to use a version URL to specify what we have. Thus, we want to use the If: header to specify the URL. But mod_dav sees all "State-token" items as lock tokens. When we get mod_dav updated and the backend APIs expanded, then we can switch to using the If: header. For now, use a custom header to specify the version resource to use as the base. */ ne_add_request_header(req, SVN_DAV_DELTA_BASE_HEADER, delta_base); } /* add in a reader to capture the body of the response. */ if (ras->compression) { decompress = ne_decompress_reader(req, ne_accept_2xx, reader, &cgc); } else { decompress = NULL; ne_add_response_body_reader(req, ne_accept_2xx, reader, &cgc); } /* complete initialization of the body reading context */ cgc.subctx = subctx; /* run the request */ err = svn_ra_dav__request_dispatch(NULL, req, sess, "GET", url, 200 /* OK */, 226 /* IM Used */,#ifdef SVN_NEON_0_25 interrogate_for_content_type, &cgc.ctype,#endif /* SVN_NEON_0_25 */ pool);#ifdef SVN_NEON_0_25 if (decompress) ne_decompress_destroy(decompress);#else /* ! SVN_NEON_0_25 */ if (decompress) decompress_rv = ne_decompress_destroy(decompress); else decompress_rv = 0;#endif /* if/else SVN_NEON_0_25 */ /* we no longer need this */ if (cgc.ctype.value != NULL) free(cgc.ctype.value); /* if there was an error writing the contents, then return it rather than Neon-related errors */ if (cgc.err) { if (err) svn_error_clear(err); return cgc.err; }#ifndef SVN_NEON_0_25 if (decompress_rv != 0) { const char *msg; msg = apr_psprintf(pool, _("GET request failed for '%s'"), url); if (err) svn_error_clear(err); err = svn_ra_dav__convert_error(sess, msg, decompress_rv, pool); }#endif /* ! SVN_NEON_0_25 */ return err;}/* This implements the ne_block_reader() callback interface. */#ifdef SVN_NEON_0_25static int#else /* ! SVN_NEON_0_25 */static void#endif /* if/else SVN_NEON_0_25 */fetch_file_reader(void *userdata, const char *buf, size_t len){ custom_get_ctx_t *cgc = userdata; file_read_ctx_t *frc = cgc->subctx; if (cgc->err) { /* We must have gotten an error during the last read. */#ifdef SVN_NEON_0_25 /* Abort the rest of the read. */ /* ### Call ne_set_error(), as ne_block_reader doc implies? */ return 1;#else /* ! SVN_NEON_0_25 */ /* In Neon < 0.25.0, we have no way to abort the read process, so we'll just have to eat all the data, even though we already know we can't handle it. */ return;#endif /* if/else SVN_NEON_0_25 */ } if (len == 0) { /* file is complete. */#ifdef SVN_NEON_0_25 return 0;#else /* ! SVN_NEON_0_25 */ return;#endif /* if/else SVN_NEON_0_25 */ } if (!cgc->checked_type) { if (cgc->ctype.type && cgc->ctype.subtype && !strcmp(cgc->ctype.type, "application") && !strcmp(cgc->ctype.subtype, "vnd.svn-svndiff")) { /* we are receiving an svndiff. set things up. */ frc->stream = svn_txdelta_parse_svndiff(frc->handler, frc->handler_baton, TRUE, frc->pool); } cgc->checked_type = 1; } if (frc->stream == NULL) { /* receiving plain text. construct a window for it. */ svn_txdelta_window_t window = { 0 }; svn_txdelta_op_t op; svn_string_t data; data.data = buf; data.len = len; op.action_code = svn_txdelta_new; op.offset = 0; op.length = len; window.tview_len = len; /* result will be this long */ window.num_ops = 1; window.ops = &op; window.new_data = &data; /* We can't really do anything useful if we get an error here. Pass it off to someone who can. */ cgc->err = (*frc->handler)(&window, frc->handler_baton); } else { /* receiving svndiff. feed it to the svndiff parser. */ apr_size_t written = len; cgc->err = svn_stream_write(frc->stream, buf, &written); /* ### the svndiff stream parser does not obey svn_stream semantics ### in its write handler. it does not output the number of bytes ### consumed by the handler. specifically, it may decrement the ### number by 4 for the header, then never touch it again. that ### makes it appear like an incomplete write. ### disable this check for now. the svndiff parser actually does ### consume all bytes, all the time. */#if 0 if (written != len && cgc->err == NULL) cgc->err = svn_error_createf(SVN_ERR_INCOMPLETE_DATA, NULL, "Unable to completely write the svndiff " "data to the parser stream " "(wrote " APR_SIZE_T_FMT " " "of " APR_SIZE_T_FMT " bytes)", written, len);#endif }#ifdef SVN_NEON_0_25 return 0;#endif /* SVN_NEON_0_25 */}static svn_error_t *simple_fetch_file(ne_session *sess, const char *url, const char *relpath, svn_boolean_t text_deltas, void *file_baton, const char *base_checksum, const svn_delta_editor_t *editor, svn_ra_get_wc_prop_func_t get_wc_prop, void *cb_baton, apr_pool_t *pool){ file_read_ctx_t frc = { 0 }; SVN_ERR_W((*editor->apply_textdelta)(file_baton, base_checksum, pool, &frc.handler, &frc.handler_baton), _("Could not save file")); /* Only bother with text-deltas if our caller cares. */ if (! text_deltas) { SVN_ERR((*frc.handler)(NULL, frc.handler_baton)); return SVN_NO_ERROR; } frc.pool = pool; SVN_ERR(custom_get_request(sess, url, relpath, fetch_file_reader, &frc, get_wc_prop, cb_baton, TRUE, pool)); /* close the handler, since the file reading completed successfully. */ SVN_ERR((*frc.handler)(NULL, frc.handler_baton)); return SVN_NO_ERROR;}/* Helper (neon callback) for svn_ra_dav__get_file. This implements the ne_block_reader() callback interface. */#ifdef SVN_NEON_0_25static int#else /* ! SVN_NEON_0_25 */static void#endif /* if/else SVN_NEON_0_25 */get_file_reader(void *userdata, const char *buf, size_t len){ custom_get_ctx_t *cgc = userdata; apr_size_t wlen; svn_error_t *err; /* The stream we want to push data at. */ file_write_ctx_t *fwc = cgc->subctx; svn_stream_t *stream = fwc->stream; if (fwc->do_checksum) apr_md5_update(&(fwc->md5_context), buf, len); /* Write however many bytes were passed in by neon. */ wlen = len; err = svn_stream_write(stream, buf, &wlen);#ifdef SVN_NEON_0_25 /* Technically, if the write came up short then there's guaranteed to be an error anyway, so we only really need to check for error. But heck, why not gather as much information as possible about what happened before tossing it all and just returning non-zero? */ if (err || (wlen != len)) { /* ### Call ne_set_error(), as ne_block_reader doc implies? */ svn_error_clear(err); return 1; } return 0;#endif /* SVN_NEON_0_25 */}/* minor helper for svn_ra_dav__get_file, of type prop_setter_t */static svn_error_t * add_prop_to_hash(void *baton, const char *name, const svn_string_t *value, apr_pool_t *pool){ apr_hash_t *ht = (apr_hash_t *) baton; apr_hash_set(ht, name, APR_HASH_KEY_STRING, value); return SVN_NO_ERROR;}/* Helper for svn_ra_dav__get_file(), svn_ra_dav__get_dir(), and svn_ra_dav__rev_proplist(). Loop over the properties in RSRC->propset, examining namespaces and such to filter Subversion, custom, etc. properties. User-visible props get added to the PROPS hash (alloced in POOL). If ADD_ENTRY_PROPS is true, then "special" working copy entry-props are added to the hash by set_special_wc_prop().
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -