⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 repos.c

📁 Apache 2.0.63 is the current stable version of the 2.0 series, and is recommended over any previous
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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 + -