📄 repos.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//*** DAV filesystem-based repository provider*/#include "apr.h"#include "apr_file_io.h"#include "apr_strings.h"#include "apr_buckets.h"#if APR_HAVE_STDIO_H#include <stdio.h> /* for sprintf() */#endif#include "httpd.h"#include "http_log.h"#include "http_protocol.h" /* for ap_set_* (in dav_fs_set_headers) */#include "http_request.h" /* for ap_update_mtime() */#include "mod_dav.h"#include "repos.h"/* to assist in debugging mod_dav's GET handling */#define DEBUG_GET_HANDLER 0#define DAV_FS_COPY_BLOCKSIZE 16384 /* copy 16k at a time *//* context needed to identify a resource */struct dav_resource_private { apr_pool_t *pool; /* memory storage pool associated with request */ const char *pathname; /* full pathname to resource */ apr_finfo_t finfo; /* filesystem info */};/* private context for doing a filesystem walk */typedef struct { /* the input walk parameters */ const dav_walk_params *params; /* reused as we walk */ dav_walk_resource wres; dav_resource res1; dav_resource_private info1; dav_buffer path1; dav_buffer uri_buf; /* MOVE/COPY need a secondary path */ dav_resource res2; dav_resource_private info2; dav_buffer path2; dav_buffer locknull_buf;} dav_fs_walker_context;typedef struct { int is_move; /* is this a MOVE? */ dav_buffer work_buf; /* handy buffer for copymove_file() */ /* CALLBACK: this is a secondary resource managed specially for us */ const dav_resource *res_dst; /* copied from dav_walk_params (they are invariant across the walk) */ const dav_resource *root; apr_pool_t *pool;} dav_fs_copymove_walk_ctx;/* an internal WALKTYPE to walk hidden files (the .DAV directory) */#define DAV_WALKTYPE_HIDDEN 0x4000/* an internal WALKTYPE to call collections (again) after their contents */#define DAV_WALKTYPE_POSTFIX 0x8000#define DAV_CALLTYPE_POSTFIX 1000 /* a private call type *//* pull this in from the other source file */extern const dav_hooks_locks dav_hooks_locks_fs;/* forward-declare the hook structures */static const dav_hooks_repository dav_hooks_repository_fs;static const dav_hooks_liveprop dav_hooks_liveprop_fs;/*** The namespace URIs that we use. This list and the enumeration must** stay in sync.*/static const char * const dav_fs_namespace_uris[] ={ "DAV:", "http://apache.org/dav/props/", NULL /* sentinel */};enum { DAV_FS_URI_DAV, /* the DAV: namespace URI */ DAV_FS_URI_MYPROPS /* the namespace URI for our custom props */};/*** Does this platform support an executable flag?**** ### need a way to portably abstract this query*/#ifndef WIN32#define DAV_FS_HAS_EXECUTABLE#endif/*** The single property that we define (in the DAV_FS_URI_MYPROPS namespace)*/#define DAV_PROPID_FS_executable 1static const dav_liveprop_spec dav_fs_props[] ={ /* standard DAV properties */ { DAV_FS_URI_DAV, "creationdate", DAV_PROPID_creationdate, 0 }, { DAV_FS_URI_DAV, "getcontentlength", DAV_PROPID_getcontentlength, 0 }, { DAV_FS_URI_DAV, "getetag", DAV_PROPID_getetag, 0 }, { DAV_FS_URI_DAV, "getlastmodified", DAV_PROPID_getlastmodified, 0 }, /* our custom properties */ { DAV_FS_URI_MYPROPS, "executable", DAV_PROPID_FS_executable, 0 /* handled special in dav_fs_is_writable */ }, { 0 } /* sentinel */};static const dav_liveprop_group dav_fs_liveprop_group ={ dav_fs_props, dav_fs_namespace_uris, &dav_hooks_liveprop_fs};/* define the dav_stream structure for our use */struct dav_stream { apr_pool_t *p; apr_file_t *f; const char *pathname; /* we may need to remove it at close time */};/* returns an appropriate HTTP status code given an APR status code for a * failed I/O operation. ### use something besides 500? */#define MAP_IO2HTTP(e) (APR_STATUS_IS_ENOSPC(e) ? HTTP_INSUFFICIENT_STORAGE : \ HTTP_INTERNAL_SERVER_ERROR)/* forward declaration for internal treewalkers */static dav_error * dav_fs_walk(const dav_walk_params *params, int depth, dav_response **response);static dav_error * dav_fs_internal_walk(const dav_walk_params *params, int depth, int is_move, const dav_resource *root_dst, dav_response **response);/* --------------------------------------------------------------------**** PRIVATE REPOSITORY FUNCTIONS*/apr_pool_t *dav_fs_pool(const dav_resource *resource){ return resource->info->pool;}const char *dav_fs_pathname(const dav_resource *resource){ return resource->info->pathname;}dav_error * dav_fs_dir_file_name( const dav_resource *resource, const char **dirpath_p, const char **fname_p){ dav_resource_private *ctx = resource->info; if (resource->collection) { *dirpath_p = ctx->pathname; if (fname_p != NULL) *fname_p = NULL; } else { const char *testpath, *rootpath; char *dirpath = ap_make_dirstr_parent(ctx->pool, ctx->pathname); apr_size_t dirlen = strlen(dirpath); apr_status_t rv = APR_SUCCESS; testpath = dirpath; if (dirlen > 0) { rv = apr_filepath_root(&rootpath, &testpath, 0, ctx->pool); } /* remove trailing slash from dirpath, unless it's a root path */ if ((rv == APR_SUCCESS && testpath && *testpath) || rv == APR_ERELATIVE) { if (dirpath[dirlen - 1] == '/') { dirpath[dirlen - 1] = '\0'; } } /* ###: Looks like a response could be appropriate * * APR_SUCCESS here tells us the dir is a root * APR_ERELATIVE told us we had no root (ok) * APR_EINCOMPLETE an incomplete testpath told us * there was no -file- name here! * APR_EBADPATH or other errors tell us this file * path is undecipherable */ if (rv == APR_SUCCESS || rv == APR_ERELATIVE) { *dirpath_p = dirpath; if (fname_p != NULL) *fname_p = ctx->pathname + dirlen; } else { return dav_new_error(ctx->pool, HTTP_INTERNAL_SERVER_ERROR, 0, "An incomplete/bad path was found in " "dav_fs_dir_file_name."); } } return NULL;}/* Note: picked up from ap_gm_timestr_822() *//* NOTE: buf must be at least DAV_TIMEBUF_SIZE chars in size */static void dav_format_time(int style, apr_time_t sec, char *buf){ apr_time_exp_t tms; /* ### what to do if fails? */ (void) apr_time_exp_gmt(&tms, sec); if (style == DAV_STYLE_ISO8601) { /* ### should we use "-00:00" instead of "Z" ?? */ /* 20 chars plus null term */ sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2dZ", tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday, tms.tm_hour, tms.tm_min, tms.tm_sec); return; } /* RFC 822 date format; as strftime '%a, %d %b %Y %T GMT' */ /* 29 chars plus null term */ sprintf(buf, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", apr_day_snames[tms.tm_wday], tms.tm_mday, apr_month_snames[tms.tm_mon], tms.tm_year + 1900, tms.tm_hour, tms.tm_min, tms.tm_sec);}/* Copy or move src to dst; src_finfo is used to propagate permissions * bits across if non-NULL; dst_finfo must be non-NULL iff dst already * exists. */static dav_error * dav_fs_copymove_file( int is_move, apr_pool_t * p, const char *src, const char *dst, const apr_finfo_t *src_finfo, const apr_finfo_t *dst_finfo, dav_buffer *pbuf){ dav_buffer work_buf = { 0 }; apr_file_t *inf = NULL; apr_file_t *outf = NULL; apr_status_t status; apr_fileperms_t perms; if (pbuf == NULL) pbuf = &work_buf; /* Determine permissions to use for destination */ if (src_finfo && src_finfo->valid & APR_FINFO_PROT && src_finfo->protection & APR_UEXECUTE) { perms = src_finfo->protection; if (dst_finfo != NULL) { /* chmod it if it already exist */ if (apr_file_perms_set(dst, perms)) { return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not set permissions on destination"); } } } else { perms = APR_OS_DEFAULT; } dav_set_bufsize(p, pbuf, DAV_FS_COPY_BLOCKSIZE); if ((apr_file_open(&inf, src, APR_READ | APR_BINARY, APR_OS_DEFAULT, p)) != APR_SUCCESS) { /* ### use something besides 500? */ return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not open file for reading"); } /* ### do we need to deal with the umask? */ status = apr_file_open(&outf, dst, APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY, perms, p); if (status != APR_SUCCESS) { apr_file_close(inf); return dav_new_error(p, MAP_IO2HTTP(status), 0, "Could not open file for writing"); } while (1) { apr_size_t len = DAV_FS_COPY_BLOCKSIZE; status = apr_file_read(inf, pbuf->buf, &len); if (status != APR_SUCCESS && status != APR_EOF) { apr_file_close(inf); apr_file_close(outf); if (apr_file_remove(dst, p) != APR_SUCCESS) { /* ### ACK! Inconsistent state... */ /* ### use something besides 500? */ return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not delete output after read " "failure. Server is now in an " "inconsistent state."); } /* ### use something besides 500? */ return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, "Could not read input file"); } if (status == APR_EOF) break; /* write any bytes that were read */ status = apr_file_write_full(outf, pbuf->buf, len, NULL); if (status != APR_SUCCESS) { apr_file_close(inf); apr_file_close(outf);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -