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

📄 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 页
字号:
        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, 
                                   &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(&params, 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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -