1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "apr_buckets.h"
18
19#if APR_HAS_MMAP
20
21static apr_status_t mmap_bucket_read(apr_bucket *b, const char **str,
22                                     apr_size_t *length, apr_read_type_e block)
23{
24    apr_bucket_mmap *m = b->data;
25    apr_status_t ok;
26    void *addr;
27
28    if (!m->mmap) {
29        /* the apr_mmap_t was already cleaned up out from under us */
30        return APR_EINVAL;
31    }
32
33    ok = apr_mmap_offset(&addr, m->mmap, b->start);
34    if (ok != APR_SUCCESS) {
35        return ok;
36    }
37    *str = addr;
38    *length = b->length;
39    return APR_SUCCESS;
40}
41
42static apr_status_t mmap_bucket_cleanup(void *data)
43{
44    /* the apr_mmap_t is about to disappear out from under us, so we
45     * have no choice but to pretend it doesn't exist anymore.  the
46     * refcount is now useless because there's nothing to refer to
47     * anymore.  so the only valid action on any remaining referrer
48     * is to delete it.  no more reads, no more anything. */
49    apr_bucket_mmap *m = data;
50
51    m->mmap = NULL;
52    return APR_SUCCESS;
53}
54
55static void mmap_bucket_destroy(void *data)
56{
57    apr_bucket_mmap *m = data;
58
59    if (apr_bucket_shared_destroy(m)) {
60        if (m->mmap) {
61            apr_pool_cleanup_kill(m->mmap->cntxt, m, mmap_bucket_cleanup);
62            apr_mmap_delete(m->mmap);
63        }
64        apr_bucket_free(m);
65    }
66}
67
68/*
69 * XXX: are the start and length arguments useful?
70 */
71APU_DECLARE(apr_bucket *) apr_bucket_mmap_make(apr_bucket *b, apr_mmap_t *mm,
72                                               apr_off_t start,
73                                               apr_size_t length)
74{
75    apr_bucket_mmap *m;
76
77    m = apr_bucket_alloc(sizeof(*m), b->list);
78    m->mmap = mm;
79
80    apr_pool_cleanup_register(mm->cntxt, m, mmap_bucket_cleanup,
81                              apr_pool_cleanup_null);
82
83    b = apr_bucket_shared_make(b, m, start, length);
84    b->type = &apr_bucket_type_mmap;
85
86    return b;
87}
88
89
90APU_DECLARE(apr_bucket *) apr_bucket_mmap_create(apr_mmap_t *mm,
91                                                 apr_off_t start,
92                                                 apr_size_t length,
93                                                 apr_bucket_alloc_t *list)
94{
95    apr_bucket *b = apr_bucket_alloc(sizeof(*b), list);
96
97    APR_BUCKET_INIT(b);
98    b->free = apr_bucket_free;
99    b->list = list;
100    return apr_bucket_mmap_make(b, mm, start, length);
101}
102
103static apr_status_t mmap_bucket_setaside(apr_bucket *b, apr_pool_t *p)
104{
105    apr_bucket_mmap *m = b->data;
106    apr_mmap_t *mm = m->mmap;
107    apr_mmap_t *new_mm;
108    apr_status_t ok;
109
110    if (!mm) {
111        /* the apr_mmap_t was already cleaned up out from under us */
112        return APR_EINVAL;
113    }
114
115    /* shortcut if possible */
116    if (apr_pool_is_ancestor(mm->cntxt, p)) {
117        return APR_SUCCESS;
118    }
119
120    /* duplicate apr_mmap_t into new pool */
121    ok = apr_mmap_dup(&new_mm, mm, p);
122    if (ok != APR_SUCCESS) {
123        return ok;
124    }
125
126    /* decrement refcount on old apr_bucket_mmap */
127    mmap_bucket_destroy(m);
128
129    /* create new apr_bucket_mmap pointing to new apr_mmap_t */
130    apr_bucket_mmap_make(b, new_mm, b->start, b->length);
131
132    return APR_SUCCESS;
133}
134
135APU_DECLARE_DATA const apr_bucket_type_t apr_bucket_type_mmap = {
136    "MMAP", 5, APR_BUCKET_DATA,
137    mmap_bucket_destroy,
138    mmap_bucket_read,
139    mmap_bucket_setaside,
140    apr_bucket_shared_split,
141    apr_bucket_shared_copy
142};
143
144#endif
145