diff options
Diffstat (limited to 'camel')
-rw-r--r-- | camel/ChangeLog | 20 | ||||
-rw-r--r-- | camel/Makefile.am | 2 | ||||
-rw-r--r-- | camel/camel-io.c | 4 | ||||
-rw-r--r-- | camel/camel-uid-cache.c | 173 | ||||
-rw-r--r-- | camel/camel-uid-cache.h | 10 |
5 files changed, 155 insertions, 54 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog index 43eab8d580..62dd624984 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,23 @@ +2003-06-04 Jeffrey Stedfast <fejj@ximian.com> + + * camel-uid-cache.c (camel_uid_cache_new): Create the directory + with mode 0777 and the cache file itself with mode 0666. Let the + user's umask filter the permissions. Instead of saving the fd on + the Cache object, instead save the filename. Use camel_read() + instead of expecting read() to just always work without getting an + EINTR/etc. + (maybe_write_uid): Don't do anything if cache->fd == -1, this + means an error has occured in a previous callback. Replace the 2 + calls to write() with camel_write() and check their return + values. If either of them fails, set cache->fd to -1 (GHashTable + doesn't give us a way to abort foreach'ing thru the table). + (camel_uid_cache_save): Save to a temp file instead of overwriting + the original. Do proper error checking, etc. Also added some + smarts about whether to try and overwrite the old cache even if we + haven't successfully saved all the uids in the cache. + (camel_uid_cache_destroy): Free the cache->filename, no longer + need to close (cache->fd). + 2003-06-11 Larry Ewing <lewing@ximian.com> * camel-text-index.c (text_index_normalise): use g_utf8_strdown properly. diff --git a/camel/Makefile.am b/camel/Makefile.am index 099f370e0a..5599b93008 100644 --- a/camel/Makefile.am +++ b/camel/Makefile.am @@ -49,6 +49,7 @@ libcamel_la_SOURCES = \ camel-http-stream.c \ camel-index.c \ camel-internet-address.c \ + camel-io.c \ camel-lock.c \ camel-lock-client.c \ camel-medium.c \ @@ -150,6 +151,7 @@ libcamelinclude_HEADERS = \ camel-http-stream.h \ camel-index.h \ camel-internet-address.h \ + camel-io.h \ camel-i18n.h \ camel-lock.h \ camel-lock-client.h \ diff --git a/camel/camel-io.c b/camel/camel-io.c index 88ddcf692d..df831162ba 100644 --- a/camel/camel-io.c +++ b/camel/camel-io.c @@ -35,6 +35,10 @@ #include "camel-operation.h" +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + /* FIXME: should we trade out select() for a poll() instead? */ ssize_t diff --git a/camel/camel-uid-cache.c b/camel/camel-uid-cache.c index a1dc7c660b..5bb616b304 100644 --- a/camel/camel-uid-cache.c +++ b/camel/camel-uid-cache.c @@ -32,6 +32,8 @@ #include <sys/stat.h> #include <unistd.h> +#include "camel-io.h" +#include "camel-store.h" /* for camel_mkdir_hier */ #include "camel-uid-cache.h" struct _uid_state { @@ -39,33 +41,6 @@ struct _uid_state { gboolean save; }; -static void free_uid (gpointer key, gpointer value, gpointer data); -static void maybe_write_uid (gpointer key, gpointer value, gpointer data); - - -static int -mkdir_heir (const char *path, mode_t mode) -{ - char *copy, *p; - - p = copy = g_strdup (path); - do { - p = strchr (p + 1, '/'); - if (p) - *p = '\0'; - if (access (copy, F_OK) == -1) { - if (mkdir (copy, mode) == -1) { - g_free (copy); - return -1; - } - } - if (p) - *p = '/'; - } while (p); - - g_free (copy); - return 0; -} /** * camel_uid_cache_new: @@ -86,30 +61,40 @@ camel_uid_cache_new (const char *filename) int fd, i; dirname = g_path_get_dirname (filename); - mkdir_heir (dirname, 0700); + if (camel_mkdir_hier (dirname, 0777) == -1) { + g_free (dirname); + return NULL; + } + g_free (dirname); - fd = open (filename, O_RDWR | O_CREAT, 0700); - if (fd == -1) + if ((fd = open (filename, O_RDONLY | O_CREAT, 0666)) == -1) return NULL; - if (fstat (fd, &st) != 0) { + if (fstat (fd, &st) == -1) { close (fd); return NULL; } + buf = g_malloc (st.st_size + 1); - if (read (fd, buf, st.st_size) == -1) { + if (st.st_size > 0 && camel_read (fd, buf, st.st_size) == -1) { close (fd); g_free (buf); return NULL; } + buf[st.st_size] = '\0'; + close (fd); + cache = g_new (CamelUIDCache, 1); - cache->fd = fd; - cache->level = 1; cache->uids = g_hash_table_new (g_str_hash, g_str_equal); + cache->filename = g_strdup (filename); + cache->level = 1; + cache->expired = 0; + cache->size = 0; + cache->fd = -1; uids = g_strsplit (buf, "\n", 0); g_free (buf); @@ -122,11 +107,37 @@ camel_uid_cache_new (const char *filename) g_hash_table_insert (cache->uids, uids[i], state); } + g_free (uids); return cache; } + +static void +maybe_write_uid (gpointer key, gpointer value, gpointer data) +{ + CamelUIDCache *cache = data; + struct _uid_state *state = value; + + if (cache->fd == -1) + return; + + if (state && state->level == cache->level && state->save) { + if (camel_write (cache->fd, key, strlen (key)) == -1 || + camel_write (cache->fd, "\n", 1) == -1) { + cache->fd = -1; + } else { + cache->size += strlen (key) + 1; + } + } else { + /* keep track of how much space the expired uids would + * have taken up in the cache */ + cache->expired += strlen (key) + 1; + } +} + + /** * camel_uid_cache_save: * @cache: a CamelUIDCache @@ -138,22 +149,87 @@ camel_uid_cache_new (const char *filename) gboolean camel_uid_cache_save (CamelUIDCache *cache) { - if (lseek (cache->fd, 0, SEEK_SET) != 0) + struct stat st; + char *filename; + int errnosav; + int fd; + + filename = g_strdup_printf ("%s~", cache->filename); + if ((fd = open (filename, O_WRONLY | O_CREAT | O_EXCL, 0666)) == -1) { + g_free (filename); return FALSE; + } + + cache->fd = fd; + cache->size = 0; + cache->expired = 0; g_hash_table_foreach (cache->uids, maybe_write_uid, cache); - return ftruncate (cache->fd, lseek (cache->fd, 0, SEEK_CUR)) == 0; + + if (cache->fd == -1) + goto exception; + + overwrite: + if (fsync (fd) == -1) + goto exception; + + close (fd); + fd = -1; + + if (rename (filename, cache->filename) == -1) + goto exception; + + g_free (filename); + + return TRUE; + + exception: + + errnosav = errno; + +#ifdef ENABLE_SPASMOLYTIC + if (fd != -1) { + /** + * If our new cache size is larger than the old cache, + * even if we haven't finished writing it out + * successfully, we should still attempt to replace + * the old cache with the new cache because it will at + * least avoid re-downloading a few extra messages + * than if we just kept the old cache. + * + * Similarly, even if the new cache size is smaller + * than the old cache size, but we've expired enough + * uids to make up for the difference in size (or + * more), then we should replace the old cache with + * the new cache as well. + **/ + + if (stat (cache->filename, &st) == 0 && + (cache->size > st.st_size || cache->size + cache->expired > st.st_size)) { + if (ftruncate (fd, (off_t) cache->size) != -1) { + cache->size = 0; + cache->expired = 0; + goto overwrite; + } + } + + close (fd); + } +#endif + + unlink (filename); + g_free (filename); + + errno = errnosav; + + return FALSE; } + static void -maybe_write_uid (gpointer key, gpointer value, gpointer data) +free_uid (gpointer key, gpointer value, gpointer data) { - CamelUIDCache *cache = data; - struct _uid_state *state = value; - - if (state && state->level == cache->level && state->save) { - write (cache->fd, key, strlen (key)); - write (cache->fd, "\n", 1); - } + g_free (key); + g_free (value); } @@ -168,17 +244,10 @@ camel_uid_cache_destroy (CamelUIDCache *cache) { g_hash_table_foreach (cache->uids, free_uid, NULL); g_hash_table_destroy (cache->uids); - close (cache->fd); + g_free (cache->filename); g_free (cache); } -static void -free_uid (gpointer key, gpointer value, gpointer data) -{ - g_free (key); - g_free (value); -} - /** * camel_uid_cache_get_new_uids: diff --git a/camel/camel-uid-cache.h b/camel/camel-uid-cache.h index e4327c9b12..37d90c89e6 100644 --- a/camel/camel-uid-cache.h +++ b/camel/camel-uid-cache.h @@ -30,12 +30,18 @@ extern "C" { #pragma } #endif /* __cplusplus */ -#include <stdio.h> #include <glib.h> +#include <stdio.h> +#include <sys/types.h> + typedef struct { - int fd, level; + char *filename; GHashTable *uids; + unsigned int level; + size_t expired; + size_t size; + int fd; } CamelUIDCache; CamelUIDCache *camel_uid_cache_new (const char *filename); |