📄 repos.c
字号:
return NULL;}static dav_error * dav_fs_close_stream(dav_stream *stream, int commit){ apr_file_close(stream->f); if (!commit) { if (apr_file_remove(stream->pathname, stream->p) != APR_SUCCESS) { /* ### use a better description? */ return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, "There was a problem removing (rolling " "back) the resource " "when it was being closed."); } } return NULL;}static dav_error * dav_fs_read_stream(dav_stream *stream, void *buf, apr_size_t *bufsize){ if (apr_file_read(stream->f, buf, bufsize) != APR_SUCCESS) { /* ### use something besides 500? */ return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, "An error occurred while reading from a " "resource."); } return NULL;}static dav_error * dav_fs_write_stream(dav_stream *stream, const void *buf, apr_size_t bufsize){ apr_status_t status; status = apr_file_write_full(stream->f, buf, bufsize, NULL); if (status == APR_ENOSPC) { return dav_new_error(stream->p, HTTP_INSUFFICIENT_STORAGE, 0, "There is not enough storage to write to " "this resource."); } else if (status != APR_SUCCESS) { /* ### use something besides 500? */ return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, "An error occurred while writing to a " "resource."); } return NULL;}static dav_error * dav_fs_seek_stream(dav_stream *stream, apr_off_t abs_pos){ if (apr_file_seek(stream->f, APR_SET, &abs_pos) != APR_SUCCESS) { /* ### should check whether apr_file_seek set abs_pos was set to the * correct position? */ /* ### use something besides 500? */ return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not seek to specified position in the " "resource."); } return NULL;}static dav_error * dav_fs_set_headers(request_rec *r, const dav_resource *resource){ /* ### this function isn't really used since we have a get_pathname */#if DEBUG_GET_HANDLER if (!resource->exists) return NULL; /* make sure the proper mtime is in the request record */ ap_update_mtime(r, resource->info->finfo.mtime); /* ### note that these use r->filename rather than <resource> */ ap_set_last_modified(r); ap_set_etag(r); /* we accept byte-ranges */ apr_table_setn(r->headers_out, "Accept-Ranges", "bytes"); /* set up the Content-Length header */ ap_set_content_length(r, resource->info->finfo.size); /* ### how to set the content type? */ /* ### until this is resolved, the Content-Type header is busted */#endif return NULL;}#if DEBUG_PATHNAME_STYLEstatic const char * dav_fs_get_pathname( const dav_resource *resource, void **free_handle_p){ return resource->info->pathname;}#endifstatic void dav_fs_free_file(void *free_handle){ /* nothing to free ... */}static dav_error * dav_fs_create_collection(dav_resource *resource){ dav_resource_private *ctx = resource->info; apr_status_t status; status = apr_dir_make(ctx->pathname, APR_OS_DEFAULT, ctx->pool); if (status == ENOSPC) { return dav_new_error(ctx->pool, HTTP_INSUFFICIENT_STORAGE, 0, "There is not enough storage to create " "this collection."); } else if (status != APR_SUCCESS) { /* ### refine this error message? */ return dav_new_error(ctx->pool, HTTP_FORBIDDEN, 0, "Unable to create collection."); } /* update resource state to show it exists as a collection */ resource->exists = 1; resource->collection = 1; return NULL;}static dav_error * dav_fs_copymove_walker(dav_walk_resource *wres, int calltype){ dav_fs_copymove_walk_ctx *ctx = wres->walk_ctx; dav_resource_private *srcinfo = wres->resource->info; dav_resource_private *dstinfo = ctx->res_dst->info; dav_error *err = NULL; if (wres->resource->collection) { if (calltype == DAV_CALLTYPE_POSTFIX) { /* Postfix call for MOVE. delete the source dir. * Note: when copying, we do not enable the postfix-traversal. */ /* ### we are ignoring any error here; what should we do? */ (void) apr_dir_remove(srcinfo->pathname, ctx->pool); } else { /* copy/move of a collection. Create the new, target collection */ if (apr_dir_make(dstinfo->pathname, APR_OS_DEFAULT, ctx->pool) != APR_SUCCESS) { /* ### assume it was a permissions problem */ /* ### need a description here */ err = dav_new_error(ctx->pool, HTTP_FORBIDDEN, 0, NULL); } } } else { err = dav_fs_copymove_file(ctx->is_move, ctx->pool, srcinfo->pathname, dstinfo->pathname, &ctx->work_buf); /* ### push a higher-level description? */ } /* ** If we have a "not so bad" error, then it might need to go into a ** multistatus response. ** ** For a MOVE, it will always go into the multistatus. It could be ** that everything has been moved *except* for the root. Using a ** multistatus (with no errors for the other resources) will signify ** this condition. ** ** For a COPY, we are traversing in a prefix fashion. If the root fails, ** then we can just bail out now. */ if (err != NULL && !ap_is_HTTP_SERVER_ERROR(err->status) && (ctx->is_move || !dav_fs_is_same_resource(wres->resource, ctx->root))) { /* ### use errno to generate DAV:responsedescription? */ dav_add_response(wres, err->status, NULL); /* the error is in the multistatus now. do not stop the traversal. */ return NULL; } return err;}static dav_error *dav_fs_copymove_resource( int is_move, const dav_resource *src, const dav_resource *dst, int depth, dav_response **response){ dav_error *err = NULL; dav_buffer work_buf = { 0 }; *response = NULL; /* if a collection, recursively copy/move it and its children, * including the state dirs */ if (src->collection) { dav_walk_params params = { 0 }; dav_response *multi_status; params.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_HIDDEN; params.func = dav_fs_copymove_walker; params.pool = src->info->pool; params.root = src; /* params.walk_ctx is managed by dav_fs_internal_walk() */ /* postfix is needed for MOVE to delete source dirs */ if (is_move) params.walk_type |= DAV_WALKTYPE_POSTFIX; /* note that we return the error OR the multistatus. never both */ if ((err = dav_fs_internal_walk(¶ms, depth, is_move, dst, &multi_status)) != NULL) { /* on a "real" error, then just punt. nothing else to do. */ return err; } if ((*response = multi_status) != NULL) { /* some multistatus responses exist. wrap them in a 207 */ return dav_new_error(src->info->pool, HTTP_MULTI_STATUS, 0, "Error(s) occurred on some resources during " "the COPY/MOVE process."); } return NULL; } /* not a collection */ if ((err = dav_fs_copymove_file(is_move, src->info->pool, src->info->pathname, dst->info->pathname, &work_buf)) != NULL) { /* ### push a higher-level description? */ return err; } /* copy/move properties as well */ return dav_fs_copymoveset(is_move, src->info->pool, src, dst, &work_buf);}static dav_error * dav_fs_copy_resource( const dav_resource *src, dav_resource *dst, int depth, dav_response **response){ dav_error *err;#if DAV_DEBUG if (src->hooks != dst->hooks) { /* ** ### strictly speaking, this is a design error; we should not ** ### have reached this point. */ return dav_new_error(src->info->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "DESIGN ERROR: a mix of repositories " "was passed to copy_resource."); }#endif if ((err = dav_fs_copymove_resource(0, src, dst, depth, response)) == NULL) { /* update state of destination resource to show it exists */ dst->exists = 1; dst->collection = src->collection; } return err;}static dav_error * dav_fs_move_resource( dav_resource *src, dav_resource *dst, dav_response **response){ dav_resource_private *srcinfo = src->info; dav_resource_private *dstinfo = dst->info; dav_error *err; int can_rename = 0;#if DAV_DEBUG if (src->hooks != dst->hooks) { /* ** ### strictly speaking, this is a design error; we should not ** ### have reached this point. */ return dav_new_error(src->info->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "DESIGN ERROR: a mix of repositories " "was passed to move_resource."); }#endif /* determine whether a simple rename will work. * Assume source exists, else we wouldn't get called. */ if (dstinfo->finfo.filetype != 0) { if (dstinfo->finfo.device == srcinfo->finfo.device) { /* target exists and is on the same device. */ can_rename = 1; } } else { const char *dirpath; apr_finfo_t finfo; /* destination does not exist, but the parent directory should, * so try it */ dirpath = ap_make_dirstr_parent(dstinfo->pool, dstinfo->pathname); if (apr_stat(&finfo, dirpath, APR_FINFO_NORM, dstinfo->pool) == 0 && finfo.device == srcinfo->finfo.device) { can_rename = 1; } } /* if we can't simply rename, then do it the hard way... */ if (!can_rename) { if ((err = dav_fs_copymove_resource(1, src, dst, DAV_INFINITY, response)) == NULL) { /* update resource states */ dst->exists = 1; dst->collection = src->collection; src->exists = 0; src->collection = 0; } return err; } /* a rename should work. do it, and move properties as well */ /* no multistatus response */ *response = NULL; /* ### APR has no rename? */ if (apr_file_rename(srcinfo->pathname, dstinfo->pathname, srcinfo->pool) != APR_SUCCESS) { /* ### should have a better error than this. */ return dav_new_error(srcinfo->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not rename resource."); } /* update resource states */ dst->exists = 1; dst->collection = src->collection; src->exists = 0; src->collection = 0; if ((err = dav_fs_copymoveset(1, src->info->pool, src, dst, NULL)) == NULL) { /* no error. we're done. go ahead and return now. */ return NULL; } /* error occurred during properties move; try to put resource back */ if (apr_file_rename(dstinfo->pathname, srcinfo->pathname, srcinfo->pool) != APR_SUCCESS) { /* couldn't put it back! */ return dav_push_error(srcinfo->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "The resource was moved, but a failure " "occurred during the move of its " "properties. The resource could not be " "restored to its original location. The " "server is now in an inconsistent state.", err); } /* update resource states again */ src->exists = 1; src->collection = dst->collection; dst->exists = 0; dst->collection = 0; /* resource moved back, but properties may be inconsistent */ return dav_push_error(srcinfo->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "The resource was moved, but a failure " "occurred during the move of its properties. " "The resource was moved back to its original " "location, but its properties may have been " "partially moved. The server may be in an " "inconsistent state.", err);}static dav_error * dav_fs_delete_walker(dav_walk_resource *wres, int calltype){ dav_resource_private *info = wres->resource->info; /* do not attempt to remove a null resource, * or a collection with children */ if (wres->resource->exists && (!wres->resource->collection || calltype == DAV_CALLTYPE_POSTFIX)) { /* try to remove the resource */ apr_status_t result; result = wres->resource->collection ? apr_dir_remove(info->pathname, wres->pool) : apr_file_remove(info->pathname, wres->pool); /* ** If an error occurred, then add it to multistatus response.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -