summaryrefslogtreecommitdiffabout
path: root/kmicromail/libetpan/tools/mmapstring.c
Unidiff
Diffstat (limited to 'kmicromail/libetpan/tools/mmapstring.c') (more/less context) (show whitespace changes)
-rw-r--r--kmicromail/libetpan/tools/mmapstring.c526
1 files changed, 526 insertions, 0 deletions
diff --git a/kmicromail/libetpan/tools/mmapstring.c b/kmicromail/libetpan/tools/mmapstring.c
new file mode 100644
index 0000000..8c44842
--- a/dev/null
+++ b/kmicromail/libetpan/tools/mmapstring.c
@@ -0,0 +1,526 @@
1/*
2 * libEtPan! -- a mail stuff library
3 *
4 * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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#include <stdlib.h>
41#include <unistd.h>
42#include <sys/mman.h>
43#include <string.h>
44#include <pthread.h>
45
46#include "libetpan-config.h"
47
48#define MAX(a, b) ((a) > (b) ? (a) : (b))
49#define MIN(a, b) ((a) < (b) ? (a) : (b))
50
51#define MMAP_STRING_DEFAULT_CEIL (8 * 1024 * 1024)
52
53#define DEFAULT_TMP_PATH "/tmp"
54
55static char tmpdir[PATH_MAX] = DEFAULT_TMP_PATH;
56
57static size_t mmap_string_ceil = MMAP_STRING_DEFAULT_CEIL;
58
59/* MMAPString references */
60
61static pthread_mutex_t mmapstring_lock = PTHREAD_MUTEX_INITIALIZER;
62static chash * mmapstring_hashtable = NULL;
63
64static void mmapstring_hashtable_init()
65{
66 mmapstring_hashtable = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
67}
68
69void mmap_string_set_tmpdir(char * directory)
70{
71 strncpy(tmpdir, directory, PATH_MAX);
72 tmpdir[PATH_MAX - 1] = 0;
73}
74
75
76int mmap_string_ref(MMAPString * string)
77{
78 chash * ht;
79 int r;
80 chashdatum key;
81 chashdatum data;
82
83 pthread_mutex_lock(&mmapstring_lock);
84 if (mmapstring_hashtable == NULL) {
85 mmapstring_hashtable_init();
86 }
87 ht = mmapstring_hashtable;
88
89 if (ht == NULL) {
90 pthread_mutex_unlock(&mmapstring_lock);
91 return -1;
92 }
93
94 key.data = &string->str;
95 key.len = sizeof(string->str);
96 data.data = string;
97 data.len = 0;
98
99 r = chash_set(mmapstring_hashtable, &key, &data, NULL);
100 pthread_mutex_unlock(&mmapstring_lock);
101
102 if (r < 0)
103 return r;
104
105 return 0;
106}
107
108int mmap_string_unref(char * str)
109{
110 MMAPString * string;
111 chash * ht;
112 chashdatum key;
113 chashdatum data;
114 int r;
115
116 pthread_mutex_lock(&mmapstring_lock);
117 ht = mmapstring_hashtable;
118
119 if (ht == NULL) {
120 pthread_mutex_unlock(&mmapstring_lock);
121 return -1;
122 }
123
124 key.data = &str;
125 key.len = sizeof(str);
126
127 r = chash_get(ht, &key, &data);
128 if (r < 0)
129 string = NULL;
130 else
131 string = data.data;
132
133 if (string != NULL) {
134 chash_delete(ht, &key, NULL);
135 if (chash_count(ht) == 0) {
136 chash_free(ht);
137 mmapstring_hashtable = NULL;
138 }
139 }
140
141 pthread_mutex_unlock(&mmapstring_lock);
142
143 if (string != NULL) {
144 mmap_string_free(string);
145 return 0;
146 }
147 else
148 return -1;
149}
150
151
152
153/* MMAPString */
154
155#define MY_MAXSIZE ((size_t) -1)
156
157static inline size_t
158nearest_power (size_t base, size_t num)
159{
160 if (num > MY_MAXSIZE / 2) {
161 return MY_MAXSIZE;
162 }
163 else {
164 size_t n = base;
165
166 while (n < num)
167 n <<= 1;
168
169 return n;
170 }
171}
172
173void mmap_string_set_ceil(size_t ceil)
174{
175 mmap_string_ceil = ceil;
176}
177
178/* Strings.
179 */
180
181static MMAPString * mmap_string_realloc_file(MMAPString * string)
182{
183 char * data;
184
185 if (string->fd == -1) {
186 char tmpfilename[PATH_MAX];
187 int fd;
188
189 * tmpfilename = 0;
190 strcat(tmpfilename, tmpdir);
191 strcat(tmpfilename, "/libetpan-mmapstring-XXXXXX");
192
193 fd = mkstemp(tmpfilename);
194 if (fd == -1)
195 return NULL;
196
197 if (unlink(tmpfilename) == -1) {
198 close(fd);
199 return NULL;
200 }
201
202 if (ftruncate(fd, string->allocated_len) == -1) {
203 close(fd);
204 return NULL;
205 }
206
207 data = mmap(NULL, string->allocated_len, PROT_WRITE | PROT_READ,
208 MAP_SHARED, fd, 0);
209
210 if (data == MAP_FAILED) {
211 close(fd);
212 return NULL;
213 }
214
215 if (string->str != NULL)
216 memcpy(data, string->str, string->len + 1);
217
218 string->fd = fd;
219 string->mmapped_size = string->allocated_len;
220 free(string->str);
221 string->str = data;
222 }
223 else {
224 if (munmap(string->str, string->mmapped_size) == -1)
225 return NULL;
226
227 if (ftruncate(string->fd, string->allocated_len) == -1)
228 return NULL;
229
230 data = mmap(NULL, string->allocated_len, PROT_WRITE | PROT_READ,
231 MAP_SHARED, string->fd, 0);
232
233 if (data == MAP_FAILED)
234 return NULL;
235
236 string->mmapped_size = string->allocated_len;
237 string->str = data;
238 }
239
240 return string;
241}
242
243static MMAPString * mmap_string_realloc_memory(MMAPString * string)
244{
245 char * tmp;
246
247 tmp = realloc (string->str, string->allocated_len);
248
249 if (tmp == NULL)
250 string = NULL;
251 else
252 string->str = tmp;
253
254 return string;
255}
256
257static MMAPString *
258mmap_string_maybe_expand (MMAPString* string,
259 size_t len)
260{
261 if (string->len + len >= string->allocated_len)
262 {
263 size_t old_size;
264 MMAPString * newstring;
265
266 old_size = string->allocated_len;
267
268 string->allocated_len = nearest_power (1, string->len + len + 1);
269
270#ifndef MMAP_UNAVAILABLE
271 if (string->allocated_len > mmap_string_ceil)
272 newstring = mmap_string_realloc_file(string);
273 else {
274#endif
275 newstring = mmap_string_realloc_memory(string);
276#ifndef MMAP_UNAVAILABLE
277 if (newstring == NULL)
278 newstring = mmap_string_realloc_file(string);
279 }
280#endif
281
282 if (newstring == NULL)
283 string->allocated_len = old_size;
284 }
285
286 return string;
287}
288
289MMAPString*
290mmap_string_sized_new (size_t dfl_size)
291{
292 MMAPString *string;
293
294 string = malloc(sizeof(* string));
295 if (string == NULL)
296 return NULL;
297
298 string->allocated_len = 0;
299 string->len = 0;
300 string->str = NULL;
301 string->fd = -1;
302 string->mmapped_size = 0;
303
304 if (mmap_string_maybe_expand (string, MAX (dfl_size, 2)) == NULL)
305 return NULL;
306
307 string->str[0] = 0;
308
309 return string;
310}
311
312MMAPString*
313mmap_string_new (const char *init)
314{
315 MMAPString *string;
316
317 string = mmap_string_sized_new (init ? strlen (init) + 2 : 2);
318 if (string == NULL)
319 return NULL;
320
321 if (init)
322 mmap_string_append (string, init);
323
324 return string;
325}
326
327MMAPString*
328mmap_string_new_len (const char *init,
329 size_t len)
330{
331 MMAPString *string;
332
333 if (len <= 0)
334 return mmap_string_new (init);
335 else
336 {
337 string = mmap_string_sized_new (len);
338
339 if (init)
340 mmap_string_append_len (string, init, len);
341
342 return string;
343 }
344}
345
346void
347mmap_string_free (MMAPString *string)
348{
349 if (string == NULL)
350 return;
351
352 if (string->fd != -1) {
353 munmap(string->str, string->mmapped_size);
354 close(string->fd);
355 }
356 else {
357 free (string->str);
358 }
359 free(string);
360}
361
362MMAPString*
363mmap_string_assign (MMAPString *string,
364 const char *rval)
365{
366 mmap_string_truncate (string, 0);
367 if (mmap_string_append (string, rval) == NULL)
368 return NULL;
369
370 return string;
371}
372
373MMAPString*
374mmap_string_truncate (MMAPString *string,
375 size_t len)
376{
377 string->len = MIN (len, string->len);
378 string->str[string->len] = 0;
379
380 return string;
381}
382
383/**
384 * mmap_string_set_size:
385 * @string: a #MMAPString
386 * @len: the new length
387 *
388 * Sets the length of a #MMAPString. If the length is less than
389 * the current length, the string will be truncated. If the
390 * length is greater than the current length, the contents
391 * of the newly added area are undefined. (However, as
392 * always, string->str[string->len] will be a nul byte.)
393 *
394 * Return value: @string
395 **/
396MMAPString*
397mmap_string_set_size (MMAPString *string,
398 size_t len)
399{
400 if (len >= string->allocated_len)
401 if (mmap_string_maybe_expand (string, len - string->len) == NULL)
402 return NULL;
403
404 string->len = len;
405 string->str[len] = 0;
406
407 return string;
408}
409
410/*
411static int in_mapped_zone(MMAPString * string, char * val)
412{
413 return (val >= string->str) && (val < string->str + string->mmapped_size);
414}
415*/
416
417MMAPString*
418mmap_string_insert_len (MMAPString *string,
419 size_t pos,
420 const char *val,
421 size_t len)
422{
423 if (mmap_string_maybe_expand (string, len) == NULL)
424 return NULL;
425
426 if (pos < string->len)
427 memmove (string->str + pos + len, string->str + pos, string->len - pos);
428
429 /* insert the new string */
430 memmove (string->str + pos, val, len);
431
432 string->len += len;
433
434 string->str[string->len] = 0;
435
436 return string;
437}
438
439MMAPString*
440mmap_string_append (MMAPString *string,
441 const char *val)
442{
443 return mmap_string_insert_len (string, string->len, val, strlen(val));
444}
445
446MMAPString*
447 mmap_string_append_len (MMAPString *string,
448 const char *val,
449 size_t len)
450{
451 return mmap_string_insert_len (string, string->len, val, len);
452}
453
454MMAPString*
455mmap_string_append_c (MMAPString *string,
456 char c)
457{
458 return mmap_string_insert_c (string, string->len, c);
459}
460
461MMAPString*
462mmap_string_prepend (MMAPString *string,
463 const char *val)
464{
465 return mmap_string_insert_len (string, 0, val, strlen(val));
466}
467
468MMAPString*
469 mmap_string_prepend_len (MMAPString *string,
470 const char *val,
471 size_t len)
472{
473 return mmap_string_insert_len (string, 0, val, len);
474}
475
476MMAPString*
477mmap_string_prepend_c (MMAPString *string,
478 char c)
479{
480 return mmap_string_insert_c (string, 0, c);
481}
482
483MMAPString*
484mmap_string_insert (MMAPString *string,
485 size_t pos,
486 const char *val)
487{
488 return mmap_string_insert_len (string, pos, val, strlen(val));
489}
490
491MMAPString*
492mmap_string_insert_c (MMAPString *string,
493 size_t pos,
494 char c)
495{
496 if (mmap_string_maybe_expand (string, 1) == NULL)
497 return NULL;
498
499 /* If not just an append, move the old stuff */
500 if (pos < string->len)
501 memmove (string->str + pos + 1, string->str + pos, string->len - pos);
502
503 string->str[pos] = c;
504
505 string->len += 1;
506
507 string->str[string->len] = 0;
508
509 return string;
510}
511
512MMAPString*
513mmap_string_erase (MMAPString *string,
514 size_t pos,
515 size_t len)
516{
517 if ((pos + len) < string->len)
518 memmove (string->str + pos, string->str + pos + len,
519 string->len - (pos + len));
520
521 string->len -= len;
522
523 string->str[string->len] = 0;
524
525 return string;
526}