📄 repos.c
字号:
}
apr_file_close(inf);
apr_file_close(outf);
if (is_move && apr_file_remove(src, p) != APR_SUCCESS) {
dav_error *err;
int save_errno = errno; /* save the errno that got us here */
if (apr_file_remove(dst, p) != APR_SUCCESS) {
/* ### ACK. this creates an inconsistency. do more!? */
/* ### use something besides 500? */
/* Note that we use the latest errno */
return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
"Could not remove source or destination "
"file. Server is now in an inconsistent "
"state.");
}
/* ### use something besides 500? */
err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
"Could not remove source file after move. "
"Destination was removed to ensure consistency.");
err->save_errno = save_errno;
return err;
}
return NULL;
}
/* copy/move a file from within a state dir to another state dir */
/* ### need more buffers to replace the pool argument */
static dav_error * dav_fs_copymove_state(
int is_move,
apr_pool_t * p,
const char *src_dir, const char *src_file,
const char *dst_dir, const char *dst_file,
dav_buffer *pbuf)
{
apr_finfo_t src_finfo; /* finfo for source file */
apr_finfo_t dst_state_finfo; /* finfo for STATE directory */
apr_status_t rv;
const char *src;
const char *dst;
/* build the propset pathname for the source file */
src = apr_pstrcat(p, src_dir, "/" DAV_FS_STATE_DIR "/", src_file, NULL);
/* the source file doesn't exist */
rv = apr_stat(&src_finfo, src, APR_FINFO_NORM, p);
if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
return NULL;
}
/* build the pathname for the destination state dir */
dst = apr_pstrcat(p, dst_dir, "/" DAV_FS_STATE_DIR, NULL);
/* ### do we need to deal with the umask? */
/* ensure that it exists */
rv = apr_dir_make(dst, APR_OS_DEFAULT, p);
if (rv != APR_SUCCESS) {
if (!APR_STATUS_IS_EEXIST(rv)) {
/* ### use something besides 500? */
return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
"Could not create internal state directory");
}
}
/* get info about the state directory */
rv = apr_stat(&dst_state_finfo, dst, APR_FINFO_NORM, p);
if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
/* Ack! Where'd it go? */
/* ### use something besides 500? */
return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
"State directory disappeared");
}
/* The mkdir() may have failed because a *file* exists there already */
if (dst_state_finfo.filetype != APR_DIR) {
/* ### try to recover by deleting this file? (and mkdir again) */
/* ### use something besides 500? */
return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
"State directory is actually a file");
}
/* append the target file to the state directory pathname */
dst = apr_pstrcat(p, dst, "/", dst_file, NULL);
/* copy/move the file now */
if (is_move && src_finfo.device == dst_state_finfo.device) {
/* simple rename is possible since it is on the same device */
if (apr_file_rename(src, dst, p) != APR_SUCCESS) {
/* ### use something besides 500? */
return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
"Could not move state file.");
}
}
else
{
/* gotta copy (and delete) */
return dav_fs_copymove_file(is_move, p, src, dst, pbuf);
}
return NULL;
}
static dav_error *dav_fs_copymoveset(int is_move, apr_pool_t *p,
const dav_resource *src,
const dav_resource *dst,
dav_buffer *pbuf)
{
const char *src_dir;
const char *src_file;
const char *src_state1;
const char *src_state2;
const char *dst_dir;
const char *dst_file;
const char *dst_state1;
const char *dst_state2;
dav_error *err;
/* Get directory and filename for resources */
/* ### should test these result values... */
(void) dav_fs_dir_file_name(src, &src_dir, &src_file);
(void) dav_fs_dir_file_name(dst, &dst_dir, &dst_file);
/* Get the corresponding state files for each resource */
dav_dbm_get_statefiles(p, src_file, &src_state1, &src_state2);
dav_dbm_get_statefiles(p, dst_file, &dst_state1, &dst_state2);
#if DAV_DEBUG
if ((src_state2 != NULL && dst_state2 == NULL) ||
(src_state2 == NULL && dst_state2 != NULL)) {
return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
"DESIGN ERROR: dav_dbm_get_statefiles() "
"returned inconsistent results.");
}
#endif
err = dav_fs_copymove_state(is_move, p,
src_dir, src_state1,
dst_dir, dst_state1,
pbuf);
if (err == NULL && src_state2 != NULL) {
err = dav_fs_copymove_state(is_move, p,
src_dir, src_state2,
dst_dir, dst_state2,
pbuf);
if (err != NULL) {
/* ### CRAP. inconsistency. */
/* ### should perform some cleanup at the target if we still
### have the original files */
/* Change the error to reflect the bad server state. */
err->status = HTTP_INTERNAL_SERVER_ERROR;
err->desc =
"Could not fully copy/move the properties. "
"The server is now in an inconsistent state.";
}
}
return err;
}
static dav_error *dav_fs_deleteset(apr_pool_t *p, const dav_resource *resource)
{
const char *dirpath;
const char *fname;
const char *state1;
const char *state2;
const char *pathname;
apr_status_t status;
/* Get directory, filename, and state-file names for the resource */
/* ### should test this result value... */
(void) dav_fs_dir_file_name(resource, &dirpath, &fname);
dav_dbm_get_statefiles(p, fname, &state1, &state2);
/* build the propset pathname for the file */
pathname = apr_pstrcat(p,
dirpath,
"/" DAV_FS_STATE_DIR "/",
state1,
NULL);
/* note: we may get ENOENT if the state dir is not present */
if ((status = apr_file_remove(pathname, p)) != APR_SUCCESS
&& !APR_STATUS_IS_ENOENT(status)) {
return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
"Could not remove properties.");
}
if (state2 != NULL) {
/* build the propset pathname for the file */
pathname = apr_pstrcat(p,
dirpath,
"/" DAV_FS_STATE_DIR "/",
state2,
NULL);
if ((status = apr_file_remove(pathname, p)) != APR_SUCCESS
&& !APR_STATUS_IS_ENOENT(status)) {
/* ### CRAP. only removed half. */
return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
"Could not fully remove properties. "
"The server is now in an inconsistent "
"state.");
}
}
return NULL;
}
/* --------------------------------------------------------------------
**
** REPOSITORY HOOK FUNCTIONS
*/
static dav_error * dav_fs_get_resource(
request_rec *r,
const char *root_dir,
const char *label,
int use_checked_in,
dav_resource **result_resource)
{
dav_resource_private *ctx;
dav_resource *resource;
char *s;
char *filename;
apr_size_t len;
/* ### optimize this into a single allocation! */
/* Create private resource context descriptor */
ctx = apr_pcalloc(r->pool, sizeof(*ctx));
ctx->finfo = r->finfo;
/* ### this should go away */
ctx->pool = r->pool;
/* Preserve case on OSes which fold canonical filenames */
#if 0
/* ### not available in Apache 2.0 yet */
filename = r->case_preserved_filename;
#else
filename = r->filename;
#endif
/*
** If there is anything in the path_info, then this indicates that the
** entire path was not used to specify the file/dir. We want to append
** it onto the filename so that we get a "valid" pathname for null
** resources.
*/
s = apr_pstrcat(r->pool, filename, r->path_info, NULL);
/* make sure the pathname does not have a trailing "/" */
len = strlen(s);
if (len > 1 && s[len - 1] == '/') {
s[len - 1] = '\0';
}
ctx->pathname = s;
/* Create resource descriptor */
resource = apr_pcalloc(r->pool, sizeof(*resource));
resource->type = DAV_RESOURCE_TYPE_REGULAR;
resource->info = ctx;
resource->hooks = &dav_hooks_repository_fs;
resource->pool = r->pool;
/* make sure the URI does not have a trailing "/" */
len = strlen(r->uri);
if (len > 1 && r->uri[len - 1] == '/') {
s = apr_pstrdup(r->pool, r->uri);
s[len - 1] = '\0';
resource->uri = s;
}
else {
resource->uri = r->uri;
}
if (r->finfo.filetype != 0) {
resource->exists = 1;
resource->collection = r->finfo.filetype == APR_DIR;
/* unused info in the URL will indicate a null resource */
if (r->path_info != NULL && *r->path_info != '\0') {
if (resource->collection) {
/* only a trailing "/" is allowed */
if (*r->path_info != '/' || r->path_info[1] != '\0') {
/*
** This URL/filename represents a locknull resource or
** possibly a destination of a MOVE/COPY
*/
resource->exists = 0;
resource->collection = 0;
}
}
else
{
/*
** The base of the path refers to a file -- nothing should
** be in path_info. The resource is simply an error: it
** can't be a null or a locknull resource.
*/
return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
"The URL contains extraneous path "
"components. The resource could not "
"be identified.");
}
/* retain proper integrity across the structures */
if (!resource->exists) {
ctx->finfo.filetype = 0;
}
}
}
*result_resource = resource;
return NULL;
}
static dav_error * dav_fs_get_parent_resource(const dav_resource *resource,
dav_resource **result_parent)
{
dav_resource_private *ctx = resource->info;
dav_resource_private *parent_ctx;
dav_resource *parent_resource;
apr_status_t rv;
char *dirpath;
const char *testroot;
const char *testpath;
/* If we're at the root of the URL space, then there is no parent. */
if (strcmp(resource->uri, "/") == 0) {
*result_parent = NULL;
return NULL;
}
/* If given resource is root, then there is no parent.
* Unless we can retrieve the filepath root, this is
* intendend to fail. If we split the root and
* no path info remains, then we also fail.
*/
testpath = ctx->pathname;
rv = apr_filepath_root(&testroot, &testpath, 0, ctx->pool);
if ((rv != APR_SUCCESS && rv != APR_ERELATIVE)
|| !testpath || !*testpath) {
*result_parent = NULL;
return NULL;
}
/* ### optimize this into a single allocation! */
/* Create private resource context descriptor */
parent_ctx = apr_pcalloc(ctx->pool, sizeof(*parent_ctx));
/* ### this should go away */
parent_ctx->pool = ctx->pool;
dirpath = ap_make_dirstr_parent(ctx->pool, ctx->pathname);
if (strlen(dirpath) > 1 && dirpath[strlen(dirpath) - 1] == '/')
dirpath[strlen(dirpath) - 1] = '\0';
parent_ctx->pathname = dirpath;
parent_resource = apr_pcalloc(ctx->pool, sizeof(*parent_resource));
parent_resource->info = parent_ctx;
parent_resource->collection = 1;
parent_resource->hooks = &dav_hooks_repository_fs;
parent_resource->pool = resource->pool;
if (resource->uri != NULL) {
char *uri = ap_make_dirstr_parent(ctx->pool, resource->uri);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -