📄 repos.c
字号:
if (resource->uri != NULL) { char *uri = ap_make_dirstr_parent(ctx->pool, resource->uri); if (strlen(uri) > 1 && uri[strlen(uri) - 1] == '/') uri[strlen(uri) - 1] = '\0'; parent_resource->uri = uri; } rv = apr_stat(&parent_ctx->finfo, parent_ctx->pathname, APR_FINFO_NORM, ctx->pool); if (rv == APR_SUCCESS || rv == APR_INCOMPLETE) { parent_resource->exists = 1; } *result_parent = parent_resource; return NULL;}static int dav_fs_is_same_resource( const dav_resource *res1, const dav_resource *res2){ dav_resource_private *ctx1 = res1->info; dav_resource_private *ctx2 = res2->info; if (res1->hooks != res2->hooks) return 0; if ((ctx1->finfo.filetype != 0) && (ctx2->finfo.filetype != 0) && (ctx1->finfo.valid & ctx2->finfo.valid & APR_FINFO_INODE)) { return ctx1->finfo.inode == ctx2->finfo.inode; } else { return strcmp(ctx1->pathname, ctx2->pathname) == 0; }}static int dav_fs_is_parent_resource( const dav_resource *res1, const dav_resource *res2){ dav_resource_private *ctx1 = res1->info; dav_resource_private *ctx2 = res2->info; apr_size_t len1 = strlen(ctx1->pathname); apr_size_t len2; if (res1->hooks != res2->hooks) return 0; /* it is safe to use ctx2 now */ len2 = strlen(ctx2->pathname); return (len2 > len1 && memcmp(ctx1->pathname, ctx2->pathname, len1) == 0 && ctx2->pathname[len1] == '/');}static dav_error * dav_fs_open_stream(const dav_resource *resource, dav_stream_mode mode, dav_stream **stream){ apr_pool_t *p = resource->info->pool; dav_stream *ds = apr_pcalloc(p, sizeof(*ds)); apr_int32_t flags; apr_status_t rv; switch (mode) { default: flags = APR_READ | APR_BINARY; break; case DAV_MODE_WRITE_TRUNC: flags = APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY; break; case DAV_MODE_WRITE_SEEKABLE: flags = APR_WRITE | APR_CREATE | APR_BINARY; break; } ds->p = p; ds->pathname = resource->info->pathname; rv = apr_file_open(&ds->f, ds->pathname, flags, APR_OS_DEFAULT, ds->p); if (rv != APR_SUCCESS) { return dav_new_error(p, MAP_IO2HTTP(rv), 0, "An error occurred while opening a resource."); } /* (APR registers cleanups for the fd with the pool) */ *stream = ds; 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_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 (APR_STATUS_IS_ENOSPC(status)) { 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;}#if DEBUG_GET_HANDLER/* only define set_headers() and deliver() for debug purposes */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 (!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 */ return NULL;}static dav_error * dav_fs_deliver(const dav_resource *resource, ap_filter_t *output){ apr_pool_t *pool = resource->pool; apr_bucket_brigade *bb; apr_file_t *fd; apr_status_t status; apr_bucket *bkt; /* Check resource type */ if (resource->type != DAV_RESOURCE_TYPE_REGULAR && resource->type != DAV_RESOURCE_TYPE_VERSION && resource->type != DAV_RESOURCE_TYPE_WORKING) { return dav_new_error(pool, HTTP_CONFLICT, 0, "Cannot GET this type of resource."); } if (resource->collection) { return dav_new_error(pool, HTTP_CONFLICT, 0, "There is no default response to GET for a " "collection."); } if ((status = apr_file_open(&fd, resource->info->pathname, APR_READ | APR_BINARY, 0, pool)) != APR_SUCCESS) { return dav_new_error(pool, HTTP_FORBIDDEN, 0, "File permissions deny server access."); } bb = apr_brigade_create(pool, output->c->bucket_alloc); /* ### this does not handle large files. but this is test code anyway */ bkt = apr_bucket_file_create(fd, 0, (apr_size_t)resource->info->finfo.size, pool, output->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, bkt); bkt = apr_bucket_eos_create(output->c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, bkt); if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) { return dav_new_error(pool, HTTP_FORBIDDEN, 0, "Could not write contents to filter."); } return NULL;}#endif /* DEBUG_GET_HANDLER */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 (APR_STATUS_IS_ENOSPC(status)) { return dav_new_error(ctx->pool, HTTP_INSUFFICIENT_STORAGE, 0, "There is not enough storage to create " "this collection."); } else if (APR_STATUS_IS_ENOENT(status)) { return dav_new_error(ctx->pool, HTTP_CONFLICT, 0, "Cannot create collection; intermediate " "collection does not exist."); } 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, &srcinfo->finfo, ctx->res_dst->exists ? &dstinfo->finfo : NULL, &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, &src->info->finfo, dst->exists ? &dst->info->finfo : NULL, &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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -