Diffstat (limited to 'kmicromail/libetpan/tools/mmapstring.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | kmicromail/libetpan/tools/mmapstring.c | 526 |
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 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2002 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mmapstring.h" + +#include "chash.h" + +#include <stdlib.h> +#include <unistd.h> +#include <sys/mman.h> +#include <string.h> +#include <pthread.h> + +#include "libetpan-config.h" + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define MMAP_STRING_DEFAULT_CEIL (8 * 1024 * 1024) + +#define DEFAULT_TMP_PATH "/tmp" + +static char tmpdir[PATH_MAX] = DEFAULT_TMP_PATH; + +static size_t mmap_string_ceil = MMAP_STRING_DEFAULT_CEIL; + +/* MMAPString references */ + +static pthread_mutex_t mmapstring_lock = PTHREAD_MUTEX_INITIALIZER; +static chash * mmapstring_hashtable = NULL; + +static void mmapstring_hashtable_init() +{ + mmapstring_hashtable = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY); +} + +void mmap_string_set_tmpdir(char * directory) +{ + strncpy(tmpdir, directory, PATH_MAX); + tmpdir[PATH_MAX - 1] = 0; +} + + +int mmap_string_ref(MMAPString * string) +{ + chash * ht; + int r; + chashdatum key; + chashdatum data; + + pthread_mutex_lock(&mmapstring_lock); + if (mmapstring_hashtable == NULL) { + mmapstring_hashtable_init(); + } + ht = mmapstring_hashtable; + + if (ht == NULL) { + pthread_mutex_unlock(&mmapstring_lock); + return -1; + } + + key.data = &string->str; + key.len = sizeof(string->str); + data.data = string; + data.len = 0; + + r = chash_set(mmapstring_hashtable, &key, &data, NULL); + pthread_mutex_unlock(&mmapstring_lock); + + if (r < 0) + return r; + + return 0; +} + +int mmap_string_unref(char * str) +{ + MMAPString * string; + chash * ht; + chashdatum key; + chashdatum data; + int r; + + pthread_mutex_lock(&mmapstring_lock); + ht = mmapstring_hashtable; + + if (ht == NULL) { + pthread_mutex_unlock(&mmapstring_lock); + return -1; + } + + key.data = &str; + key.len = sizeof(str); + + r = chash_get(ht, &key, &data); + if (r < 0) + string = NULL; + else + string = data.data; + + if (string != NULL) { + chash_delete(ht, &key, NULL); + if (chash_count(ht) == 0) { + chash_free(ht); + mmapstring_hashtable = NULL; + } + } + + pthread_mutex_unlock(&mmapstring_lock); + + if (string != NULL) { + mmap_string_free(string); + return 0; + } + else + return -1; +} + + + +/* MMAPString */ + +#define MY_MAXSIZE ((size_t) -1) + +static inline size_t +nearest_power (size_t base, size_t num) +{ + if (num > MY_MAXSIZE / 2) { + return MY_MAXSIZE; + } + else { + size_t n = base; + + while (n < num) + n <<= 1; + + return n; + } +} + +void mmap_string_set_ceil(size_t ceil) +{ + mmap_string_ceil = ceil; +} + +/* Strings. + */ + +static MMAPString * mmap_string_realloc_file(MMAPString * string) +{ + char * data; + + if (string->fd == -1) { + char tmpfilename[PATH_MAX]; + int fd; + + * tmpfilename = 0; + strcat(tmpfilename, tmpdir); + strcat(tmpfilename, "/libetpan-mmapstring-XXXXXX"); + + fd = mkstemp(tmpfilename); + if (fd == -1) + return NULL; + + if (unlink(tmpfilename) == -1) { + close(fd); + return NULL; + } + + if (ftruncate(fd, string->allocated_len) == -1) { + close(fd); + return NULL; + } + + data = mmap(NULL, string->allocated_len, PROT_WRITE | PROT_READ, + MAP_SHARED, fd, 0); + + if (data == MAP_FAILED) { + close(fd); + return NULL; + } + + if (string->str != NULL) + memcpy(data, string->str, string->len + 1); + + string->fd = fd; + string->mmapped_size = string->allocated_len; + free(string->str); + string->str = data; + } + else { + if (munmap(string->str, string->mmapped_size) == -1) + return NULL; + + if (ftruncate(string->fd, string->allocated_len) == -1) + return NULL; + + data = mmap(NULL, string->allocated_len, PROT_WRITE | PROT_READ, + MAP_SHARED, string->fd, 0); + + if (data == MAP_FAILED) + return NULL; + + string->mmapped_size = string->allocated_len; + string->str = data; + } + + return string; +} + +static MMAPString * mmap_string_realloc_memory(MMAPString * string) +{ + char * tmp; + + tmp = realloc (string->str, string->allocated_len); + + if (tmp == NULL) + string = NULL; + else + string->str = tmp; + + return string; +} + +static MMAPString * +mmap_string_maybe_expand (MMAPString* string, + size_t len) +{ + if (string->len + len >= string->allocated_len) + { + size_t old_size; + MMAPString * newstring; + + old_size = string->allocated_len; + + string->allocated_len = nearest_power (1, string->len + len + 1); + +#ifndef MMAP_UNAVAILABLE + if (string->allocated_len > mmap_string_ceil) + newstring = mmap_string_realloc_file(string); + else { +#endif + newstring = mmap_string_realloc_memory(string); +#ifndef MMAP_UNAVAILABLE + if (newstring == NULL) + newstring = mmap_string_realloc_file(string); + } +#endif + + if (newstring == NULL) + string->allocated_len = old_size; + } + + return string; +} + +MMAPString* +mmap_string_sized_new (size_t dfl_size) +{ + MMAPString *string; + + string = malloc(sizeof(* string)); + if (string == NULL) + return NULL; + + string->allocated_len = 0; + string->len = 0; + string->str = NULL; + string->fd = -1; + string->mmapped_size = 0; + + if (mmap_string_maybe_expand (string, MAX (dfl_size, 2)) == NULL) + return NULL; + + string->str[0] = 0; + + return string; +} + +MMAPString* +mmap_string_new (const char *init) +{ + MMAPString *string; + + string = mmap_string_sized_new (init ? strlen (init) + 2 : 2); + if (string == NULL) + return NULL; + + if (init) + mmap_string_append (string, init); + + return string; +} + +MMAPString* +mmap_string_new_len (const char *init, + size_t len) +{ + MMAPString *string; + + if (len <= 0) + return mmap_string_new (init); + else + { + string = mmap_string_sized_new (len); + + if (init) + mmap_string_append_len (string, init, len); + + return string; + } +} + +void +mmap_string_free (MMAPString *string) +{ + if (string == NULL) + return; + + if (string->fd != -1) { + munmap(string->str, string->mmapped_size); + close(string->fd); + } + else { + free (string->str); + } + free(string); +} + +MMAPString* +mmap_string_assign (MMAPString *string, + const char *rval) +{ + mmap_string_truncate (string, 0); + if (mmap_string_append (string, rval) == NULL) + return NULL; + + return string; +} + +MMAPString* +mmap_string_truncate (MMAPString *string, + size_t len) +{ + string->len = MIN (len, string->len); + string->str[string->len] = 0; + + return string; +} + +/** + * mmap_string_set_size: + * @string: a #MMAPString + * @len: the new length + * + * Sets the length of a #MMAPString. If the length is less than + * the current length, the string will be truncated. If the + * length is greater than the current length, the contents + * of the newly added area are undefined. (However, as + * always, string->str[string->len] will be a nul byte.) + * + * Return value: @string + **/ +MMAPString* +mmap_string_set_size (MMAPString *string, + size_t len) +{ + if (len >= string->allocated_len) + if (mmap_string_maybe_expand (string, len - string->len) == NULL) + return NULL; + + string->len = len; + string->str[len] = 0; + + return string; +} + +/* +static int in_mapped_zone(MMAPString * string, char * val) +{ + return (val >= string->str) && (val < string->str + string->mmapped_size); +} +*/ + +MMAPString* +mmap_string_insert_len (MMAPString *string, + size_t pos, + const char *val, + size_t len) +{ + if (mmap_string_maybe_expand (string, len) == NULL) + return NULL; + + if (pos < string->len) + memmove (string->str + pos + len, string->str + pos, string->len - pos); + + /* insert the new string */ + memmove (string->str + pos, val, len); + + string->len += len; + + string->str[string->len] = 0; + + return string; +} + +MMAPString* +mmap_string_append (MMAPString *string, + const char *val) +{ + return mmap_string_insert_len (string, string->len, val, strlen(val)); +} + +MMAPString* +mmap_string_append_len (MMAPString *string, + const char *val, + size_t len) +{ + return mmap_string_insert_len (string, string->len, val, len); +} + +MMAPString* +mmap_string_append_c (MMAPString *string, + char c) +{ + return mmap_string_insert_c (string, string->len, c); +} + +MMAPString* +mmap_string_prepend (MMAPString *string, + const char *val) +{ + return mmap_string_insert_len (string, 0, val, strlen(val)); +} + +MMAPString* +mmap_string_prepend_len (MMAPString *string, + const char *val, + size_t len) +{ + return mmap_string_insert_len (string, 0, val, len); +} + +MMAPString* +mmap_string_prepend_c (MMAPString *string, + char c) +{ + return mmap_string_insert_c (string, 0, c); +} + +MMAPString* +mmap_string_insert (MMAPString *string, + size_t pos, + const char *val) +{ + return mmap_string_insert_len (string, pos, val, strlen(val)); +} + +MMAPString* +mmap_string_insert_c (MMAPString *string, + size_t pos, + char c) +{ + if (mmap_string_maybe_expand (string, 1) == NULL) + return NULL; + + /* If not just an append, move the old stuff */ + if (pos < string->len) + memmove (string->str + pos + 1, string->str + pos, string->len - pos); + + string->str[pos] = c; + + string->len += 1; + + string->str[string->len] = 0; + + return string; +} + +MMAPString* +mmap_string_erase (MMAPString *string, + size_t pos, + size_t len) +{ + if ((pos + len) < string->len) + memmove (string->str + pos, string->str + pos + len, + string->len - (pos + len)); + + string->len -= len; + + string->str[string->len] = 0; + + return string; +} |