Commit 61e324d1 61e324d1b6b2c85c7e13757536bc82a124142f5d by Alain Magloire

mapfile_stream.c

support for mmap() mailboxes.
1 parent e63412d7
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 }