📄 repos.c
字号:
r->uri = apr_pstrdup(r->pool, uri);
/* parse the uri and prep the associated resource. */
derr = dav_svn_get_resource(r, root_path,
/* ### I can't believe that every single
parser ignores the LABEL and USE_CHECKED_IN
args below!! */
"ignored_label", 1,
&resource);
/* Restore r back to normal. */
r->uri = saved_uri;
if (derr)
return derr;
if (resource->type == DAV_RESOURCE_TYPE_REGULAR)
{
/* Either a public URI or a bc. In both cases, prep_regular()
has already set the 'exists' and 'collection' flags by
querying the appropriate revision root and path. */
if (! resource->exists)
*kind = svn_node_none;
else
*kind = resource->collection ? svn_node_dir : svn_node_file;
}
else if (resource->type == DAV_RESOURCE_TYPE_VERSION)
{
if (resource->baselined) /* bln */
*kind = svn_node_unknown;
else /* ver */
{
serr = svn_fs_check_path (kind, resource->info->root.root,
resource->info->repos_path, r->pool);
if (serr)
return dav_svn_convert_err
(serr, HTTP_INTERNAL_SERVER_ERROR,
apr_psprintf(r->pool,
"Error checking kind of path '%s' in repository",
resource->info->repos_path),
r->pool);
}
}
else if (resource->type == DAV_RESOURCE_TYPE_WORKING)
{
if (resource->baselined) /* wbl */
*kind = svn_node_unknown;
else /* wrk */
{
/* don't call fs_check_path on the txn, but on the original
revision that the txn is based on. */
base_rev = svn_fs_txn_base_revision (resource->info->root.txn);
serr = svn_fs_revision_root (&base_rev_root,
resource->info->repos->fs,
base_rev, r->pool);
if (serr)
return dav_svn_convert_err
(serr, HTTP_INTERNAL_SERVER_ERROR,
apr_psprintf(r->pool,
"Could not open root of revision %ld",
base_rev),
r->pool);
serr = svn_fs_check_path (kind, base_rev_root,
resource->info->repos_path, r->pool);
if (serr)
return dav_svn_convert_err
(serr, HTTP_INTERNAL_SERVER_ERROR,
apr_psprintf(r->pool,
"Error checking kind of path '%s' in repository",
resource->info->repos_path),
r->pool);
}
}
else
/* act, his, vcc, or some other private resource */
*kind = svn_node_unknown;
return NULL;
}
static dav_error * dav_svn_open_stream(const dav_resource *resource,
dav_stream_mode mode,
dav_stream **stream)
{
svn_error_t *serr;
if (mode == DAV_MODE_WRITE_TRUNC || mode == DAV_MODE_WRITE_SEEKABLE)
{
if (resource->type != DAV_RESOURCE_TYPE_WORKING)
{
return dav_new_error(resource->pool, HTTP_METHOD_NOT_ALLOWED, 0,
"Resource body changes may only be made to "
"working resources [at this time].");
}
}
#if 1
if (mode == DAV_MODE_WRITE_SEEKABLE)
{
return dav_new_error(resource->pool, HTTP_NOT_IMPLEMENTED, 0,
"Resource body writes cannot use ranges "
"[at this time].");
}
#endif
/* start building the stream structure */
*stream = apr_pcalloc(resource->pool, sizeof(**stream));
(*stream)->res = resource;
/* note: when writing, we don't need to use DAV_SVN_REPOS_PATH since
we cannot write into an "id root". Partly because the FS may not
let us, but mostly that we have an id root only to deal with Version
Resources, and those are read only. */
serr = svn_fs_apply_textdelta(&(*stream)->delta_handler,
&(*stream)->delta_baton,
resource->info->root.root,
resource->info->repos_path,
resource->info->base_checksum,
resource->info->result_checksum,
resource->pool);
if (serr != NULL && serr->apr_err == SVN_ERR_FS_NOT_FOUND)
{
svn_error_clear(serr);
serr = svn_fs_make_file(resource->info->root.root,
resource->info->repos_path,
resource->pool);
if (serr != NULL)
{
return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"Could not create file within the "
"repository.",
resource->pool);
}
serr = svn_fs_apply_textdelta(&(*stream)->delta_handler,
&(*stream)->delta_baton,
resource->info->root.root,
resource->info->repos_path,
resource->info->base_checksum,
resource->info->result_checksum,
resource->pool);
}
if (serr != NULL)
{
return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"Could not prepare to write the file",
resource->pool);
}
/* if the incoming data is an SVNDIFF, then create a stream that
will process the data into windows and invoke the FS window handler
when a window is ready. */
/* ### we need a better way to check the content-type! this is bogus
### because we're effectively looking at the request_rec. doubly
### bogus because this means you cannot open arbitrary streams and
### feed them content (the type is always tied to a request_rec).
### probably ought to pass the type to open_stream */
if (resource->info->is_svndiff)
{
(*stream)->wstream =
svn_txdelta_parse_svndiff((*stream)->delta_handler,
(*stream)->delta_baton,
TRUE,
resource->pool);
}
return NULL;
}
static dav_error * dav_svn_close_stream(dav_stream *stream, int commit)
{
svn_error_t *serr;
apr_pool_t *pool = stream->res->pool;
if (stream->rstream != NULL)
{
serr = svn_stream_close(stream->rstream);
if (serr)
return dav_svn_convert_err
(serr, HTTP_INTERNAL_SERVER_ERROR,
"dav_svn_close_stream: error closing read stream",
pool);
}
/* if we have a write-stream, then closing it also takes care of the
handler (so make sure not to send a NULL to it, too) */
if (stream->wstream != NULL)
{
serr = svn_stream_close(stream->wstream);
if (serr)
return dav_svn_convert_err
(serr, HTTP_INTERNAL_SERVER_ERROR,
"dav_svn_close_stream: error closing write stream",
pool);
}
else if (stream->delta_handler != NULL)
{
serr = (*stream->delta_handler)(NULL, stream->delta_baton);
if (serr)
return dav_svn_convert_err
(serr, HTTP_INTERNAL_SERVER_ERROR,
"dav_svn_close_stream: error sending final (null) delta window",
pool);
}
return NULL;
}
static dav_error * dav_svn_write_stream(dav_stream *stream, const void *buf,
apr_size_t bufsize)
{
svn_error_t *serr;
apr_pool_t *pool = stream->res->pool;
if (stream->wstream != NULL)
{
serr = svn_stream_write(stream->wstream, buf, &bufsize);
/* ### would the returned bufsize ever not match the requested amt? */
}
else
{
svn_txdelta_window_t window = { 0 };
svn_txdelta_op_t op;
svn_string_t data;
data.data = buf;
data.len = bufsize;
op.action_code = svn_txdelta_new;
op.offset = 0;
op.length = bufsize;
window.tview_len = bufsize; /* result will be this long */
window.num_ops = 1;
window.ops = &op;
window.new_data = &data;
serr = (*stream->delta_handler)(&window, stream->delta_baton);
}
if (serr)
{
return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
"could not write the file contents",
pool);
}
return NULL;
}
static dav_error * dav_svn_seek_stream(dav_stream *stream,
apr_off_t abs_position)
{
/* ### fill this in */
return dav_new_error(stream->res->pool, HTTP_NOT_IMPLEMENTED, 0,
"Resource body read/write cannot use ranges "
"[at this time].");
}
const char * dav_svn_getetag(const dav_resource *resource, apr_pool_t *pool)
{
svn_error_t *serr;
svn_revnum_t created_rev;
/* if the resource doesn't exist, isn't a simple REGULAR or VERSION
resource, or it is a Baseline, then it has no etag. */
/* ### we should assign etags to all resources at some point */
if (!resource->exists
|| (resource->type != DAV_RESOURCE_TYPE_REGULAR
&& resource->type != DAV_RESOURCE_TYPE_VERSION)
|| (resource->type == DAV_RESOURCE_TYPE_VERSION && resource->baselined))
return "";
/* ### what kind of etag to return for collections, activities, etc? */
if ((serr = svn_fs_node_created_rev(&created_rev, resource->info->root.root,
resource->info->repos_path,
pool)))
{
/* ### what to do? */
svn_error_clear(serr);
return "";
}
/* Use the "weak" format of the etag for collections because our GET
requests on collections include dynamic data (the HEAD revision,
the build version of Subversion, etc.). */
return apr_psprintf(pool, "%s\"%ld/%s\"",
resource->collection ? "W/" : "",
created_rev,
apr_xml_quote_string(pool,
resource->info->repos_path, 1));
}
/* Since dav_svn_getetag() takes a pool argument, this wrapper is for
the mod_dav hooks vtable entry, which does not. */
static const char * getetag_pathetic(const dav_resource *resource)
{
return dav_svn_getetag(resource, resource->pool);
}
static dav_error * dav_svn_set_headers(request_rec *r,
const dav_resource *resource)
{
svn_error_t *serr;
svn_filesize_t length;
const char *mimetype = NULL;
if (!resource->exists)
return NULL;
/* ### what to do for collections, activities, etc */
/* make sure the proper mtime is in the request record */
#if 0
ap_update_mtime(r, resource->info->finfo.mtime);
#endif
/* ### note that these use r->filename rather than <resource> */
#if 0
ap_set_last_modified(r);
#endif
/* generate our etag and place it into the output */
apr_table_setn(r->headers_out, "ETag",
dav_svn_getetag(resource, resource->pool));
/* we accept byte-ranges */
apr_table_setn(r->headers_out, "Accept-Ranges", "bytes");
/* For a directory, we will send text/html or text/xml. If we have a delta
base, then we will always be generating an svndiff. Otherwise,
we need to fetch the appropriate MIME type from the resource's
properties (and use text/plain if it isn't there). */
if (resource->collection)
{
if (resource->info->repos->xslt_uri)
mimetype = "text/xml";
else
mimetype = "text/html; charset=UTF-8";
}
else if (resource->info->delta_base != NULL)
{
dav_svn_uri_info info;
/* First order of business is to parse it. */
serr = dav_svn_simple_parse_uri(&info, resource,
resource->info->delta_base,
resource->pool);
/* If we successfully parse the base URL, then send an svndiff. */
if ((serr == NULL) && (info.rev != SVN_INVALID_REVNUM))
{
mimetype = SVN_SVNDIFF_MIME_TYPE;
}
svn_error_clear(serr);
}
if ((mimetype == NULL)
&& ((resource->type == DAV_RESOURCE_TYPE_VERSION)
|| (resource->type == DAV_RESOURCE_TYPE_REGULAR))
&& (resource->info->repos_path != NULL))
{
svn_string_t
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -