mmap.c revision 251886
1268899Sbapt/* Licensed to the Apache Software Foundation (ASF) under one or more
2234949Sbapt * contributor license agreements.  See the NOTICE file distributed with
3234949Sbapt * this work for additional information regarding copyright ownership.
4234949Sbapt * The ASF licenses this file to You under the Apache License, Version 2.0
5234949Sbapt * (the "License"); you may not use this file except in compliance with
6234949Sbapt * the License.  You may obtain a copy of the License at
7234949Sbapt *
8234949Sbapt *     http://www.apache.org/licenses/LICENSE-2.0
9234949Sbapt *
10234949Sbapt * Unless required by applicable law or agreed to in writing, software
11234949Sbapt * distributed under the License is distributed on an "AS IS" BASIS,
12234949Sbapt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13234949Sbapt * See the License for the specific language governing permissions and
14234949Sbapt * limitations under the License.
15234949Sbapt */
16268899Sbapt
17234949Sbapt#include "apr.h"
18234949Sbapt#include "apr_private.h"
19234949Sbapt#include "apr_general.h"
20234949Sbapt#include "apr_strings.h"
21234949Sbapt#include "apr_mmap.h"
22234949Sbapt#include "apr_errno.h"
23234949Sbapt#include "apr_arch_file_io.h"
24234949Sbapt#include "apr_portable.h"
25234949Sbapt
26268899Sbapt/* System headers required for the mmap library */
27234949Sbapt#ifdef BEOS
28234949Sbapt#include <kernel/OS.h>
29234949Sbapt#endif
30234949Sbapt#if APR_HAVE_STRING_H
31234949Sbapt#include <string.h>
32234949Sbapt#endif
33234949Sbapt#if APR_HAVE_STDIO_H
34234949Sbapt#include <stdio.h>
35234949Sbapt#endif
36234949Sbapt#ifdef HAVE_SYS_STAT_H
37234949Sbapt#include <sys/stat.h>
38234949Sbapt#endif
39234949Sbapt#ifdef HAVE_SYS_MMAN_H
40234949Sbapt#include <sys/mman.h>
41234949Sbapt#endif
42268899Sbapt
43268899Sbapt#if APR_HAS_MMAP || defined(BEOS)
44268899Sbapt
45268899Sbaptstatic apr_status_t mmap_cleanup(void *themmap)
46268899Sbapt{
47268899Sbapt    apr_mmap_t *mm = themmap;
48268899Sbapt    apr_mmap_t *next = APR_RING_NEXT(mm,link);
49268899Sbapt    int rv = 0;
50268899Sbapt
51268899Sbapt    /* we no longer refer to the mmaped region */
52268899Sbapt    APR_RING_REMOVE(mm,link);
53268899Sbapt    APR_RING_NEXT(mm,link) = NULL;
54268899Sbapt    APR_RING_PREV(mm,link) = NULL;
55268899Sbapt
56268899Sbapt    if (next != mm) {
57268899Sbapt        /* more references exist, so we're done */
58268899Sbapt        return APR_SUCCESS;
59268899Sbapt    }
60268899Sbapt
61268899Sbapt#ifdef BEOS
62234949Sbapt    rv = delete_area(mm->area);
63234949Sbapt#else
64234949Sbapt    rv = munmap(mm->mm, mm->size);
65234949Sbapt#endif
66234949Sbapt    mm->mm = (void *)-1;
67234949Sbapt
68268899Sbapt    if (rv == 0) {
69234949Sbapt        return APR_SUCCESS;
70234949Sbapt    }
71234949Sbapt    return errno;
72234949Sbapt}
73234949Sbapt
74234949SbaptAPR_DECLARE(apr_status_t) apr_mmap_create(apr_mmap_t **new,
75234949Sbapt                                          apr_file_t *file, apr_off_t offset,
76234949Sbapt                                          apr_size_t size, apr_int32_t flag,
77234949Sbapt                                          apr_pool_t *cont)
78234949Sbapt{
79234949Sbapt    void *mm;
80234949Sbapt#ifdef BEOS
81234949Sbapt    area_id aid = -1;
82234949Sbapt    uint32 pages = 0;
83234949Sbapt#else
84234949Sbapt    apr_int32_t native_flags = 0;
85234949Sbapt#endif
86234949Sbapt
87234949Sbapt#if APR_HAS_LARGE_FILES && defined(HAVE_MMAP64)
88234949Sbapt#define mmap mmap64
89234949Sbapt#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T == 4
90234949Sbapt    /* LFS but no mmap64: check for overflow */
91234949Sbapt    if ((apr_int64_t)offset + size > INT_MAX)
92234949Sbapt        return APR_EINVAL;
93234949Sbapt#endif
94234949Sbapt
95234949Sbapt    if (size == 0)
96234949Sbapt        return APR_EINVAL;
97234949Sbapt
98234949Sbapt    if (file == NULL || file->filedes == -1 || file->buffered)
99234949Sbapt        return APR_EBADF;
100234949Sbapt    (*new) = (apr_mmap_t *)apr_pcalloc(cont, sizeof(apr_mmap_t));
101234949Sbapt
102234949Sbapt#ifdef BEOS
103234949Sbapt    /* XXX: mmap shouldn't really change the seek offset */
104234949Sbapt    apr_file_seek(file, APR_SET, &offset);
105234949Sbapt
106234949Sbapt    /* There seems to be some strange interactions that mean our area must
107234949Sbapt     * be set as READ & WRITE or writev will fail!  Go figure...
108234949Sbapt     * So we ignore the value in flags and always ask for both READ and WRITE
109234949Sbapt     */
110234949Sbapt    pages = (size + B_PAGE_SIZE -1) / B_PAGE_SIZE;
111234949Sbapt    aid = create_area("apr_mmap", &mm , B_ANY_ADDRESS, pages * B_PAGE_SIZE,
112234949Sbapt        B_NO_LOCK, B_WRITE_AREA|B_READ_AREA);
113234949Sbapt
114234949Sbapt    if (aid < B_NO_ERROR) {
115234949Sbapt        /* we failed to get an area we can use... */
116234949Sbapt        *new = NULL;
117234949Sbapt        return APR_ENOMEM;
118234949Sbapt    }
119234949Sbapt
120234949Sbapt    if (aid >= B_NO_ERROR)
121234949Sbapt        read(file->filedes, mm, size);
122234949Sbapt
123234949Sbapt    (*new)->area = aid;
124234949Sbapt#else
125234949Sbapt
126234949Sbapt    if (flag & APR_MMAP_WRITE) {
127234949Sbapt        native_flags |= PROT_WRITE;
128234949Sbapt    }
129234949Sbapt    if (flag & APR_MMAP_READ) {
130234949Sbapt        native_flags |= PROT_READ;
131234949Sbapt    }
132234949Sbapt
133234949Sbapt    mm = mmap(NULL, size, native_flags, MAP_SHARED, file->filedes, offset);
134234949Sbapt
135234949Sbapt    if (mm == (void *)-1) {
136234949Sbapt        /* we failed to get an mmap'd file... */
137234949Sbapt        *new = NULL;
138234949Sbapt        return errno;
139234949Sbapt    }
140234949Sbapt#endif
141234949Sbapt
142234949Sbapt    (*new)->mm = mm;
143234949Sbapt    (*new)->size = size;
144234949Sbapt    (*new)->cntxt = cont;
145234949Sbapt    APR_RING_ELEM_INIT(*new, link);
146234949Sbapt
147234949Sbapt    /* register the cleanup... */
148234949Sbapt    apr_pool_cleanup_register((*new)->cntxt, (void*)(*new), mmap_cleanup,
149234949Sbapt             apr_pool_cleanup_null);
150234949Sbapt    return APR_SUCCESS;
151234949Sbapt}
152234949Sbapt
153234949SbaptAPR_DECLARE(apr_status_t) apr_mmap_dup(apr_mmap_t **new_mmap,
154234949Sbapt                                       apr_mmap_t *old_mmap,
155234949Sbapt                                       apr_pool_t *p)
156234949Sbapt{
157234949Sbapt    *new_mmap = (apr_mmap_t *)apr_pmemdup(p, old_mmap, sizeof(apr_mmap_t));
158234949Sbapt    (*new_mmap)->cntxt = p;
159234949Sbapt
160234949Sbapt    APR_RING_INSERT_AFTER(old_mmap, *new_mmap, link);
161234949Sbapt
162234949Sbapt    apr_pool_cleanup_register(p, *new_mmap, mmap_cleanup,
163234949Sbapt                              apr_pool_cleanup_null);
164234949Sbapt    return APR_SUCCESS;
165234949Sbapt}
166234949Sbapt
167234949SbaptAPR_DECLARE(apr_status_t) apr_mmap_delete(apr_mmap_t *mm)
168234949Sbapt{
169234949Sbapt    return apr_pool_cleanup_run(mm->cntxt, mm, mmap_cleanup);
170234949Sbapt}
171234949Sbapt
172234949Sbapt#endif
173234949Sbapt