📄 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 1
static 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);
}
static dav_error * dav_fs_copymove_file(
int is_move,
apr_pool_t * p,
const char *src,
const char *dst,
dav_buffer *pbuf)
{
dav_buffer work_buf = { 0 };
apr_file_t *inf = NULL;
apr_file_t *outf = NULL;
apr_status_t status;
if (pbuf == NULL)
pbuf = &work_buf;
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, APR_OS_DEFAULT, 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);
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 write "
"failure. Server is now in an "
"inconsistent state.");
}
return dav_new_error(p, MAP_IO2HTTP(status), 0,
"Could not write output file");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -