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"
50 #define MMAP_STRING_DEFAULT_CEIL (8 * 1024 * 1024)
52 #define DEFAULT_TMP_PATH "/tmp"
54 static char tmpdir[PATH_MAX] = DEFAULT_TMP_PATH;
56 static size_t mmap_string_ceil = MMAP_STRING_DEFAULT_CEIL;
58 /* MMAPString references */
60 static pthread_mutex_t mmapstring_lock = PTHREAD_MUTEX_INITIALIZER;
61 static chash * mmapstring_hashtable = NULL;
63 static void mmapstring_hashtable_init()
65 mmapstring_hashtable = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
68 void mmap_string_set_tmpdir(char * directory)
70 strncpy(tmpdir, directory, PATH_MAX);
71 tmpdir[PATH_MAX - 1] = 0;
75 int mmap_string_ref(MMAPString * string)
82 pthread_mutex_lock(&mmapstring_lock);
83 if (mmapstring_hashtable == NULL) {
84 mmapstring_hashtable_init();
86 ht = mmapstring_hashtable;
89 pthread_mutex_unlock(&mmapstring_lock);
93 key.data = &string->str;
94 key.len = sizeof(string->str);
98 r = chash_set(mmapstring_hashtable, &key, &data, NULL);
99 pthread_mutex_unlock(&mmapstring_lock);
107 int mmap_string_unref(char * str)
115 pthread_mutex_lock(&mmapstring_lock);
116 ht = mmapstring_hashtable;
119 pthread_mutex_unlock(&mmapstring_lock);
124 key.len = sizeof(str);
126 r = chash_get(ht, &key, &data);
132 if (string != NULL) {
133 chash_delete(ht, &key, NULL);
134 if (chash_count(ht) == 0) {
136 mmapstring_hashtable = NULL;
140 pthread_mutex_unlock(&mmapstring_lock);
142 if (string != NULL) {
143 mmap_string_free(string);
154 #define MY_MAXSIZE ((size_t) -1)
157 nearest_power (size_t base, size_t num)
159 if (num > MY_MAXSIZE / 2) {
172 void mmap_string_set_ceil(size_t ceil)
174 mmap_string_ceil = ceil;
180 static MMAPString * mmap_string_realloc_file(MMAPString * string)
184 if (string->fd == -1) {
185 char tmpfilename[PATH_MAX];
189 strcat(tmpfilename, tmpdir);
190 strcat(tmpfilename, "/libetpan-mmapstring-XXXXXX");
192 fd = g_mkstemp(tmpfilename);
196 if (unlink(tmpfilename) == -1) {
201 if (ftruncate(fd, string->allocated_len) == -1) {
206 data = mmap(NULL, string->allocated_len, PROT_WRITE | PROT_READ,
209 if (data == MAP_FAILED) {
214 if (string->str != NULL)
215 memcpy(data, string->str, string->len + 1);
218 string->mmapped_size = string->allocated_len;
223 if (munmap(string->str, string->mmapped_size) == -1)
226 if (ftruncate(string->fd, string->allocated_len) == -1)
229 data = mmap(NULL, string->allocated_len, PROT_WRITE | PROT_READ,
230 MAP_SHARED, string->fd, 0);
232 if (data == MAP_FAILED)
235 string->mmapped_size = string->allocated_len;
242 static MMAPString * mmap_string_realloc_memory(MMAPString * string)
246 tmp = realloc (string->str, string->allocated_len);
257 mmap_string_maybe_expand (MMAPString* string,
260 if (string->len + len >= string->allocated_len)
263 MMAPString * newstring;
265 old_size = string->allocated_len;
267 string->allocated_len = nearest_power (1, string->len + len + 1);
269 #ifndef MMAP_UNAVAILABLE
270 if (string->allocated_len > mmap_string_ceil)
271 newstring = mmap_string_realloc_file(string);
274 newstring = mmap_string_realloc_memory(string);
275 #ifndef MMAP_UNAVAILABLE
276 if (newstring == NULL)
277 newstring = mmap_string_realloc_file(string);
281 if (newstring == NULL)
282 string->allocated_len = old_size;
289 mmap_string_sized_new (size_t dfl_size)
293 string = malloc(sizeof(* string));
297 string->allocated_len = 0;
301 string->mmapped_size = 0;
303 if (mmap_string_maybe_expand (string, MAX (dfl_size, 2)) == NULL)
306 if (string->str == NULL)
309 string->str[0] = '\0';
315 mmap_string_new (const char *init)
319 string = mmap_string_sized_new (init ? strlen (init) + 2 : 2);
324 mmap_string_append (string, init);
330 mmap_string_new_len (const char *init,
336 return mmap_string_new (init);
339 string = mmap_string_sized_new (len);
342 mmap_string_append_len (string, init, len);
349 mmap_string_free (MMAPString *string)
354 if (string->fd != -1) {
355 munmap(string->str, string->mmapped_size);
365 mmap_string_assign (MMAPString *string,
368 mmap_string_truncate (string, 0);
369 if (mmap_string_append (string, rval) == NULL)
376 mmap_string_truncate (MMAPString *string,
379 string->len = MIN (len, string->len);
380 string->str[string->len] = 0;
386 * mmap_string_set_size:
387 * @string: a #MMAPString
388 * @len: the new length
390 * Sets the length of a #MMAPString. If the length is less than
391 * the current length, the string will be truncated. If the
392 * length is greater than the current length, the contents
393 * of the newly added area are undefined. (However, as
394 * always, string->str[string->len] will be a nul byte.)
396 * Return value: @string
399 mmap_string_set_size (MMAPString *string,
402 if (len >= string->allocated_len)
403 if (mmap_string_maybe_expand (string, len - string->len) == NULL)
407 string->str[len] = 0;
413 static int in_mapped_zone(MMAPString * string, char * val)
415 return (val >= string->str) && (val < string->str + string->mmapped_size);
420 mmap_string_insert_len (MMAPString *string,
425 if (mmap_string_maybe_expand (string, len) == NULL)
428 if (pos < string->len)
429 memmove (string->str + pos + len, string->str + pos, string->len - pos);
431 /* insert the new string */
432 memmove (string->str + pos, val, len);
436 string->str[string->len] = 0;
442 mmap_string_append (MMAPString *string,
445 return mmap_string_insert_len (string, string->len, val, strlen(val));
449 mmap_string_append_len (MMAPString *string,
453 return mmap_string_insert_len (string, string->len, val, len);
457 mmap_string_append_c (MMAPString *string,
460 return mmap_string_insert_c (string, string->len, c);
464 mmap_string_prepend (MMAPString *string,
467 return mmap_string_insert_len (string, 0, val, strlen(val));
471 mmap_string_prepend_len (MMAPString *string,
475 return mmap_string_insert_len (string, 0, val, len);
479 mmap_string_prepend_c (MMAPString *string,
482 return mmap_string_insert_c (string, 0, c);
486 mmap_string_insert (MMAPString *string,
490 return mmap_string_insert_len (string, pos, val, strlen(val));
494 mmap_string_insert_c (MMAPString *string,
498 if (mmap_string_maybe_expand (string, 1) == NULL)
501 /* If not just an append, move the old stuff */
502 if (pos < string->len)
503 memmove (string->str + pos + 1, string->str + pos, string->len - pos);
505 string->str[pos] = c;
509 string->str[string->len] = 0;
515 mmap_string_erase (MMAPString *string,
519 if ((pos + len) < string->len)
520 memmove (string->str + pos, string->str + pos + len,
521 string->len - (pos + len));
525 string->str[string->len] = 0;