summaryrefslogtreecommitdiffabout
path: root/libetpan/src/data-types/mmapstring.c
Unidiff
Diffstat (limited to 'libetpan/src/data-types/mmapstring.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/data-types/mmapstring.c551
1 files changed, 551 insertions, 0 deletions
diff --git a/libetpan/src/data-types/mmapstring.c b/libetpan/src/data-types/mmapstring.c
new file mode 100644
index 0000000..37c681c
--- a/dev/null
+++ b/libetpan/src/data-types/mmapstring.c
@@ -0,0 +1,551 @@
1/*
2 * libEtPan! -- a mail stuff library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#include "mmapstring.h"
37
38#include "chash.h"
39
40#ifndef CONFIG_H
41#define CONFIG_H
42#include "config.h"
43#endif
44
45#include <stdlib.h>
46#include <unistd.h>
47#include <sys/mman.h>
48#include <string.h>
49#ifdef LIBETPAN_REENTRANT
50#include <pthread.h>
51#endif
52
53#include "libetpan-config.h"
54
55#define MMAPSTRING_MAX(a, b) ((a) > (b) ? (a) : (b))
56#define MMAPSTRING_MIN(a, b) ((a) < (b) ? (a) : (b))
57
58#define MMAP_STRING_DEFAULT_CEIL (8 * 1024 * 1024)
59
60#define DEFAULT_TMP_PATH "/tmp"
61
62static char tmpdir[PATH_MAX] = DEFAULT_TMP_PATH;
63
64static size_t mmap_string_ceil = MMAP_STRING_DEFAULT_CEIL;
65
66/* MMAPString references */
67
68#ifdef LIBETPAN_REENTRANT
69static pthread_mutex_t mmapstring_lock = PTHREAD_MUTEX_INITIALIZER;
70#endif
71static chash * mmapstring_hashtable = NULL;
72
73static void mmapstring_hashtable_init()
74{
75 mmapstring_hashtable = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
76}
77
78void mmap_string_set_tmpdir(char * directory)
79{
80 strncpy(tmpdir, directory, PATH_MAX);
81 tmpdir[PATH_MAX - 1] = 0;
82}
83
84
85int mmap_string_ref(MMAPString * string)
86{
87 chash * ht;
88 int r;
89 chashdatum key;
90 chashdatum data;
91
92#ifdef LIBETPAN_REENTRANT
93 pthread_mutex_lock(&mmapstring_lock);
94#endif
95 if (mmapstring_hashtable == NULL) {
96 mmapstring_hashtable_init();
97 }
98 ht = mmapstring_hashtable;
99
100 if (ht == NULL) {
101#ifdef LIBETPAN_REENTRANT
102 pthread_mutex_unlock(&mmapstring_lock);
103#endif
104 return -1;
105 }
106
107 key.data = &string->str;
108 key.len = sizeof(string->str);
109 data.data = string;
110 data.len = 0;
111
112 r = chash_set(mmapstring_hashtable, &key, &data, NULL);
113#ifdef LIBETPAN_REENTRANT
114 pthread_mutex_unlock(&mmapstring_lock);
115#endif
116
117 if (r < 0)
118 return r;
119
120 return 0;
121}
122
123int mmap_string_unref(char * str)
124{
125 MMAPString * string;
126 chash * ht;
127 chashdatum key;
128 chashdatum data;
129 int r;
130
131#ifdef LIBETPAN_REENTRANT
132 pthread_mutex_lock(&mmapstring_lock);
133#endif
134 ht = mmapstring_hashtable;
135
136 if (ht == NULL) {
137#ifdef LIBETPAN_REENTRANT
138 pthread_mutex_unlock(&mmapstring_lock);
139#endif
140 return -1;
141 }
142
143 key.data = &str;
144 key.len = sizeof(str);
145
146 r = chash_get(ht, &key, &data);
147 if (r < 0)
148 string = NULL;
149 else
150 string = data.data;
151
152 if (string != NULL) {
153 chash_delete(ht, &key, NULL);
154 if (chash_count(ht) == 0) {
155 chash_free(ht);
156 mmapstring_hashtable = NULL;
157 }
158 }
159
160#ifdef LIBETPAN_REENTRANT
161 pthread_mutex_unlock(&mmapstring_lock);
162#endif
163
164 if (string != NULL) {
165 mmap_string_free(string);
166 return 0;
167 }
168 else
169 return -1;
170}
171
172
173
174/* MMAPString */
175
176#define MY_MAXSIZE ((size_t) -1)
177
178static inline size_t
179nearest_power (size_t base, size_t num)
180{
181 if (num > MY_MAXSIZE / 2) {
182 return MY_MAXSIZE;
183 }
184 else {
185 size_t n = base;
186
187 while (n < num)
188 n <<= 1;
189
190 return n;
191 }
192}
193
194void mmap_string_set_ceil(size_t ceil)
195{
196 mmap_string_ceil = ceil;
197}
198
199/* Strings.
200 */
201
202static MMAPString * mmap_string_realloc_file(MMAPString * string)
203{
204 char * data;
205
206 if (string->fd == -1) {
207 char tmpfilename[PATH_MAX];
208 int fd;
209
210 * tmpfilename = 0;
211 strcat(tmpfilename, tmpdir);
212 strcat(tmpfilename, "/libetpan-mmapstring-XXXXXX");
213
214 fd = mkstemp(tmpfilename);
215 if (fd == -1)
216 return NULL;
217
218 if (unlink(tmpfilename) == -1) {
219 close(fd);
220 return NULL;
221 }
222
223 if (ftruncate(fd, string->allocated_len) == -1) {
224 close(fd);
225 return NULL;
226 }
227
228 data = mmap(NULL, string->allocated_len, PROT_WRITE | PROT_READ,
229 MAP_SHARED, fd, 0);
230
231 if (data == MAP_FAILED) {
232 close(fd);
233 return NULL;
234 }
235
236 if (string->str != NULL)
237 memcpy(data, string->str, string->len + 1);
238
239 string->fd = fd;
240 string->mmapped_size = string->allocated_len;
241 free(string->str);
242 string->str = data;
243 }
244 else {
245 if (munmap(string->str, string->mmapped_size) == -1)
246 return NULL;
247
248 if (ftruncate(string->fd, string->allocated_len) == -1)
249 return NULL;
250
251 data = mmap(NULL, string->allocated_len, PROT_WRITE | PROT_READ,
252 MAP_SHARED, string->fd, 0);
253
254 if (data == MAP_FAILED)
255 return NULL;
256
257 string->mmapped_size = string->allocated_len;
258 string->str = data;
259 }
260
261 return string;
262}
263
264static MMAPString * mmap_string_realloc_memory(MMAPString * string)
265{
266 char * tmp;
267
268 tmp = realloc (string->str, string->allocated_len);
269
270 if (tmp == NULL)
271 string = NULL;
272 else
273 string->str = tmp;
274
275 return string;
276}
277
278static MMAPString *
279mmap_string_maybe_expand (MMAPString* string,
280 size_t len)
281{
282 if (string->len + len >= string->allocated_len)
283 {
284 size_t old_size;
285 MMAPString * newstring;
286
287 old_size = string->allocated_len;
288
289 string->allocated_len = nearest_power (1, string->len + len + 1);
290
291#ifndef MMAP_UNAVAILABLE
292 if (string->allocated_len > mmap_string_ceil)
293 newstring = mmap_string_realloc_file(string);
294 else {
295#endif
296 newstring = mmap_string_realloc_memory(string);
297#ifndef MMAP_UNAVAILABLE
298 if (newstring == NULL)
299 newstring = mmap_string_realloc_file(string);
300 }
301#endif
302
303 if (newstring == NULL)
304 string->allocated_len = old_size;
305
306 return newstring;
307 }
308
309 return string;
310}
311
312MMAPString*
313mmap_string_sized_new (size_t dfl_size)
314{
315 MMAPString *string;
316
317 string = malloc(sizeof(* string));
318 if (string == NULL)
319 return NULL;
320
321 string->allocated_len = 0;
322 string->len = 0;
323 string->str = NULL;
324 string->fd = -1;
325 string->mmapped_size = 0;
326
327 if (mmap_string_maybe_expand (string, MMAPSTRING_MAX (dfl_size, 2)) == NULL)
328 return NULL;
329
330 string->str[0] = 0;
331
332 return string;
333}
334
335MMAPString*
336mmap_string_new (const char *init)
337{
338 MMAPString *string;
339
340 string = mmap_string_sized_new (init ? strlen (init) + 2 : 2);
341 if (string == NULL)
342 return NULL;
343
344 if (init)
345 mmap_string_append (string, init);
346
347 return string;
348}
349
350MMAPString*
351mmap_string_new_len (const char *init,
352 size_t len)
353{
354 MMAPString *string;
355
356 if (len <= 0)
357 return mmap_string_new ("");
358 else
359 {
360 string = mmap_string_sized_new (len);
361 if (string == NULL)
362 return string;
363
364 if (init)
365 mmap_string_append_len (string, init, len);
366
367 return string;
368 }
369}
370
371void
372mmap_string_free (MMAPString *string)
373{
374 if (string == NULL)
375 return;
376
377 if (string->fd != -1) {
378 munmap(string->str, string->mmapped_size);
379 close(string->fd);
380 }
381 else {
382 free (string->str);
383 }
384 free(string);
385}
386
387MMAPString*
388mmap_string_assign (MMAPString *string,
389 const char *rval)
390{
391 mmap_string_truncate (string, 0);
392 if (mmap_string_append (string, rval) == NULL)
393 return NULL;
394
395 return string;
396}
397
398MMAPString*
399mmap_string_truncate (MMAPString *string,
400 size_t len)
401{
402 string->len = MMAPSTRING_MIN (len, string->len);
403 string->str[string->len] = 0;
404
405 return string;
406}
407
408/**
409 * mmap_string_set_size:
410 * @string: a #MMAPString
411 * @len: the new length
412 *
413 * Sets the length of a #MMAPString. If the length is less than
414 * the current length, the string will be truncated. If the
415 * length is greater than the current length, the contents
416 * of the newly added area are undefined. (However, as
417 * always, string->str[string->len] will be a nul byte.)
418 *
419 * Return value: @string
420 **/
421MMAPString*
422mmap_string_set_size (MMAPString *string,
423 size_t len)
424{
425 if (len >= string->allocated_len)
426 if (mmap_string_maybe_expand (string, len - string->len) == NULL)
427 return NULL;
428
429 string->len = len;
430 string->str[len] = 0;
431
432 return string;
433}
434
435/*
436static int in_mapped_zone(MMAPString * string, char * val)
437{
438 return (val >= string->str) && (val < string->str + string->mmapped_size);
439}
440*/
441
442MMAPString*
443mmap_string_insert_len (MMAPString *string,
444 size_t pos,
445 const char *val,
446 size_t len)
447{
448 if (mmap_string_maybe_expand (string, len) == NULL)
449 return NULL;
450
451 if (pos < string->len)
452 memmove (string->str + pos + len, string->str + pos, string->len - pos);
453
454 /* insert the new string */
455 memmove (string->str + pos, val, len);
456
457 string->len += len;
458
459 string->str[string->len] = 0;
460
461 return string;
462}
463
464MMAPString*
465mmap_string_append (MMAPString *string,
466 const char *val)
467{
468 return mmap_string_insert_len (string, string->len, val, strlen(val));
469}
470
471MMAPString*
472 mmap_string_append_len (MMAPString *string,
473 const char *val,
474 size_t len)
475{
476 return mmap_string_insert_len (string, string->len, val, len);
477}
478
479MMAPString*
480mmap_string_append_c (MMAPString *string,
481 char c)
482{
483 return mmap_string_insert_c (string, string->len, c);
484}
485
486MMAPString*
487mmap_string_prepend (MMAPString *string,
488 const char *val)
489{
490 return mmap_string_insert_len (string, 0, val, strlen(val));
491}
492
493MMAPString*
494 mmap_string_prepend_len (MMAPString *string,
495 const char *val,
496 size_t len)
497{
498 return mmap_string_insert_len (string, 0, val, len);
499}
500
501MMAPString*
502mmap_string_prepend_c (MMAPString *string,
503 char c)
504{
505 return mmap_string_insert_c (string, 0, c);
506}
507
508MMAPString*
509mmap_string_insert (MMAPString *string,
510 size_t pos,
511 const char *val)
512{
513 return mmap_string_insert_len (string, pos, val, strlen(val));
514}
515
516MMAPString*
517mmap_string_insert_c (MMAPString *string,
518 size_t pos,
519 char c)
520{
521 if (mmap_string_maybe_expand (string, 1) == NULL)
522 return NULL;
523
524 /* If not just an append, move the old stuff */
525 if (pos < string->len)
526 memmove (string->str + pos + 1, string->str + pos, string->len - pos);
527
528 string->str[pos] = c;
529
530 string->len += 1;
531
532 string->str[string->len] = 0;
533
534 return string;
535}
536
537MMAPString*
538mmap_string_erase (MMAPString *string,
539 size_t pos,
540 size_t len)
541{
542 if ((pos + len) < string->len)
543 memmove (string->str + pos, string->str + pos + len,
544 string->len - (pos + len));
545
546 string->len -= len;
547
548 string->str[string->len] = 0;
549
550 return string;
551}