2 * libEtPan! -- a mail stuff library
4 * Copyright (C) 2001, 2002 - DINH Viet Hoa
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
36 #include "mmapstring.h"
49 #define MAX(a, b) ((a) > (b) ? (a) : (b))
50 #define MIN(a, b) ((a) < (b) ? (a) : (b))
52 #define MMAP_STRING_DEFAULT_CEIL (8 * 1024 * 1024)
54 #define DEFAULT_TMP_PATH "/tmp"
56 static char tmpdir[PATH_MAX] = DEFAULT_TMP_PATH;
58 static size_t mmap_string_ceil = MMAP_STRING_DEFAULT_CEIL;
60 /* MMAPString references */
62 static pthread_mutex_t mmapstring_lock = PTHREAD_MUTEX_INITIALIZER;
63 static chash * mmapstring_hashtable = NULL;
65 static void mmapstring_hashtable_init()
67 mmapstring_hashtable = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
70 void mmap_string_set_tmpdir(char * directory)
72 strncpy(tmpdir, directory, PATH_MAX);
73 tmpdir[PATH_MAX - 1] = 0;
77 int mmap_string_ref(MMAPString * string)
84 pthread_mutex_lock(&mmapstring_lock);
85 if (mmapstring_hashtable == NULL) {
86 mmapstring_hashtable_init();
88 ht = mmapstring_hashtable;
91 pthread_mutex_unlock(&mmapstring_lock);
95 key.data = &string->str;
96 key.len = sizeof(string->str);
100 r = chash_set(mmapstring_hashtable, &key, &data, NULL);
101 pthread_mutex_unlock(&mmapstring_lock);
109 int mmap_string_unref(char * str)
117 pthread_mutex_lock(&mmapstring_lock);
118 ht = mmapstring_hashtable;
121 pthread_mutex_unlock(&mmapstring_lock);
126 key.len = sizeof(str);
128 r = chash_get(ht, &key, &data);
134 if (string != NULL) {
135 chash_delete(ht, &key, NULL);
136 if (chash_count(ht) == 0) {
138 mmapstring_hashtable = NULL;
142 pthread_mutex_unlock(&mmapstring_lock);
144 if (string != NULL) {
145 mmap_string_free(string);
156 #define MY_MAXSIZE ((size_t) -1)
159 nearest_power (size_t base, size_t num)
161 if (num > MY_MAXSIZE / 2) {
174 void mmap_string_set_ceil(size_t ceil)
176 mmap_string_ceil = ceil;
182 static MMAPString * mmap_string_realloc_file(MMAPString * string)
186 if (string->fd == -1) {
187 char tmpfilename[PATH_MAX];
191 strcat(tmpfilename, tmpdir);
192 strcat(tmpfilename, "/libetpan-mmapstring-XXXXXX");
194 fd = mkstemp(tmpfilename);
198 if (unlink(tmpfilename) == -1) {
203 if (ftruncate(fd, string->allocated_len) == -1) {
208 data = mmap(NULL, string->allocated_len, PROT_WRITE | PROT_READ,
211 if (data == MAP_FAILED) {
216 if (string->str != NULL)
217 memcpy(data, string->str, string->len + 1);
220 string->mmapped_size = string->allocated_len;
225 if (munmap(string->str, string->mmapped_size) == -1)
228 if (ftruncate(string->fd, string->allocated_len) == -1)
231 data = mmap(NULL, string->allocated_len, PROT_WRITE | PROT_READ,
232 MAP_SHARED, string->fd, 0);
234 if (data == MAP_FAILED)
237 string->mmapped_size = string->allocated_len;
244 static MMAPString * mmap_string_realloc_memory(MMAPString * string)
248 tmp = realloc (string->str, string->allocated_len);
259 mmap_string_maybe_expand (MMAPString* string,
262 if (string->len + len >= string->allocated_len)
265 MMAPString * newstring;
267 old_size = string->allocated_len;
269 string->allocated_len = nearest_power (1, string->len + len + 1);
271 #ifndef MMAP_UNAVAILABLE
272 if (string->allocated_len > mmap_string_ceil)
273 newstring = mmap_string_realloc_file(string);
276 newstring = mmap_string_realloc_memory(string);
277 #ifndef MMAP_UNAVAILABLE
278 if (newstring == NULL)
279 newstring = mmap_string_realloc_file(string);
283 if (newstring == NULL)
284 string->allocated_len = old_size;
291 mmap_string_sized_new (size_t dfl_size)
295 string = malloc(sizeof(* string));
299 string->allocated_len = 0;
303 string->mmapped_size = 0;
305 if (mmap_string_maybe_expand (string, MAX (dfl_size, 2)) == NULL)
314 mmap_string_new (const char *init)
318 string = mmap_string_sized_new (init ? strlen (init) + 2 : 2);
323 mmap_string_append (string, init);
329 mmap_string_new_len (const char *init,
335 return mmap_string_new (init);
338 string = mmap_string_sized_new (len);
341 mmap_string_append_len (string, init, len);
348 mmap_string_free (MMAPString *string)
353 if (string->fd != -1) {
354 munmap(string->str, string->mmapped_size);
364 mmap_string_assign (MMAPString *string,
367 mmap_string_truncate (string, 0);
368 if (mmap_string_append (string, rval) == NULL)
375 mmap_string_truncate (MMAPString *string,
378 string->len = MIN (len, string->len);
379 string->str[string->len] = 0;
385 * mmap_string_set_size:
386 * @string: a #MMAPString
387 * @len: the new length
389 * Sets the length of a #MMAPString. If the length is less than
390 * the current length, the string will be truncated. If the
391 * length is greater than the current length, the contents
392 * of the newly added area are undefined. (However, as
393 * always, string->str[string->len] will be a nul byte.)
395 * Return value: @string
398 mmap_string_set_size (MMAPString *string,
401 if (len >= string->allocated_len)
402 if (mmap_string_maybe_expand (string, len - string->len) == NULL)
406 string->str[len] = 0;
412 static int in_mapped_zone(MMAPString * string, char * val)
414 return (val >= string->str) && (val < string->str + string->mmapped_size);
419 mmap_string_insert_len (MMAPString *string,
424 if (mmap_string_maybe_expand (string, len) == NULL)
427 if (pos < string->len)
428 memmove (string->str + pos + len, string->str + pos, string->len - pos);
430 /* insert the new string */
431 memmove (string->str + pos, val, len);
435 string->str[string->len] = 0;
441 mmap_string_append (MMAPString *string,
444 return mmap_string_insert_len (string, string->len, val, strlen(val));
448 mmap_string_append_len (MMAPString *string,
452 return mmap_string_insert_len (string, string->len, val, len);
456 mmap_string_append_c (MMAPString *string,
459 return mmap_string_insert_c (string, string->len, c);
463 mmap_string_prepend (MMAPString *string,
466 return mmap_string_insert_len (string, 0, val, strlen(val));
470 mmap_string_prepend_len (MMAPString *string,
474 return mmap_string_insert_len (string, 0, val, len);
478 mmap_string_prepend_c (MMAPString *string,
481 return mmap_string_insert_c (string, 0, c);
485 mmap_string_insert (MMAPString *string,
489 return mmap_string_insert_len (string, pos, val, strlen(val));
493 mmap_string_insert_c (MMAPString *string,
497 if (mmap_string_maybe_expand (string, 1) == NULL)
500 /* If not just an append, move the old stuff */
501 if (pos < string->len)
502 memmove (string->str + pos + 1, string->str + pos, string->len - pos);
504 string->str[pos] = c;
508 string->str[string->len] = 0;
514 mmap_string_erase (MMAPString *string,
518 if ((pos + len) < string->len)
519 memmove (string->str + pos, string->str + pos + len,
520 string->len - (pos + len));
524 string->str[string->len] = 0;