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.h" 18#include "apr_private.h" 19#include "apr_general.h" 20#include "apr_strings.h" 21#include "apr_mmap.h" 22#include "apr_errno.h" 23#include "apr_arch_file_io.h" 24#include "apr_portable.h" 25 26/* System headers required for the mmap library */ 27#ifdef BEOS 28#include <kernel/OS.h> 29#endif 30#if APR_HAVE_STRING_H 31#include <string.h> 32#endif 33#if APR_HAVE_STDIO_H 34#include <stdio.h> 35#endif 36#ifdef HAVE_SYS_STAT_H 37#include <sys/stat.h> 38#endif 39#ifdef HAVE_SYS_MMAN_H 40#include <sys/mman.h> 41#endif 42 43#if APR_HAS_MMAP || defined(BEOS) 44 45static apr_status_t mmap_cleanup(void *themmap) 46{ 47 apr_mmap_t *mm = themmap; 48 apr_mmap_t *next = APR_RING_NEXT(mm,link); 49 int rv = 0; 50 51 /* we no longer refer to the mmaped region */ 52 APR_RING_REMOVE(mm,link); 53 APR_RING_NEXT(mm,link) = NULL; 54 APR_RING_PREV(mm,link) = NULL; 55 56 if (next != mm) { 57 /* more references exist, so we're done */ 58 return APR_SUCCESS; 59 } 60 61#ifdef BEOS 62 rv = delete_area(mm->area); 63#else 64 rv = munmap(mm->mm, mm->size); 65#endif 66 mm->mm = (void *)-1; 67 68 if (rv == 0) { 69 return APR_SUCCESS; 70 } 71 return errno; 72} 73 74APR_DECLARE(apr_status_t) apr_mmap_create(apr_mmap_t **new, 75 apr_file_t *file, apr_off_t offset, 76 apr_size_t size, apr_int32_t flag, 77 apr_pool_t *cont) 78{ 79 void *mm; 80#ifdef BEOS 81 area_id aid = -1; 82 uint32 pages = 0; 83#else 84 apr_int32_t native_flags = 0; 85#endif 86 87#if APR_HAS_LARGE_FILES && defined(HAVE_MMAP64) 88#define mmap mmap64 89#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4 90 /* LFS but no mmap64: check for overflow */ 91 if ((apr_int64_t)offset + size > INT_MAX) 92 return APR_EINVAL; 93#endif 94 95 if (size == 0) 96 return APR_EINVAL; 97 98 if (file == NULL || file->filedes == -1 || file->buffered) 99 return APR_EBADF; 100 (*new) = (apr_mmap_t *)apr_pcalloc(cont, sizeof(apr_mmap_t)); 101 102#ifdef BEOS 103 /* XXX: mmap shouldn't really change the seek offset */ 104 apr_file_seek(file, APR_SET, &offset); 105 106 /* There seems to be some strange interactions that mean our area must 107 * be set as READ & WRITE or writev will fail! Go figure... 108 * So we ignore the value in flags and always ask for both READ and WRITE 109 */ 110 pages = (size + B_PAGE_SIZE -1) / B_PAGE_SIZE; 111 aid = create_area("apr_mmap", &mm , B_ANY_ADDRESS, pages * B_PAGE_SIZE, 112 B_NO_LOCK, B_WRITE_AREA|B_READ_AREA); 113 114 if (aid < B_NO_ERROR) { 115 /* we failed to get an area we can use... */ 116 *new = NULL; 117 return APR_ENOMEM; 118 } 119 120 if (aid >= B_NO_ERROR) 121 read(file->filedes, mm, size); 122 123 (*new)->area = aid; 124#else 125 126 if (flag & APR_MMAP_WRITE) { 127 native_flags |= PROT_WRITE; 128 } 129 if (flag & APR_MMAP_READ) { 130 native_flags |= PROT_READ; 131 } 132 133 mm = mmap(NULL, size, native_flags, MAP_SHARED, file->filedes, offset); 134 135 if (mm == (void *)-1) { 136 /* we failed to get an mmap'd file... */ 137 *new = NULL; 138 return errno; 139 } 140#endif 141 142 (*new)->mm = mm; 143 (*new)->size = size; 144 (*new)->cntxt = cont; 145 APR_RING_ELEM_INIT(*new, link); 146 147 /* register the cleanup... */ 148 apr_pool_cleanup_register((*new)->cntxt, (void*)(*new), mmap_cleanup, 149 apr_pool_cleanup_null); 150 return APR_SUCCESS; 151} 152 153APR_DECLARE(apr_status_t) apr_mmap_dup(apr_mmap_t **new_mmap, 154 apr_mmap_t *old_mmap, 155 apr_pool_t *p) 156{ 157 *new_mmap = (apr_mmap_t *)apr_pmemdup(p, old_mmap, sizeof(apr_mmap_t)); 158 (*new_mmap)->cntxt = p; 159 160 APR_RING_INSERT_AFTER(old_mmap, *new_mmap, link); 161 162 apr_pool_cleanup_register(p, *new_mmap, mmap_cleanup, 163 apr_pool_cleanup_null); 164 return APR_SUCCESS; 165} 166 167APR_DECLARE(apr_status_t) apr_mmap_delete(apr_mmap_t *mm) 168{ 169 return apr_pool_cleanup_run(mm->cntxt, mm, mmap_cleanup); 170} 171 172#endif 173