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