diff options
author | Jeffrey Stedfast <fejj@ximian.com> | 2003-06-12 04:36:06 +0800 |
---|---|---|
committer | Jeffrey Stedfast <fejj@src.gnome.org> | 2003-06-12 04:36:06 +0800 |
commit | 65672ffc09eb33c2770b72695065f6834ce5dd34 (patch) | |
tree | 35dcd4b7fd74cdcb50abc58146fb5f41b0c89667 | |
parent | 67e26bcc8e9c00520c1314c39a69a9f5457b363e (diff) | |
download | gsoc2013-evolution-65672ffc09eb33c2770b72695065f6834ce5dd34.tar.gz gsoc2013-evolution-65672ffc09eb33c2770b72695065f6834ce5dd34.tar.zst gsoc2013-evolution-65672ffc09eb33c2770b72695065f6834ce5dd34.zip |
some days you just wish you had that subatomic 100 megaton kill-o-zap bomb.
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).
svn path=/trunk/; revision=21416
-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); |