mapfile_stream.c
support for mmap() mailboxes.
Showing
1 changed file
with
291 additions
and
0 deletions
mailbox/mapfile_stream.c
0 → 100644
1 | /* GNU mailutils - a suite of utilities for electronic mail | ||
2 | Copyright (C) 1999, 2000 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Library Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU Library General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
17 | |||
18 | |||
19 | #include <errno.h> | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | #include <sys/types.h> | ||
25 | #include <sys/stat.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <unistd.h> | ||
28 | #include <sys/mman.h> | ||
29 | |||
30 | #include <io0.h> | ||
31 | |||
32 | struct _mapfile_stream | ||
33 | { | ||
34 | int fd; | ||
35 | int flags; | ||
36 | char *ptr; | ||
37 | size_t size; | ||
38 | }; | ||
39 | |||
40 | static void | ||
41 | _mapfile_destroy (stream_t stream) | ||
42 | { | ||
43 | struct _mapfile_stream *mfs = stream->owner; | ||
44 | |||
45 | if (mfs->ptr) | ||
46 | { | ||
47 | munmap (mfs->ptr, mfs->size); | ||
48 | close (mfs->fd); | ||
49 | } | ||
50 | free (mfs); | ||
51 | } | ||
52 | |||
53 | static int | ||
54 | _mapfile_read (stream_t stream, char *optr, size_t osize, | ||
55 | off_t offset, size_t *nbytes) | ||
56 | { | ||
57 | struct _mapfile_stream *mfs = stream->owner; | ||
58 | size_t n; | ||
59 | |||
60 | if (offset >= (off_t)mfs->size) | ||
61 | { | ||
62 | if (nbytes) | ||
63 | *nbytes = 0; | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | n = ((offset + osize) > mfs->size) ? mfs->size - offset : osize; | ||
68 | memcpy (optr, mfs->ptr + offset, n); | ||
69 | |||
70 | if (nbytes) | ||
71 | *nbytes = n; | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int | ||
76 | _mapfile_readline (stream_t stream, char *optr, size_t osize, | ||
77 | off_t offset, size_t *nbytes) | ||
78 | { | ||
79 | struct _mapfile_stream *mfs = stream->owner; | ||
80 | char *nl; | ||
81 | size_t n = 0; | ||
82 | |||
83 | /* save space for the null byte */ | ||
84 | osize--; | ||
85 | if (offset >= (off_t)mfs->size) | ||
86 | { | ||
87 | if (nbytes) | ||
88 | *nbytes = 0; | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | nl = memchr (mfs->ptr + offset, '\n', mfs->size - offset); | ||
93 | n = nl - (mfs->ptr + offset) + 1; | ||
94 | n = (n) > osize ? osize : n; | ||
95 | memcpy (optr, mfs->ptr + offset, n); | ||
96 | if (nbytes) | ||
97 | *nbytes = n; | ||
98 | optr[n] = '\0'; | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int | ||
103 | _mapfile_write (stream_t stream, const char *iptr, size_t isize, | ||
104 | off_t offset, size_t *nbytes) | ||
105 | { | ||
106 | struct _mapfile_stream *mfs = stream->owner; | ||
107 | |||
108 | if (! (mfs->flags & PROT_WRITE)) | ||
109 | return EACCES; | ||
110 | |||
111 | /* not recommanded, really */ | ||
112 | /* bigger we have to remmap */ | ||
113 | if (mfs->size < (offset + isize)) | ||
114 | { | ||
115 | if (munmap (mfs->ptr, mfs->size) != 0) | ||
116 | { | ||
117 | int err = errno; | ||
118 | mfs->ptr = MAP_FAILED; | ||
119 | close (mfs->fd); | ||
120 | return err; | ||
121 | } | ||
122 | if (ftruncate (mfs->fd, offset + isize) != 0) | ||
123 | return errno; | ||
124 | mfs->ptr = mmap (0, offset + isize, mfs->flags, MAP_SHARED, mfs->fd, 0); | ||
125 | if (mfs->ptr == MAP_FAILED) | ||
126 | { | ||
127 | int err = errno; | ||
128 | close (mfs->fd); | ||
129 | return err; | ||
130 | } | ||
131 | mfs->size = offset + isize; | ||
132 | } | ||
133 | |||
134 | memcpy (mfs->ptr + offset, iptr, isize); | ||
135 | if (nbytes) | ||
136 | *nbytes = isize; | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int | ||
141 | _mapfile_truncate (stream_t stream, off_t len) | ||
142 | { | ||
143 | struct _mapfile_stream *mfs = stream->owner; | ||
144 | /* remap */ | ||
145 | if (munmap (mfs->ptr, mfs->size) != 0) | ||
146 | { | ||
147 | int err = errno; | ||
148 | mfs->ptr = MAP_FAILED; | ||
149 | close (mfs->fd); | ||
150 | return err; | ||
151 | } | ||
152 | if (ftruncate (mfs->fd, len) != 0) | ||
153 | return errno; | ||
154 | mfs->ptr = mmap (0, len, mfs->flags, MAP_SHARED, mfs->fd, 0); | ||
155 | if (mfs->ptr == MAP_FAILED) | ||
156 | { | ||
157 | int err = errno; | ||
158 | close (mfs->fd); | ||
159 | return err; | ||
160 | } | ||
161 | mfs->size = len; | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static int | ||
166 | _mapfile_size (stream_t stream, off_t *psize) | ||
167 | { | ||
168 | struct _mapfile_stream *mfs = stream->owner; | ||
169 | struct stat stbuf; | ||
170 | msync (mfs->ptr, mfs->size, MS_SYNC); | ||
171 | if (fstat(mfs->fd, &stbuf) != 0) | ||
172 | return errno; | ||
173 | if (psize) | ||
174 | *psize = stbuf.st_size; | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int | ||
179 | _mapfile_flush (stream_t stream) | ||
180 | { | ||
181 | struct _mapfile_stream *mfs = stream->owner; | ||
182 | return msync (mfs->ptr, mfs->size, MS_SYNC); | ||
183 | } | ||
184 | |||
185 | static int | ||
186 | _mapfile_get_fd (stream_t stream, int *pfd) | ||
187 | { | ||
188 | struct _mapfile_stream *mfs = stream->owner; | ||
189 | if (pfd) | ||
190 | *pfd = mfs->fd; | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int | ||
195 | _mapfile_close (stream_t stream) | ||
196 | { | ||
197 | struct _mapfile_stream *mfs = stream->owner; | ||
198 | if (mfs->ptr) | ||
199 | { | ||
200 | if (munmap (mfs->ptr, mfs->size) != 0) | ||
201 | return errno; | ||
202 | mfs->ptr = NULL; | ||
203 | if (close (mfs->fd) != 0) | ||
204 | return errno; | ||
205 | mfs->fd = -1; | ||
206 | } | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int | ||
211 | _mapfile_open (stream_t stream, const char *filename, int port, int flags) | ||
212 | { | ||
213 | struct _mapfile_stream *mfs = stream->owner; | ||
214 | int mflag, flg; | ||
215 | struct stat st; | ||
216 | |||
217 | (void)port; /* shutup gcc */ | ||
218 | |||
219 | /* map the flags to the system equivalent */ | ||
220 | if (flags & MU_STREAM_WRITE) | ||
221 | { | ||
222 | mflag = PROT_WRITE; | ||
223 | flg = O_WRONLY; | ||
224 | } | ||
225 | else if (flags & MU_STREAM_RDWR) | ||
226 | { | ||
227 | mflag = PROT_READ | PROT_WRITE; | ||
228 | flg = O_RDWR; | ||
229 | } | ||
230 | else if (flags & MU_STREAM_CREAT) | ||
231 | return ENOTSUP; | ||
232 | else /* default */ | ||
233 | { | ||
234 | mflag = PROT_READ; | ||
235 | flg = O_RDONLY; | ||
236 | } | ||
237 | |||
238 | mfs->fd = open (filename, flg); | ||
239 | if (mfs->fd < 0) | ||
240 | return errno; | ||
241 | if (fstat (mfs->fd, &st) != 0) | ||
242 | { | ||
243 | int err = errno; | ||
244 | close (mfs->fd); | ||
245 | return err; | ||
246 | } | ||
247 | mfs->size = st.st_size; | ||
248 | mfs->ptr = mmap (0, mfs->size, mflag , MAP_SHARED, mfs->fd, 0); | ||
249 | if (mfs->ptr == MAP_FAILED) | ||
250 | { | ||
251 | int err = errno; | ||
252 | close (mfs->fd); | ||
253 | return err; | ||
254 | } | ||
255 | mfs->flags = mflag; | ||
256 | stream_set_flags (stream, flags |MU_STREAM_NO_CHECK, mfs); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | int | ||
261 | mapfile_stream_create (stream_t *stream) | ||
262 | { | ||
263 | struct _mapfile_stream *fs; | ||
264 | int ret; | ||
265 | |||
266 | if (stream == NULL) | ||
267 | return EINVAL; | ||
268 | |||
269 | fs = calloc (1, sizeof (struct _mapfile_stream)); | ||
270 | if (fs == NULL) | ||
271 | return ENOMEM; | ||
272 | |||
273 | ret = stream_create (stream, MU_STREAM_NO_CHECK, fs); | ||
274 | if (ret != 0) | ||
275 | { | ||
276 | free (fs); | ||
277 | return ret; | ||
278 | } | ||
279 | |||
280 | stream_set_open (*stream, _mapfile_open, fs); | ||
281 | stream_set_close (*stream, _mapfile_close, fs); | ||
282 | stream_set_fd (*stream, _mapfile_get_fd, fs); | ||
283 | stream_set_read (*stream, _mapfile_read, fs); | ||
284 | stream_set_readline (*stream, _mapfile_readline, fs); | ||
285 | stream_set_write (*stream, _mapfile_write, fs); | ||
286 | stream_set_truncate (*stream, _mapfile_truncate, fs); | ||
287 | stream_set_size (*stream, _mapfile_size, fs); | ||
288 | stream_set_flush (*stream, _mapfile_flush, fs); | ||
289 | stream_set_destroy (*stream, _mapfile_destroy, fs); | ||
290 | return 0; | ||
291 | } |
-
Please register or sign in to post a comment