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_mmap.h" 21#include "apr_errno.h" 22#include "apr_arch_file_io.h" 23#include "apr_portable.h" 24#include "apr_strings.h" 25 26#if APR_HAS_MMAP 27 28static apr_status_t mmap_cleanup(void *themmap) 29{ 30 apr_mmap_t *mm = themmap; 31 apr_mmap_t *next = APR_RING_NEXT(mm,link); 32 33 /* we no longer refer to the mmaped region */ 34 APR_RING_REMOVE(mm,link); 35 APR_RING_NEXT(mm,link) = NULL; 36 APR_RING_PREV(mm,link) = NULL; 37 38 if (next != mm) { 39 /* more references exist, so we're done */ 40 return APR_SUCCESS; 41 } 42 43 if (mm->mv) { 44 if (!UnmapViewOfFile(mm->mv)) 45 { 46 apr_status_t rv = apr_get_os_error(); 47 CloseHandle(mm->mhandle); 48 mm->mv = NULL; 49 mm->mhandle = NULL; 50 return rv; 51 } 52 mm->mv = NULL; 53 } 54 if (mm->mhandle) 55 { 56 if (!CloseHandle(mm->mhandle)) 57 { 58 apr_status_t rv = apr_get_os_error(); 59 CloseHandle(mm->mhandle); 60 mm->mhandle = NULL; 61 return rv; 62 } 63 mm->mhandle = NULL; 64 } 65 return APR_SUCCESS; 66} 67 68APR_DECLARE(apr_status_t) apr_mmap_create(apr_mmap_t **new, apr_file_t *file, 69 apr_off_t offset, apr_size_t size, 70 apr_int32_t flag, apr_pool_t *cont) 71{ 72 static DWORD memblock = 0; 73 DWORD fmaccess = 0; 74 DWORD mvaccess = 0; 75 DWORD offlo; 76 DWORD offhi; 77 78 if (size == 0) 79 return APR_EINVAL; 80 81 if (flag & APR_MMAP_WRITE) 82 fmaccess |= PAGE_READWRITE; 83 else if (flag & APR_MMAP_READ) 84 fmaccess |= PAGE_READONLY; 85 86 if (flag & APR_MMAP_READ) 87 mvaccess |= FILE_MAP_READ; 88 if (flag & APR_MMAP_WRITE) 89 mvaccess |= FILE_MAP_WRITE; 90 91 if (!file || !file->filehand || file->filehand == INVALID_HANDLE_VALUE 92 || file->buffered) 93 return APR_EBADF; 94 95 if (!memblock) 96 { 97 SYSTEM_INFO si; 98 GetSystemInfo(&si); 99 memblock = si.dwAllocationGranularity; 100 } 101 102 *new = apr_pcalloc(cont, sizeof(apr_mmap_t)); 103 (*new)->pstart = (offset / memblock) * memblock; 104 (*new)->poffset = offset - (*new)->pstart; 105 (*new)->psize = (apr_size_t)((*new)->poffset) + size; 106 /* The size of the CreateFileMapping object is the current size 107 * of the size of the mmap object (e.g. file size), not the size 108 * of the mapped region! 109 */ 110 111 (*new)->mhandle = CreateFileMapping(file->filehand, NULL, fmaccess, 112 0, 0, NULL); 113 if (!(*new)->mhandle || (*new)->mhandle == INVALID_HANDLE_VALUE) 114 { 115 *new = NULL; 116 return apr_get_os_error(); 117 } 118 119 offlo = (DWORD)(*new)->pstart; 120 offhi = (DWORD)((*new)->pstart >> 32); 121 (*new)->mv = MapViewOfFile((*new)->mhandle, mvaccess, offhi, 122 offlo, (*new)->psize); 123 if (!(*new)->mv) 124 { 125 apr_status_t rv = apr_get_os_error(); 126 CloseHandle((*new)->mhandle); 127 *new = NULL; 128 return rv; 129 } 130 131 (*new)->mm = (char*)((*new)->mv) + (*new)->poffset; 132 (*new)->size = size; 133 (*new)->cntxt = cont; 134 APR_RING_ELEM_INIT(*new, link); 135 136 /* register the cleanup... */ 137 apr_pool_cleanup_register((*new)->cntxt, (void*)(*new), mmap_cleanup, 138 apr_pool_cleanup_null); 139 return APR_SUCCESS; 140} 141 142APR_DECLARE(apr_status_t) apr_mmap_dup(apr_mmap_t **new_mmap, 143 apr_mmap_t *old_mmap, 144 apr_pool_t *p) 145{ 146 *new_mmap = (apr_mmap_t *)apr_pmemdup(p, old_mmap, sizeof(apr_mmap_t)); 147 (*new_mmap)->cntxt = p; 148 149 APR_RING_INSERT_AFTER(old_mmap, *new_mmap, link); 150 151 apr_pool_cleanup_register(p, *new_mmap, mmap_cleanup, 152 apr_pool_cleanup_null); 153 return APR_SUCCESS; 154} 155 156APR_DECLARE(apr_status_t) apr_mmap_delete(apr_mmap_t *mm) 157{ 158 return apr_pool_cleanup_run(mm->cntxt, mm, mmap_cleanup); 159} 160 161#endif 162