|
|
SVN_ERR_RA_DAV_CATEGORY_START + 6, | SVN_ERR_RA_DAV_CATEGORY_START + 6, |
"Invalid configuration value") | "Invalid configuration value") |
| |
|
/** @deprecated To improve consistency between ra layers, this error code |
|
is replaced in ra_{neon|serf} by SVN_ERR_FS_NOT_FOUND. |
|
Slated for removal in the next major release. */ |
SVN_ERRDEF(SVN_ERR_RA_DAV_PATH_NOT_FOUND, | SVN_ERRDEF(SVN_ERR_RA_DAV_PATH_NOT_FOUND, |
SVN_ERR_RA_DAV_CATEGORY_START + 7, | SVN_ERR_RA_DAV_CATEGORY_START + 7, |
"HTTP Path Not Found") | "HTTP Path Not Found") |
|
|
if (err) | if (err) |
{ | { |
if (err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES | if (err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES |
|| err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND |
|
|| err->apr_err == SVN_ERR_FS_NOT_FOUND) | || err->apr_err == SVN_ERR_FS_NOT_FOUND) |
{ | { |
/* PATH@TARGET_ENTRY->REVISION didn't exist at | /* PATH@TARGET_ENTRY->REVISION didn't exist at |
|
|
if (err) | if (err) |
{ | { |
if (err->apr_err == SVN_ERR_FS_NOT_FOUND | if (err->apr_err == SVN_ERR_FS_NOT_FOUND |
|| err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND |
|
|| err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES) | || err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES) |
svn_error_clear(err); | svn_error_clear(err); |
else | else |
|
|
### consistent in the error it returns(?) | ### consistent in the error it returns(?) |
*/ | */ |
if (err->apr_err == SVN_ERR_FS_NOT_FOUND | if (err->apr_err == SVN_ERR_FS_NOT_FOUND |
|| err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND |
|
|| err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES) | || err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES) |
svn_error_clear(err); | svn_error_clear(err); |
else | else |
|
|
_("File '%s' already exists"), | _("File '%s' already exists"), |
file->rsrc->url); | file->rsrc->url); |
} | } |
else if (err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND) |
else if (err->apr_err == SVN_ERR_FS_NOT_FOUND) |
{ | { |
svn_error_clear(err); | svn_error_clear(err); |
} | } |
|
|
| |
svn_pool_destroy(baton.scratchpool); | svn_pool_destroy(baton.scratchpool); |
| |
if (err && err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND) |
if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND) |
{ | { |
svn_error_clear(err); | svn_error_clear(err); |
*locks = baton.lock_hash; | *locks = baton.lock_hash; |
|
|
if (value == NULL) | if (value == NULL) |
{ | { |
/* ### need an SVN_ERR here */ | /* ### need an SVN_ERR here */ |
return svn_error_createf(SVN_ERR_RA_DAV_PROPS_NOT_FOUND, NULL, |
return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL, |
_("'%s' was not present on the resource"), | _("'%s' was not present on the resource"), |
name); | name); |
} | } |
|
|
if (! err) | if (! err) |
break; /* found an existing parent! */ | break; /* found an existing parent! */ |
| |
if (err->apr_err != SVN_ERR_RA_DAV_PATH_NOT_FOUND) |
if (err->apr_err != SVN_ERR_FS_NOT_FOUND) |
return err; /* found a _real_ error */ | return err; /* found a _real_ error */ |
| |
/* else... lop off the basename and try again. */ | /* else... lop off the basename and try again. */ |
|
|
else | else |
*kind = svn_node_file; | *kind = svn_node_file; |
} | } |
else if (err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND) |
else if (err->apr_err == SVN_ERR_FS_NOT_FOUND) |
{ | { |
| |
svn_error_clear(err); | svn_error_clear(err); |
|
|
url, revision, pool); | url, revision, pool); |
if (err) | if (err) |
{ | { |
if (err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND) |
if (err->apr_err == SVN_ERR_FS_NOT_FOUND) |
{ | { |
/* easy out: */ | /* easy out: */ |
svn_error_clear(err); | svn_error_clear(err); |
|
|
NULL, NULL /* all props */, pool); | NULL, NULL /* all props */, pool); |
if (err) | if (err) |
{ | { |
if (err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND) |
if (err->apr_err == SVN_ERR_FS_NOT_FOUND) |
{ | { |
/* easy out: */ | /* easy out: */ |
svn_error_clear(err); | svn_error_clear(err); |
|
|
svn_error_clear(err); | svn_error_clear(err); |
cap_result = capability_no; | cap_result = capability_no; |
} | } |
else if (err->apr_err == SVN_ERR_FS_NOT_FOUND |
else if (err->apr_err == SVN_ERR_FS_NOT_FOUND) |
|| err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND) |
|
{ | { |
/* Mergeinfo requests use relative paths, and | /* Mergeinfo requests use relative paths, and |
anyway we're in r0, so this is a likely error, | anyway we're in r0, so this is a likely error, |
|
|
switch (req->code) | switch (req->code) |
{ | { |
case 404: | case 404: |
return svn_error_create(SVN_ERR_RA_DAV_PATH_NOT_FOUND, NULL, |
return svn_error_create(SVN_ERR_FS_NOT_FOUND, NULL, |
apr_psprintf(pool, _("'%s' path not found"), | apr_psprintf(pool, _("'%s' path not found"), |
req->url)); | req->url)); |
| |
|
|
svn_ra_serf__handler_t *handler; | svn_ra_serf__handler_t *handler; |
svn_ra_serf__xml_parser_t *parser_ctx; | svn_ra_serf__xml_parser_t *parser_ctx; |
serf_bucket_t *buckets, *tmp; | serf_bucket_t *buckets, *tmp; |
apr_hash_t *props; |
|
const char *lopped_path, *remaining_path; |
|
const char *vcc_url, *relative_url, *baseline_url, *basecoll_url, *req_url; | const char *vcc_url, *relative_url, *baseline_url, *basecoll_url, *req_url; |
int status_code; | int status_code; |
svn_error_t *err; | svn_error_t *err; |
|
|
session->bkt_alloc); | session->bkt_alloc); |
serf_bucket_aggregate_append(buckets, tmp); | serf_bucket_aggregate_append(buckets, tmp); |
| |
props = apr_hash_make(pool); |
|
|
|
/* Get the VCC from file url, or if the file doesn't exist in HEAD, from | /* Get the VCC from file url, or if the file doesn't exist in HEAD, from |
its closest existing parent. */ | its closest existing parent. */ |
SVN_ERR(svn_ra_serf__search_for_base_props(props, &remaining_path, |
SVN_ERR(svn_ra_serf__discover_root(&vcc_url, |
&lopped_path, |
&relative_url, |
session, session->conns[0], |
session, session->conns[0], |
session->repos_url.path, pool)); |
session->repos_url.path, pool)); |
vcc_url = svn_ra_serf__get_prop(props, remaining_path, |
|
"DAV:", "version-controlled-configuration"); |
|
|
|
if (!vcc_url) |
|
{ |
|
return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL, |
|
_("The OPTIONS response did not include the " |
|
"requested version-controlled-configuration " |
|
"value")); |
|
} |
|
|
|
/* Send the request to the baseline URL */ |
|
relative_url = svn_ra_serf__get_prop(props, remaining_path, |
|
SVN_DAV_PROP_NS_DAV, |
|
"baseline-relative-path"); |
|
if (!relative_url) |
|
{ |
|
return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL, |
|
_("The OPTIONS response did not include the " |
|
"requested baseline-relative-path value")); |
|
} |
|
relative_url = svn_path_join(relative_url, |
|
svn_path_uri_decode(lopped_path, pool), |
|
pool); |
|
| |
if (end == SVN_INVALID_REVNUM) | if (end == SVN_INVALID_REVNUM) |
{ | { |
|
apr_hash_t *props = apr_hash_make(pool); |
|
|
/* Use the "checked-in" property to determine the baseline url of the HEAD | /* Use the "checked-in" property to determine the baseline url of the HEAD |
revision. */ | revision. */ |
SVN_ERR(svn_ra_serf__retrieve_props(props, session, session->conns[0], | SVN_ERR(svn_ra_serf__retrieve_props(props, session, session->conns[0], |
|
|
} | } |
else | else |
{ | { |
|
apr_hash_t *props = apr_hash_make(pool); |
|
|
/* We're asking for a specific revision. No need to use "checked-in" | /* We're asking for a specific revision. No need to use "checked-in" |
here, request the baseline-collection property with the specified | here, request the baseline-collection property with the specified |
revision in the 'Label' header (added in svn_ra_serf__retrieve_props). | revision in the 'Label' header (added in svn_ra_serf__retrieve_props). |
|
|
SVN_ERR(parser_ctx->error); | SVN_ERR(parser_ctx->error); |
} | } |
| |
if (status_code == 404) |
SVN_ERR(svn_ra_serf__error_on_status(status_code, handler->path)); |
{ |
|
return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, NULL, |
|
"'%s' path not found", |
|
handler->path); |
|
} |
|
return err; | return err; |
} | } |
|
|
| |
if (checkout_ctx->progress.status != 201) | if (checkout_ctx->progress.status != 201) |
{ | { |
if (checkout_ctx->progress.status == 404) |
SVN_ERR(svn_ra_serf__error_on_status(checkout_ctx->progress.status, |
{ |
dir->name)); |
return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, |
|
return_response_err(handler, |
|
&checkout_ctx->progress), |
|
_("Path '%s' not present"), |
|
dir->name); |
|
} |
|
| |
return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, |
return svn_error_createf(SVN_ERR_FS_CONFLICT, |
return_response_err(handler, | return_response_err(handler, |
&checkout_ctx->progress), | &checkout_ctx->progress), |
_("Directory '%s' is out of date; try updating"), | _("Directory '%s' is out of date; try updating"), |
|
|
| |
SVN_ERR(svn_ra_serf__wait_for_props(propfind_ctx, session, pool)); | SVN_ERR(svn_ra_serf__wait_for_props(propfind_ctx, session, pool)); |
| |
|
/* We wouldn't get here if the url wasn't found (404), so the checked-in |
|
property should have been set. */ |
root_checkout = | root_checkout = |
svn_ra_serf__get_ver_prop(props, session->repos_url.path, | svn_ra_serf__get_ver_prop(props, session->repos_url.path, |
base_revision, "DAV:", "checked-in"); | base_revision, "DAV:", "checked-in"); |
| |
if (!root_checkout) | if (!root_checkout) |
return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, NULL, |
return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL, |
_("Path '%s' not present"), | _("Path '%s' not present"), |
session->repos_url.path); | session->repos_url.path); |
} | } |
|
|
| |
if (file->checkout->progress.status != 201) | if (file->checkout->progress.status != 201) |
{ | { |
if (file->checkout->progress.status == 404) |
SVN_ERR(svn_ra_serf__error_on_status(file->checkout->progress.status, |
{ |
file->name)); |
return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, |
|
return_response_err(handler, |
|
&file->checkout->progress), |
|
_("Path '%s' not present"), |
|
file->name); |
|
} |
|
| |
return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, |
return svn_error_createf(SVN_ERR_FS_CONFLICT, |
return_response_err(handler, | return_response_err(handler, |
&file->checkout->progress), | &file->checkout->progress), |
_("File '%s' is out of date; try updating"), | _("File '%s' is out of date; try updating"), |
|
|
SVN_ERR(parser_ctx->error); | SVN_ERR(parser_ctx->error); |
} | } |
| |
if (loc_ctx->status_code == 404) |
SVN_ERR(svn_ra_serf__error_on_status(loc_ctx->status_code, req_url)); |
{ |
|
return svn_error_create(SVN_ERR_RA_DAV_PATH_NOT_FOUND, NULL, |
|
apr_psprintf(pool, _("'%s' path not found"), |
|
req_url)); |
|
} |
|
| |
return err; | return err; |
} | } |
|
|
} | } |
| |
if (gls_ctx->inside_report) | if (gls_ctx->inside_report) |
|
|
err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL, | err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL, |
_("Location segment report failed on '%s'@'%ld'"), | _("Location segment report failed on '%s'@'%ld'"), |
path, peg_revision); | path, peg_revision); |
| |
if (gls_ctx->status_code == 404) |
SVN_ERR(svn_ra_serf__error_on_status(gls_ctx->status_code, handler->path)); |
{ |
|
return svn_error_create(SVN_ERR_RA_DAV_PATH_NOT_FOUND, NULL, |
|
apr_psprintf(pool, _("'%s' path not found"), |
|
req_url)); |
|
} |
|
| |
svn_pool_destroy(gls_ctx->subpool); | svn_pool_destroy(gls_ctx->subpool); |
| |
|
|
svn_boolean_t include_descendants, | svn_boolean_t include_descendants, |
apr_pool_t *pool) | apr_pool_t *pool) |
{ | { |
svn_error_t *err; |
svn_error_t *err, *err2; |
int status_code; | int status_code; |
| |
mergeinfo_context_t *mergeinfo_ctx; | mergeinfo_context_t *mergeinfo_ctx; |
|
|
| |
err = svn_ra_serf__context_run_wait(&mergeinfo_ctx->done, session, pool); | err = svn_ra_serf__context_run_wait(&mergeinfo_ctx->done, session, pool); |
| |
if (status_code == 404) |
err2 = svn_ra_serf__error_on_status(status_code, handler->path); |
|
|
|
if (err2) |
{ | { |
svn_error_clear(err); | svn_error_clear(err); |
return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, NULL, |
SVN_ERR(err2); |
_("'%s' path not found"), handler->path); |
} |
} |
|
| |
if (parser_ctx->error) | if (parser_ctx->error) |
{ | { |
|
|
else | else |
SVN_ERR(err); | SVN_ERR(err); |
| |
if (status_code == 404) |
|
{ |
|
return svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, NULL, |
|
_("'%s' path not found"), handler->path); |
|
} |
|
|
|
if (mergeinfo_ctx->done) | if (mergeinfo_ctx->done) |
*catalog = mergeinfo_ctx->result_catalog; | *catalog = mergeinfo_ctx->result_catalog; |
| |
|
|
svn_error_clear(err); | svn_error_clear(err); |
SVN_ERR(prop_ctx->parser_ctx->error); | SVN_ERR(prop_ctx->parser_ctx->error); |
} | } |
|
|
|
SVN_ERR(svn_ra_serf__error_on_status(prop_ctx->status_code, prop_ctx->path)); |
|
|
return err; | return err; |
} | } |
| |
|
|
return SVN_NO_ERROR; | return SVN_NO_ERROR; |
} | } |
| |
svn_error_t * |
|
svn_ra_serf__search_for_base_props(apr_hash_t *props, |
|
const char **remaining_path, |
|
const char **missing_path, |
|
svn_ra_serf__session_t *session, |
|
svn_ra_serf__connection_t *conn, |
|
const char *url, |
|
apr_pool_t *pool) |
|
{ |
|
const char *path = url, *present_path = ""; |
|
const char *vcc_url; |
|
|
|
do |
|
{ |
|
SVN_ERR(svn_ra_serf__retrieve_props(props, session, conn, |
|
path, SVN_INVALID_REVNUM, |
|
"0", base_props, pool)); |
|
vcc_url = |
|
svn_ra_serf__get_ver_prop(props, path, |
|
SVN_INVALID_REVNUM, |
|
"DAV:", |
|
"version-controlled-configuration"); |
|
if (vcc_url) |
|
break; |
|
|
|
/* This happens when the file is missing in HEAD. */ |
|
|
|
/* Okay, strip off. */ |
|
present_path = svn_path_join(svn_path_basename(path, pool), |
|
present_path, pool); |
|
path = svn_path_dirname(path, pool); |
|
} |
|
while (!svn_path_is_empty(path)); |
|
|
|
/* Error out if entire URL was bogus (not a single part of it exists |
|
in the repository!) */ |
|
if (svn_path_is_empty(path)) |
|
return svn_error_createf(SVN_ERR_RA_ILLEGAL_URL, NULL, |
|
_("No part of path '%s' was found in " |
|
"repository HEAD"), url); |
|
|
|
*missing_path = present_path; |
|
*remaining_path = path; |
|
|
|
return SVN_NO_ERROR; |
|
} |
|
|
|
void | void |
svn_ra_serf__walk_all_props(apr_hash_t *props, | svn_ra_serf__walk_all_props(apr_hash_t *props, |
const char *name, | const char *name, |
|
|
/* SSL server certificates */ | /* SSL server certificates */ |
svn_boolean_t trust_default_ca; | svn_boolean_t trust_default_ca; |
const char *ssl_authorities; | const char *ssl_authorities; |
|
|
|
/* Repository UUID */ |
|
const char *uuid; |
}; | }; |
| |
/* | /* |
|
|
svn_ra_serf__session_t *sess, | svn_ra_serf__session_t *sess, |
apr_pool_t *pool); | apr_pool_t *pool); |
| |
/* Shared helper func: given a public URL which may not exist in HEAD, |
|
use SESSION to search up parent directories until we can retrieve a |
|
*PROPS (allocated in POOL) containing a standard set of base props: |
|
{VCC, resourcetype, baseline-relative-path}. |
|
|
|
Also return: |
|
*MISSING_PATH (allocated in POOL), which is the trailing portion of |
|
the URL that did not exist. If an error occurs, *MISSING_PATH isn't |
|
changed. |
|
*REMAINING_PATH (allocated in POOL), which is the parent path on which |
|
we found the PROPS. |
|
*/ |
|
svn_error_t * |
|
svn_ra_serf__search_for_base_props(apr_hash_t *props, |
|
const char **remaining_path, |
|
const char **missing_path, |
|
svn_ra_serf__session_t *session, |
|
svn_ra_serf__connection_t *conn, |
|
const char *url, |
|
apr_pool_t *pool); |
|
|
|
/* | /* |
* This is a blocking version of deliver_props. | * This is a blocking version of deliver_props. |
*/ | */ |
|
|
const char *path, | const char *path, |
apr_pool_t *pool); | apr_pool_t *pool); |
| |
/* Try to discover our current root @a vcc_url and the resultant @a rel_path |
/* Try to discover our current root @a VCC_URL and the resultant @a REL_PATH |
* based on @a orig_path for the @a session on @a conn. |
* based on @a ORIG_PATH for the @a SESSION on @a CONN. |
|
* REL_PATH will be URI decoded. |
* | * |
* @a rel_path may be NULL if the caller is not interested in the relative |
* @a REL_PATH may be NULL if the caller is not interested in the relative |
* path. | * path. |
* | * |
* All temporary allocations will be made in @a pool. |
* All temporary allocations will be made in @a POOL. |
*/ | */ |
svn_error_t * | svn_error_t * |
svn_ra_serf__discover_root(const char **vcc_url, | svn_ra_serf__discover_root(const char **vcc_url, |
|
|
| |
/* Set *BC_URL to the baseline collection url, and set *BC_RELATIVE to | /* Set *BC_URL to the baseline collection url, and set *BC_RELATIVE to |
* the path relative to that url for URL in REVISION using SESSION. | * the path relative to that url for URL in REVISION using SESSION. |
|
* BC_RELATIVE will be URI decoded. |
|
* |
* REVISION may be SVN_INVALID_REVNUM (to mean "the current HEAD | * REVISION may be SVN_INVALID_REVNUM (to mean "the current HEAD |
* revision"). If URL is NULL, use SESSION's session url. | * revision"). If URL is NULL, use SESSION's session url. |
* Use POOL for all allocations. | * Use POOL for all allocations. |
|
|
const char *capability, | const char *capability, |
apr_pool_t *pool); | apr_pool_t *pool); |
| |
|
|
/*** Authentication handler declarations ***/ | /*** Authentication handler declarations ***/ |
| |
/** | /** |
|
|
apr_size_t data_len, | apr_size_t data_len, |
apr_pool_t *pool); | apr_pool_t *pool); |
| |
|
|
|
/*** General utility functions ***/ |
|
|
|
/** |
|
* Convert an HTTP status code resulting from a WebDAV request to the relevant |
|
* error code. |
|
*/ |
|
svn_error_t * |
|
svn_ra_serf__error_on_status(int status_code, const char *path); |
|
|
|
|
#endif /* SVN_LIBSVN_RA_SERF_RA_SERF_H */ | #endif /* SVN_LIBSVN_RA_SERF_RA_SERF_H */ |
|
|
svn_error_clear(err); | svn_error_clear(err); |
cap_result = capability_no; | cap_result = capability_no; |
} | } |
else if (err->apr_err == SVN_ERR_FS_NOT_FOUND |
else if (err->apr_err == SVN_ERR_FS_NOT_FOUND) |
|| err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND) |
|
{ | { |
/* Mergeinfo requests use relative paths, and | /* Mergeinfo requests use relative paths, and |
anyway we're in r0, so this is a likely error, | anyway we're in r0, so this is a likely error, |
|
|
const char *path, *res_type; | const char *path, *res_type; |
svn_revnum_t fetched_rev; | svn_revnum_t fetched_rev; |
| |
SVN_ERR(fetch_path_props(&prop_ctx, &props, &path, &fetched_rev, |
svn_error_t *err = fetch_path_props(&prop_ctx, &props, &path, &fetched_rev, |
session, rel_path, |
session, rel_path, |
revision, check_path_props, pool)); |
revision, check_path_props, pool); |
| |
if (prop_ctx && (svn_ra_serf__propfind_status_code(prop_ctx) == 404)) |
if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND) |
{ | { |
|
svn_error_clear(err); |
*kind = svn_node_none; | *kind = svn_node_none; |
} | } |
else | else |
{ | { |
|
/* Any other error, raise to caller. */ |
|
if (err) |
|
return err; |
|
|
res_type = svn_ra_serf__get_ver_prop(props, path, fetched_rev, | res_type = svn_ra_serf__get_ver_prop(props, path, fetched_rev, |
"DAV:", "resourcetype"); | "DAV:", "resourcetype"); |
if (!res_type) | if (!res_type) |
|
|
const char *path; | const char *path; |
svn_revnum_t fetched_rev; | svn_revnum_t fetched_rev; |
svn_dirent_t *entry; | svn_dirent_t *entry; |
|
svn_error_t *err; |
| |
SVN_ERR(fetch_path_props(&prop_ctx, &props, &path, &fetched_rev, |
err = fetch_path_props(&prop_ctx, &props, &path, &fetched_rev, |
session, rel_path, revision, all_props, pool)); |
session, rel_path, revision, all_props, pool); |
|
if (err) |
|
{ |
|
if (err->apr_err == SVN_ERR_FS_NOT_FOUND) |
|
{ |
|
svn_error_clear(err); |
|
*dirent = NULL; |
|
return SVN_NO_ERROR; |
|
} |
|
else |
|
return err; |
|
} |
| |
entry = apr_pcalloc(pool, sizeof(*entry)); | entry = apr_pcalloc(pool, sizeof(*entry)); |
| |
|
|
| |
path = session->repos_url.path; | path = session->repos_url.path; |
| |
/* If we have a relative path, append it. */ |
/* If we have a relative path, URI encode and append it. */ |
if (rel_path) | if (rel_path) |
{ | { |
path = svn_path_url_add_component(path, rel_path, pool); | path = svn_path_url_add_component(path, rel_path, pool); |
|
|
return SVN_NO_ERROR; | return SVN_NO_ERROR; |
} | } |
| |
|
/* TODO: to fetch the uuid from the repository, we need: |
|
1. a path that exists in HEAD |
|
2. a path that's readable |
|
|
|
get_uuid handles the case where a path doesn't exist in HEAD and also the |
|
case where the root of the repository is not readable. |
|
However, it does not handle the case where we're fetching path not existing |
|
in HEAD of a repository with unreadable root directory. |
|
*/ |
static svn_error_t * | static svn_error_t * |
svn_ra_serf__get_uuid(svn_ra_session_t *ra_session, | svn_ra_serf__get_uuid(svn_ra_session_t *ra_session, |
const char **uuid, | const char **uuid, |
|
|
| |
props = apr_hash_make(pool); | props = apr_hash_make(pool); |
| |
SVN_ERR(svn_ra_serf__retrieve_props(props, session, session->conns[0], |
if (!session->uuid) |
session->repos_url_str, |
{ |
SVN_INVALID_REVNUM, "0", uuid_props, |
const char *vcc_url, *relative_url; |
pool)); |
|
*uuid = svn_ra_serf__get_prop(props, session->repos_url_str, |
/* We're not interested in vcc_url and relative_url, but this call also |
SVN_DAV_PROP_NS_DAV, "repository-uuid"); |
stores the repository's uuid in the session. */ |
|
SVN_ERR(svn_ra_serf__discover_root(&vcc_url, |
if (!*uuid) |
&relative_url, |
{ |
session, session->conns[0], |
return svn_error_create(APR_EGENERAL, NULL, |
session->repos_url.path, pool)); |
_("The UUID property was not found on the " |
if (!session->uuid) |
"resource or any of its parents")); |
{ |
|
return svn_error_create(APR_EGENERAL, NULL, |
|
_("The UUID property was not found on the " |
|
"resource or any of its parents")); |
|
} |
} | } |
|
|
|
*uuid = session->uuid; |
| |
return SVN_NO_ERROR; | return SVN_NO_ERROR; |
} | } |
|
|
serf_bucket_response_status(response, &sl); | serf_bucket_response_status(response, &sl); |
| |
/* Woo-hoo. Nothing here to see. */ | /* Woo-hoo. Nothing here to see. */ |
if (sl.code == 404) |
fetch_ctx->err = svn_ra_serf__error_on_status(sl.code, fetch_ctx->info->name); |
|
if (fetch_ctx->err) |
{ | { |
fetch_ctx->done = TRUE; | fetch_ctx->done = TRUE; |
fetch_ctx->err = svn_error_createf(SVN_ERR_RA_DAV_PATH_NOT_FOUND, NULL, |
|
"'%s' path not found", |
|
fetch_ctx->info->name); |
|
return svn_ra_serf__handle_discard_body(request, response, NULL, pool); | return svn_ra_serf__handle_discard_body(request, response, NULL, pool); |
} | } |
| |
|
|
apr_pool_t *pool) | apr_pool_t *pool) |
{ | { |
apr_hash_t *props; | apr_hash_t *props; |
const char *path, *relative_path, *present_path = ""; |
const char *path, *relative_path, *present_path = "", *uuid; |
| |
/* If we're only interested in our VCC, just return it. */ | /* If we're only interested in our VCC, just return it. */ |
if (session->vcc_url && !rel_path) | if (session->vcc_url && !rel_path) |
|
|
props = apr_hash_make(pool); | props = apr_hash_make(pool); |
path = orig_path; | path = orig_path; |
*vcc_url = NULL; | *vcc_url = NULL; |
|
uuid = NULL; |
| |
do | do |
{ | { |
SVN_ERR(svn_ra_serf__retrieve_props(props, session, conn, |
svn_error_t *err = svn_ra_serf__retrieve_props(props, session, conn, |
path, SVN_INVALID_REVNUM, |
path, SVN_INVALID_REVNUM, |
"0", base_props, pool)); |
"0", base_props, pool); |
*vcc_url = |
if (! err) |
svn_ra_serf__get_ver_prop(props, path, |
|
SVN_INVALID_REVNUM, |
|
"DAV:", |
|
"version-controlled-configuration"); |
|
|
|
if (*vcc_url) |
|
{ | { |
|
*vcc_url = |
|
svn_ra_serf__get_ver_prop(props, path, |
|
SVN_INVALID_REVNUM, |
|
"DAV:", |
|
"version-controlled-configuration"); |
|
|
relative_path = svn_ra_serf__get_ver_prop(props, path, | relative_path = svn_ra_serf__get_ver_prop(props, path, |
SVN_INVALID_REVNUM, | SVN_INVALID_REVNUM, |
SVN_DAV_PROP_NS_DAV, | SVN_DAV_PROP_NS_DAV, |
"baseline-relative-path"); | "baseline-relative-path"); |
|
|
|
uuid = svn_ra_serf__get_ver_prop(props, path, |
|
SVN_INVALID_REVNUM, |
|
SVN_DAV_PROP_NS_DAV, |
|
"repository-uuid"); |
break; | break; |
} | } |
|
else |
/* This happens when the file is missing in HEAD. */ |
{ |
|
if (err->apr_err != SVN_ERR_FS_NOT_FOUND) |
/* Okay, strip off. */ |
{ |
present_path = svn_path_join(svn_path_basename(path, pool), |
return err; /* found a _real_ error */ |
present_path, pool); |
} |
path = svn_path_dirname(path, pool); |
else |
|
{ |
|
/* This happens when the file is missing in HEAD. */ |
|
svn_error_clear(err); |
|
|
|
/* Okay, strip off. */ |
|
present_path = svn_path_join(svn_path_basename(path, pool), |
|
present_path, pool); |
|
path = svn_path_dirname(path, pool); |
|
} |
|
} |
} | } |
while (!svn_path_is_empty(path)); | while (!svn_path_is_empty(path)); |
| |
|
|
session->pool); | session->pool); |
} | } |
| |
|
/* Store the repository UUID in the cache. */ |
|
if (!session->uuid) |
|
{ |
|
session->uuid = apr_pstrdup(session->pool, uuid); |
|
} |
|
|
if (rel_path) | if (rel_path) |
{ | { |
if (present_path[0] != '\0') | if (present_path[0] != '\0') |
{ | { |
*rel_path = svn_path_url_add_component(relative_path, |
/* The relative path is supposed to be URI decoded, so decode |
present_path, pool); |
present_path before joining both together. */ |
|
*rel_path = svn_path_join(relative_path, |
|
svn_path_uri_decode(present_path, pool), |
|
pool); |
} | } |
else | else |
{ | { |
|
|
| |
return SVN_NO_ERROR; | return SVN_NO_ERROR; |
} | } |
|
|
|
svn_error_t * |
|
svn_ra_serf__error_on_status(int status_code, const char *path) |
|
{ |
|
switch(status_code) |
|
{ |
|
case 404: |
|
return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL, |
|
_("'%s' path not found"), path); |
|
} |
|
|
|
return SVN_NO_ERROR; |
|
} |
|
|
else if (!(opt_state->parents) && | else if (!(opt_state->parents) && |
(APR_STATUS_IS_ENOENT(err->apr_err) || /* in wc */ | (APR_STATUS_IS_ENOENT(err->apr_err) || /* in wc */ |
err->apr_err == SVN_ERR_FS_NOT_DIRECTORY || | err->apr_err == SVN_ERR_FS_NOT_DIRECTORY || |
err->apr_err == SVN_ERR_FS_NOT_FOUND || /* ra_local and ra_svn */ |
err->apr_err == SVN_ERR_FS_NOT_FOUND /* all ra layers */)) |
err->apr_err == SVN_ERR_RA_DAV_PATH_NOT_FOUND /* ra_neon */)) |
|
return svn_error_quick_wrap | return svn_error_quick_wrap |
(err, _("Try 'svn mkdir --parents' instead?")); | (err, _("Try 'svn mkdir --parents' instead?")); |
else | else |