Fix ordering in perl subscription_list
[blerg.git] / common / stringbucket.c
index d892541..86efff3 100644 (file)
@@ -8,6 +8,7 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <string.h>
 #include <stringbucket.h>
 
@@ -24,38 +25,76 @@ const char * strnchr(const char *s, int c, int n) {
        return NULL;
 }
 
-struct stringbucket * stringbucket_open(const char *filename) {
+int stringbucket_remap(struct stringbucket *sb) {
        struct stat st;
+
+       if (sb->list != NULL) {
+               munmap(sb->list, sb->size);
+       }
+
+       flock(sb->fd, LOCK_SH);
+       fstat(sb->fd, &st);
+       flock(sb->fd, LOCK_UN);
+       sb->size = st.st_size;
+       if (sb->size > 0) {
+               sb->list = mmap(NULL, sb->size, PROT_READ | PROT_WRITE, MAP_SHARED, sb->fd, 0);
+               if (sb->list == MAP_FAILED) {
+                       perror("stringbucket mmap");
+                       return 0;
+               }
+       } else {
+               /* Don't map anything for now. */
+               sb->list = NULL;
+       }
+
+       return 1;
+}
+
+struct stringbucket * stringbucket_open(const char *filename) {
        struct stringbucket *obj = malloc(sizeof(struct stringbucket));
+       obj->list = NULL;
+       obj->size = 0;
 
        if (obj == NULL) {
                perror("stringbucket allocate");
-               return NULL;
+               goto stringbucket_open__malloc_fail;
        }
 
        obj->fd = open(filename, O_RDWR | O_APPEND | O_CREAT, 0600);
-       flock(obj->fd, LOCK_SH);
-       fstat(obj->fd, &st);
-       flock(obj->fd, LOCK_UN);
-       obj->size = st.st_size;
-       obj->list = mmap(NULL, obj->size, PROT_READ | PROT_WRITE, MAP_SHARED, obj->fd, 0);
-       if (obj->list == NULL) {
-               perror("stringbucket mmap");
-               close(obj->fd);
-               free(obj);
-               return 0;
+       if (obj->fd == -1) {
+               perror("stringbucket open");
+               goto stringbucket_open__open_fail;
+       }
+
+       if (stringbucket_remap(obj) == 0) {
+               goto stringbucket_open__mmap_fail;
        }
 
        return obj;
+
+stringbucket_open__mmap_fail:
+       close(obj->fd);
+stringbucket_open__open_fail:
+       free(obj);
+stringbucket_open__malloc_fail:
+       return NULL;
 }
 
 void stringbucket_close(struct stringbucket *sb) {
-       munmap(sb->list, sb->size);
+       if (sb == NULL)
+               return;
+
+       if (sb->list != NULL)
+               munmap(sb->list, sb->size);
+
        close(sb->fd);
        free(sb);
 }
 
 int stringbucket_find(struct stringbucket *sb, const char *string) {
+       if (sb->list == NULL)
+               return  -1;
+
        char * end = sb->list + sb->size;
        int string_len = strlen(string);
 
@@ -78,11 +117,32 @@ int stringbucket_find(struct stringbucket *sb, const char *string) {
 
 int stringbucket_add(struct stringbucket *sb, const char *string) {
        if (stringbucket_find(sb, string) != -1) return 0;
+       int str_len = strlen(string);
+       int len;
+
        flock(sb->fd, LOCK_EX);
-       write(sb->fd, string, strlen(string));
-       write(sb->fd, "\n", 1);
+       len = write(sb->fd, string, str_len);
+       if (len < 0)
+               perror("stringbucket add");
+       if (len < str_len)
+               goto stringbucket_add__fail;
+       len = write(sb->fd, "\n", 1);
+       if (len < 0)
+               perror("stringbucket add");
+       if (len == 0)
+               goto stringbucket_add__fail;
        flock(sb->fd, LOCK_UN);
+
+       /* remap the data to include added content */
+       if (stringbucket_remap(sb) == 0)
+               return 0;
+
        return 1;
+
+stringbucket_add__fail:
+       ftruncate(sb->fd, sb->size);
+       flock(sb->fd, LOCK_UN);
+       return 0;
 }
 
 int stringbucket_delete(struct stringbucket *sb, const char *string) {
@@ -91,9 +151,13 @@ int stringbucket_delete(struct stringbucket *sb, const char *string) {
 
        /* We doin' it DOS style! */
        sb->list[pos] = 0;
+       return 1;
 }
 
 void stringbucket_iterate(struct stringbucket *sb, void (*iter)(char *, void *), void *stuff) {
+       if (sb->list == NULL)
+               return;
+
        char string[STRINGBUCKET_STRINGSIZE + 1];
        char * ptr = sb->list;
        char * end = sb->list + sb->size;