Mercurial > dovecot > original-hg > dovecot-1.2
changeset 175:73bf05a1d862 HEAD
Moved custom flags handling into lib-index.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 08 Sep 2002 02:31:56 +0300 |
parents | 61b0bb62b42e |
children | 782a0d4baa71 |
files | configure.in src/lib-index/Makefile.am src/lib-index/mail-custom-flags.c src/lib-index/mail-custom-flags.h src/lib-index/mail-index.c src/lib-index/mail-index.h src/lib-storage/Makefile.am src/lib-storage/flags-file/.cvsignore src/lib-storage/flags-file/Makefile.am src/lib-storage/flags-file/flags-file.c src/lib-storage/flags-file/flags-file.h src/lib-storage/index/index-copy.c src/lib-storage/index/index-fetch.c src/lib-storage/index/index-status.c src/lib-storage/index/index-storage.c src/lib-storage/index/index-storage.h src/lib-storage/index/index-sync.c src/lib-storage/index/index-update-flags.c src/lib-storage/index/maildir/maildir-save.c src/lib-storage/index/mbox/mbox-save.c src/lib-storage/index/mbox/mbox-storage.c |
diffstat | 21 files changed, 619 insertions(+), 625 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.in Sat Sep 07 22:01:14 2002 +0300 +++ b/configure.in Sun Sep 08 02:31:56 2002 +0300 @@ -335,7 +335,6 @@ src/lib-storage/index/maildir/Makefile src/lib-storage/index/mbox/Makefile src/lib-storage/subscription-file/Makefile -src/lib-storage/flags-file/Makefile src/auth/Makefile src/imap/Makefile src/login/Makefile
--- a/src/lib-index/Makefile.am Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-index/Makefile.am Sun Sep 08 02:31:56 2002 +0300 @@ -8,6 +8,7 @@ -I$(top_srcdir)/src/lib-imap libstorage_index_a_SOURCES = \ + mail-custom-flags.c \ mail-hash.c \ mail-index.c \ mail-index-compress.c \ @@ -20,6 +21,7 @@ mail-modifylog.c noinst_HEADERS = \ + mail-custom-flags.h \ mail-hash.h \ mail-index.h \ mail-index-data.h \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-index/mail-custom-flags.c Sun Sep 08 02:31:56 2002 +0300 @@ -0,0 +1,534 @@ +/* Copyright (C) 2002 Timo Sirainen */ + +#include "lib.h" +#include "mmap-util.h" +#include "write-full.h" +#include "imap-util.h" +#include "mail-index.h" +#include "mail-index-util.h" +#include "mail-custom-flags.h" + +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> + +/* Header is simply a counter which is increased every time the file is + updated. This allows other processes to easily notice if there's been + any changes. */ + +#define COUNTER_SIZE 4 +#define HEADER_SIZE (COUNTER_SIZE + 1) /* 0000\n */ + +struct _MailCustomFlags { + MailIndex *index; + char *path; + int fd; + int lock_type; + + char sync_counter[COUNTER_SIZE]; + char *custom_flags[MAIL_CUSTOM_FLAGS_COUNT]; + int custom_flags_refcount; + + void *mmap_base; + size_t mmap_length; + + unsigned int syncing:1; +}; + +static int lock_file(MailCustomFlags *mcf, int type); + +static int update_mmap(MailCustomFlags *mcf) +{ + mcf->mmap_base = mmap_rw_file(mcf->fd, &mcf->mmap_length); + if (mcf->mmap_base == MAP_FAILED) { + mcf->mmap_base = NULL; + index_set_error(mcf->index, "mmap() failed for " + "custom flags file %s: %m", mcf->path); + return FALSE; + } + + (void)madvise(mcf->mmap_base, mcf->mmap_length, MADV_SEQUENTIAL); + return TRUE; +} + +static int custom_flags_init(MailCustomFlags *mcf) +{ + static char buf[HEADER_SIZE] = "0000\n"; + off_t pos; + + if (!lock_file(mcf, F_WRLCK)) + return FALSE; + + /* make sure it's still empty after locking */ + pos = lseek(mcf->fd, 0, SEEK_END); + if (pos != -1 && pos < HEADER_SIZE) + pos = lseek(mcf->fd, 0, SEEK_SET); + + if (pos == -1) { + index_set_error(mcf->index, "lseek() failed for " + "custom flags file %s: %m", mcf->path); + return FALSE; + } + + /* write the header - it's a 4 byte counter as hex */ + if (write_full(mcf->fd, buf, HEADER_SIZE) < 0) { + index_set_error(mcf->index, "write() failed for " + "custom flags file %s: %m", mcf->path); + return FALSE; + } + + if (!lock_file(mcf, F_UNLCK)) + return FALSE; + + return TRUE; +} + +static void custom_flags_sync(MailCustomFlags *mcf) +{ + char *data, *data_end, *line; + unsigned int num; + int i; + + memcpy(mcf->sync_counter, mcf->mmap_base, COUNTER_SIZE); + + for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) { + if (mcf->custom_flags[i] != NULL) { + i_free(mcf->custom_flags[i]); + mcf->custom_flags[i] = NULL; + } + } + + data = mcf->mmap_base; + data_end = data + mcf->mmap_length; + + /* this loop skips the first line, which is the header */ + while (data != data_end) { + if (*data != '\n') { + data++; + continue; + } + + /* beginning of line, get the index */ + if (data+1 == data_end) + break; + data++; + + if (!i_isdigit(*data)) + continue; + + num = 0; + while (data != data_end && *data >= '0' && *data <= '9') { + num = num*10 + (*data-'0'); + data++; + } + + if (num < MAIL_CUSTOM_FLAGS_COUNT) { + /* get the name */ + if (data == data_end || *data != ' ') + continue; + + line = ++data; + while (data != data_end && *data != '\n') + data++; + + if (mcf->custom_flags[num] != NULL) { + i_warning("Error in custom flags file %s: " + "Duplicated ID %u", mcf->path, num); + i_free(mcf->custom_flags[num]); + } + + mcf->custom_flags[num] = i_strdup_until(line, data); + } + } +} + +static int custom_flags_check_sync(MailCustomFlags *mcf) +{ + if (mcf->custom_flags_refcount > 0) { + /* we've been locked from updates for now.. */ + return TRUE; + } + + if (mcf->mmap_length != 0 && + memcmp(mcf->sync_counter, mcf->mmap_base, COUNTER_SIZE) == 0) + return TRUE; + + /* file modified, resync */ + if (!update_mmap(mcf)) + return FALSE; + + if (mcf->mmap_length < HEADER_SIZE) { + /* it's broken, rewrite header */ + if (mcf->lock_type == F_RDLCK) + (void)lock_file(mcf, F_UNLCK); + + if (!custom_flags_init(mcf)) + return FALSE; + + if (!update_mmap(mcf)) + return FALSE; + } + + custom_flags_sync(mcf); + return TRUE; +} + +static int lock_file(MailCustomFlags *mcf, int type) +{ + struct flock fl; + + if (mcf->lock_type == type) + return TRUE; + + /* lock whole file */ + fl.l_type = type; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + + while (fcntl(mcf->fd, F_SETLKW, &fl) == -1) { + if (errno != EINTR) { + index_set_error(mcf->index, "fcntl() failed for " + "custom flags file %s: %m", mcf->path); + return FALSE; + } + } + + mcf->lock_type = type; + + if (type != F_UNLCK && !mcf->syncing) { + mcf->syncing = TRUE; + if (!custom_flags_check_sync(mcf)) { + mcf->syncing = FALSE; + return FALSE; + } + + /* syncing may have changed locking, do it again */ + if (!lock_file(mcf, type)) { + mcf->syncing = FALSE; + return FALSE; + } + + mcf->syncing = FALSE; + } + return TRUE; +} + +int mail_custom_flags_open_or_create(MailIndex *index) +{ + MailCustomFlags *mcf; + const char *path; + int fd; + + path = t_strconcat(index->dir, CUSTOM_FLAGS_FILE_NAME, NULL); + fd = open(path, O_RDWR | O_CREAT, 0660); + if (fd == -1) { + index_set_error(index, "Can't open custom flags file %s: %m", + path); + return FALSE; + } + + mcf = i_new(MailCustomFlags, 1); + mcf->index = index; + mcf->path = i_strdup(path); + mcf->fd = fd; + + if (!update_mmap(mcf)) { + mail_custom_flags_free(mcf); + return FALSE; + } + + if (mcf->mmap_length < HEADER_SIZE) { + /* we just created it, write the header */ + mcf->syncing = TRUE; + if (!custom_flags_init(mcf) || !update_mmap(mcf)) { + mail_custom_flags_free(mcf); + return FALSE; + } + mcf->syncing = FALSE; + } + + custom_flags_sync(mcf); + + index->custom_flags = mcf; + return TRUE; +} + +void mail_custom_flags_free(MailCustomFlags *mcf) +{ + int i; + + for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) + i_free(mcf->custom_flags[i]); + + (void)munmap(mcf->mmap_base, mcf->mmap_length); + (void)close(mcf->fd); + + i_free(mcf->path); + i_free(mcf); +} + +static int custom_flags_update_counter(MailCustomFlags *mcf) +{ + int i; + + if (lseek(mcf->fd, 0, SEEK_SET) == -1) { + index_set_error(mcf->index, "lseek() failed for " + "custom flags file %s: %m", mcf->path); + return FALSE; + } + + for (i = COUNTER_SIZE-1; i >= 0; i--) { + if (mcf->sync_counter[i] == '9') { + mcf->sync_counter[i] = 'A'; + break; + } + + if (mcf->sync_counter[i] == 'F') { + /* digit wrapped, update next one */ + mcf->sync_counter[i] = '0'; + } else { + mcf->sync_counter[i]++; + break; + } + } + + if (write_full(mcf->fd, mcf->sync_counter, COUNTER_SIZE) < 0) { + index_set_error(mcf->index, "write() failed for " + "custom flags file %s: %m", mcf->path); + return FALSE; + } + + return TRUE; +} + +static int custom_flags_add(MailCustomFlags *mcf, int idx, const char *name) +{ + const char *buf; + unsigned int len; + off_t pos; + + i_assert(idx < MAIL_CUSTOM_FLAGS_COUNT); + + /* first update the sync counter */ + if (!custom_flags_update_counter(mcf)) + return FALSE; + + /* add the flag */ + pos = lseek(mcf->fd, 0, SEEK_END); + if (pos == -1) { + index_set_error(mcf->index, "lseek() failed for " + "custom flags file %s: %m", mcf->path); + return FALSE; + } + + if (pos != (off_t)mcf->mmap_length) { + index_set_error(mcf->index, "custom flags file %s was " + "changed by someone while we were" + "trying to modify it", mcf->path); + return FALSE; + } + + buf = t_strdup_printf("\n%d %s\n", idx, name); + len = strlen(buf); + + if (((char *) mcf->mmap_base)[mcf->mmap_length-1] == '\n') { + /* don't add the \n prefix */ + buf++; + len--; + } + + if (write_full(mcf->fd, buf, len) < 0) { + index_set_error(mcf->index, "write() failed for " + "custom flags file %s: %m", mcf->path); + return FALSE; + } + + if (!update_mmap(mcf)) + return FALSE; + + return TRUE; +} + +static int custom_flags_remove(MailCustomFlags *mcf, unsigned int idx) +{ + char *data, *data_end, *line; + unsigned int num; + int pos, linelen; + + data = mcf->mmap_base; + data_end = data + mcf->mmap_length; + + while (data != data_end) { + if (*data != '\n') { + data++; + continue; + } + + /* beginning of line, get the index */ + if (data+1 == data_end) + break; + line = ++data; + + num = 0; + while (data != data_end && *data >= '0' && *data <= '9') { + num = num*10 + (*data-'0'); + data++; + } + + if (num == idx) { + /* remove this line */ + while (data != data_end && data[-1] != '\n') + data++; + + linelen = (int) (data - line); + pos = (int) (data - (char *) mcf->mmap_base); + memmove(line, data, mcf->mmap_length - pos); + + mcf->mmap_length -= linelen; + if (ftruncate(mcf->fd, (off_t) mcf->mmap_length) == -1) { + index_set_error(mcf->index, + "ftruncate() failed for " + "custom flags file %s: %m", + mcf->path); + return FALSE; + } + + return TRUE; + } + } + + return FALSE; +} + +static int find_first_unused_flag(MailCustomFlags *mcf) +{ + int i; + + for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) { + if (mcf->custom_flags[i] == NULL) + return i; + } + + return -1; +} + +static void remove_unused_custom_flags(MailCustomFlags *mcf, + MailFlags used_flags) +{ + unsigned int i; + + for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) { + if ((used_flags & (1 << (i + MAIL_CUSTOM_FLAG_1_BIT))) == 0) { + i_free(mcf->custom_flags[i]); + mcf->custom_flags[i] = NULL; + + custom_flags_remove(mcf, i); + } + } +} + +static MailFlags get_used_flags(MailCustomFlags *mcf) +{ + MailIndexRecord *rec; + MailFlags used_flags; + + used_flags = 0; + + rec = mcf->index->lookup(mcf->index, 1); + while (rec != NULL) { + used_flags |= rec->msg_flags; + rec = mcf->index->next(mcf->index, rec); + } + + return used_flags; +} + +static int get_flag_index(MailCustomFlags *mcf, const char *flag) +{ + int i, first_empty; + + /* check existing flags */ + for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) { + if (mcf->custom_flags[i] == NULL) + continue; + + i_assert(mcf->custom_flags[i] != '\0'); + if (strcasecmp(mcf->custom_flags[i], flag) == 0) + return i; + } + + /* unlock + write lock, don't directly change from read -> write lock + to prevent deadlocking */ + if (!lock_file(mcf, F_UNLCK) || !lock_file(mcf, F_WRLCK)) + return -1; + + /* new flag, add it. first find the first free flag, note that + unlock+lock might have just changed it. */ + first_empty = find_first_unused_flag(mcf); + if (first_empty == -1) { + /* all custom flags are used, see if some of them are unused */ + remove_unused_custom_flags(mcf, get_used_flags(mcf)); + + first_empty = find_first_unused_flag(mcf); + if (first_empty == -1) { + /* everything is in use */ + return -1; + } + } + + if (!custom_flags_add(mcf, first_empty, flag)) + return -1; + + mcf->custom_flags[first_empty] = i_strdup(flag); + return first_empty; +} + +int mail_custom_flags_fix_list(MailCustomFlags *mcf, MailFlags *flags, + const char *custom_flags[]) +{ + MailFlags oldflags, flag; + int i, idx; + + if ((*flags & MAIL_CUSTOM_FLAGS_MASK) == 0) + return 1; + + if (!lock_file(mcf, F_RDLCK)) + return -1; + + oldflags = *flags; + *flags &= MAIL_SYSTEM_FLAGS_MASK; + + flag = MAIL_CUSTOM_FLAG_1; + for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++, flag <<= 1) { + if (oldflags & flag) { + i_assert(custom_flags[i] != NULL && + *custom_flags[i] != '\0'); + + idx = get_flag_index(mcf, custom_flags[i]); + if (idx == -1) { + (void)lock_file(mcf, F_UNLCK); + return 0; + } + *flags |= 1 << (idx + MAIL_CUSTOM_FLAG_1_BIT); + } + } + + if (!lock_file(mcf, F_UNLCK)) + return -1; + + return 1; +} + +const char **mail_custom_flags_list_get(MailCustomFlags *mcf) +{ + mcf->custom_flags_refcount++; + return (const char **) mcf->custom_flags; +} + +void mail_custom_flags_list_unref(MailCustomFlags *mcf) +{ + i_assert(mcf->custom_flags_refcount > 0); + + mcf->custom_flags_refcount--; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-index/mail-custom-flags.h Sun Sep 08 02:31:56 2002 +0300 @@ -0,0 +1,23 @@ +#ifndef __MAIL_CUSTOM_FLAGS_H +#define __MAIL_CUSTOM_FLAGS_H + +#include "mail-index.h" + +#define CUSTOM_FLAGS_FILE_NAME ".customflags" + +int mail_custom_flags_open_or_create(MailIndex *index); +void mail_custom_flags_free(MailCustomFlags *mcf); + +/* Change custom flags so that they reflect the real flag numbers in + the file. Returns 1 if ok, 0 if number of custom flags exceeded or + -1 if error */ +int mail_custom_flags_fix_list(MailCustomFlags *mcf, MailFlags *flags, + const char *custom_flags[]); + +/* Returns a pointer to list of flags. */ +const char **mail_custom_flags_list_get(MailCustomFlags *mcf); + +/* Call this after you've done with the flags list above */ +void mail_custom_flags_list_unref(MailCustomFlags *mcf); + +#endif
--- a/src/lib-index/mail-index.c Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-index/mail-index.c Sun Sep 08 02:31:56 2002 +0300 @@ -11,6 +11,7 @@ #include "mail-hash.h" #include "mail-lockdir.h" #include "mail-modifylog.h" +#include "mail-custom-flags.h" #include <stdio.h> #include <stdlib.h> @@ -113,6 +114,11 @@ index->modifylog = NULL; } + if (index->custom_flags != NULL) { + mail_custom_flags_free(index->custom_flags); + index->custom_flags = NULL; + } + if (index->error != NULL) { i_free(index->error); index->error = NULL; @@ -553,6 +559,8 @@ break; if (!mail_modifylog_open_or_create(index)) break; + if (!mail_custom_flags_open_or_create(index)) + break; if (hdr.flags & MAIL_INDEX_FLAG_FSCK) { /* index needs fscking */
--- a/src/lib-index/mail-index.h Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-index/mail-index.h Sun Sep 08 02:31:56 2002 +0300 @@ -80,6 +80,7 @@ typedef struct _MailIndexData MailIndexData; typedef struct _MailHash MailHash; typedef struct _MailModifyLog MailModifyLog; +typedef struct _MailCustomFlags MailCustomFlags; typedef struct _MailIndexHeader MailIndexHeader; typedef struct _MailIndexDataHeader MailIndexDataHeader; @@ -296,6 +297,7 @@ MailIndexData *data; MailHash *hash; MailModifyLog *modifylog; + MailCustomFlags *custom_flags; char *dir; /* directory where to place the index files */ char *filepath; /* index file path */ @@ -338,7 +340,7 @@ #define MAIL_INDEX_PRIVATE_FILL \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0 /* defaults - same as above but prefixed with mail_index_. */ int mail_index_open(MailIndex *index, int update_recent);
--- a/src/lib-storage/Makefile.am Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-storage/Makefile.am Sun Sep 08 02:31:56 2002 +0300 @@ -1,4 +1,4 @@ -SUBDIRS = index subscription-file flags-file +SUBDIRS = index subscription-file noinst_LIBRARIES = libstorage.a
--- a/src/lib-storage/flags-file/.cvsignore Sat Sep 07 22:01:14 2002 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -*.la -*.lo -*.o -.deps -.libs -Makefile -Makefile.in -so_locations
--- a/src/lib-storage/flags-file/Makefile.am Sat Sep 07 22:01:14 2002 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -noinst_LIBRARIES = libstorage_flags_file.a - -INCLUDES = \ - -I$(top_srcdir)/src/lib \ - -I$(top_srcdir)/src/lib-storage \ - -I$(top_srcdir)/src/lib-imap - -libstorage_flags_file_a_SOURCES = \ - flags-file.c - -noinst_HEADERS = \ - flags-file.h -
--- a/src/lib-storage/flags-file/flags-file.c Sat Sep 07 22:01:14 2002 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,519 +0,0 @@ -/* Copyright (C) 2002 Timo Sirainen */ - -#include "lib.h" -#include "mmap-util.h" -#include "write-full.h" -#include "imap-util.h" -#include "flags-file.h" - -#include <unistd.h> -#include <fcntl.h> -#include <ctype.h> - -/* Header is simply a counter which is increased every time the file is - updated. This allows other processes to easily notice if there's been - any changes. */ - -#define COUNTER_SIZE 4 -#define HEADER_SIZE (COUNTER_SIZE + 1) /* 0000\n */ - -struct _FlagsFile { - MailStorage *storage; - char *path; - int fd; - int lock_type; - - char sync_counter[COUNTER_SIZE]; - char *custom_flags[MAIL_CUSTOM_FLAGS_COUNT]; - int custom_flags_refcount; - - void *mmap_base; - size_t mmap_length; - - unsigned int syncing:1; -}; - -static int lock_file(FlagsFile *ff, int type); - -static int update_mmap(FlagsFile *ff) -{ - ff->mmap_base = mmap_rw_file(ff->fd, &ff->mmap_length); - if (ff->mmap_base == MAP_FAILED) { - ff->mmap_base = NULL; - mail_storage_set_critical(ff->storage, "mmap() failed for " - "flags file %s: %m", ff->path); - return FALSE; - } - - (void)madvise(ff->mmap_base, ff->mmap_length, MADV_SEQUENTIAL); - return TRUE; -} - -static int flags_file_init(FlagsFile *ff) -{ - static char buf[HEADER_SIZE] = "0000\n"; - off_t pos; - - if (!lock_file(ff, F_WRLCK)) - return FALSE; - - /* make sure it's still empty after locking */ - pos = lseek(ff->fd, 0, SEEK_END); - if (pos != -1 && pos < HEADER_SIZE) - pos = lseek(ff->fd, 0, SEEK_SET); - - if (pos == -1) { - mail_storage_set_critical(ff->storage, "lseek() failed for " - "flags file %s: %m", ff->path); - return FALSE; - } - - /* write the header - it's a 4 byte counter as hex */ - if (write_full(ff->fd, buf, HEADER_SIZE) < 0) { - mail_storage_set_critical(ff->storage, "write() failed for " - "flags file %s: %m", ff->path); - return FALSE; - } - - if (!lock_file(ff, F_UNLCK)) - return FALSE; - - return TRUE; -} - -static void flags_file_sync(FlagsFile *ff) -{ - char *data, *data_end, *line; - unsigned int num; - int i; - - memcpy(ff->sync_counter, ff->mmap_base, COUNTER_SIZE); - - for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) { - if (ff->custom_flags[i] != NULL) { - i_free(ff->custom_flags[i]); - ff->custom_flags[i] = NULL; - } - } - - data = ff->mmap_base; - data_end = data + ff->mmap_length; - - /* this loop skips the first line, which is the header */ - while (data != data_end) { - if (*data != '\n') { - data++; - continue; - } - - /* beginning of line, get the index */ - if (data+1 == data_end) - break; - data++; - - if (!i_isdigit(*data)) - continue; - - num = 0; - while (data != data_end && *data >= '0' && *data <= '9') { - num = num*10 + (*data-'0'); - data++; - } - - if (num < MAIL_CUSTOM_FLAGS_COUNT) { - /* get the name */ - if (data == data_end || *data != ' ') - continue; - - line = ++data; - while (data != data_end && *data != '\n') - data++; - - if (ff->custom_flags[num] != NULL) { - i_warning("Error in custom flags file %s: " - "Duplicated ID %u", ff->path, num); - i_free(ff->custom_flags[num]); - } - - ff->custom_flags[num] = i_strdup_until(line, data); - } - } -} - -static int flags_file_check_sync(FlagsFile *ff) -{ - if (ff->custom_flags_refcount > 0) { - /* we've been locked from updates for now.. */ - return TRUE; - } - - if (ff->mmap_length != 0 && - memcmp(ff->sync_counter, ff->mmap_base, COUNTER_SIZE) == 0) - return TRUE; - - /* file modified, resync */ - if (!update_mmap(ff)) - return FALSE; - - if (ff->mmap_length < HEADER_SIZE) { - /* it's broken, rewrite header */ - if (ff->lock_type == F_RDLCK) - (void)lock_file(ff, F_UNLCK); - - if (!flags_file_init(ff)) - return FALSE; - - if (!update_mmap(ff)) - return FALSE; - } - - flags_file_sync(ff); - return TRUE; -} - -static int lock_file(FlagsFile *ff, int type) -{ - struct flock fl; - - if (ff->lock_type == type) - return TRUE; - - /* lock whole file */ - fl.l_type = type; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 0; - - while (fcntl(ff->fd, F_SETLKW, &fl) == -1) { - if (errno != EINTR) { - mail_storage_set_critical(ff->storage, "fcntl() failed " - "for flags file %s: %m", - ff->path); - return FALSE; - } - } - - ff->lock_type = type; - - if (type != F_UNLCK && !ff->syncing) { - ff->syncing = TRUE; - if (!flags_file_check_sync(ff)) { - ff->syncing = FALSE; - return FALSE; - } - - /* syncing may have changed locking, do it again */ - if (!lock_file(ff, type)) { - ff->syncing = FALSE; - return FALSE; - } - - ff->syncing = FALSE; - } - return TRUE; -} - -FlagsFile *flags_file_open_or_create(MailStorage *storage, const char *path) -{ - FlagsFile *ff; - int fd; - - fd = open(path, O_RDWR | O_CREAT, 0660); - if (fd == -1) { - mail_storage_set_critical(storage, "Can't open flags file " - "%s: %m", path); - return NULL; - } - - ff = i_new(FlagsFile, 1); - ff->storage = storage; - ff->path = i_strdup(path); - ff->fd = fd; - - if (!update_mmap(ff)) { - flags_file_destroy(ff); - return NULL; - } - - if (ff->mmap_length < HEADER_SIZE) { - /* we just created it, write the header */ - ff->syncing = TRUE; - if (!flags_file_init(ff) || !update_mmap(ff)) { - flags_file_destroy(ff); - return NULL; - } - ff->syncing = FALSE; - } - - flags_file_sync(ff); - return ff; -} - -void flags_file_destroy(FlagsFile *ff) -{ - int i; - - for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) - i_free(ff->custom_flags[i]); - - (void)munmap(ff->mmap_base, ff->mmap_length); - (void)close(ff->fd); - - i_free(ff->path); - i_free(ff); -} - -static int flags_file_update_counter(FlagsFile *ff) -{ - int i; - - if (lseek(ff->fd, 0, SEEK_SET) == -1) { - mail_storage_set_critical(ff->storage, "lseek() failed for " - "flags file %s: %m", ff->path); - return FALSE; - } - - for (i = COUNTER_SIZE-1; i >= 0; i--) { - if (ff->sync_counter[i] == '9') { - ff->sync_counter[i] = 'A'; - break; - } - - if (ff->sync_counter[i] == 'F') { - /* digit wrapped, update next one */ - ff->sync_counter[i] = '0'; - } else { - ff->sync_counter[i]++; - break; - } - } - - if (write_full(ff->fd, ff->sync_counter, COUNTER_SIZE) < 0) { - mail_storage_set_critical(ff->storage, "write() failed for " - "flags file %s: %m", ff->path); - return FALSE; - } - - return TRUE; -} - -static int flags_file_add(FlagsFile *ff, int idx, const char *name) -{ - const char *buf; - unsigned int len; - off_t pos; - - i_assert(idx < MAIL_CUSTOM_FLAGS_COUNT); - - /* first update the sync counter */ - if (!flags_file_update_counter(ff)) - return FALSE; - - /* add the flag */ - pos = lseek(ff->fd, 0, SEEK_END); - if (pos == -1) { - mail_storage_set_critical(ff->storage, "lseek() failed for " - "flags file %s: %m", ff->path); - return FALSE; - } - - if (pos != (off_t)ff->mmap_length) { - mail_storage_set_critical(ff->storage, "flags file %s was " - "changed by someone while we were" - "trying to modify it", ff->path); - return FALSE; - } - - buf = t_strdup_printf("\n%d %s\n", idx, name); - len = strlen(buf); - - if (((char *) ff->mmap_base)[ff->mmap_length-1] == '\n') { - /* don't add the \n prefix */ - buf++; - len--; - } - - if (write_full(ff->fd, buf, len) < 0) { - mail_storage_set_critical(ff->storage, "write() failed for " - "flags file %s: %m", ff->path); - return FALSE; - } - - if (!update_mmap(ff)) - return FALSE; - - return TRUE; -} - -static int flags_file_remove(FlagsFile *ff, unsigned int idx) -{ - char *data, *data_end, *line; - unsigned int num; - int pos, linelen; - - data = ff->mmap_base; - data_end = data + ff->mmap_length; - - while (data != data_end) { - if (*data != '\n') { - data++; - continue; - } - - /* beginning of line, get the index */ - if (data+1 == data_end) - break; - line = ++data; - - num = 0; - while (data != data_end && *data >= '0' && *data <= '9') { - num = num*10 + (*data-'0'); - data++; - } - - if (num == idx) { - /* remove this line */ - while (data != data_end && data[-1] != '\n') - data++; - - linelen = (int) (data - line); - pos = (int) (data - (char *) ff->mmap_base); - memmove(line, data, ff->mmap_length - pos); - - ff->mmap_length -= linelen; - if (ftruncate(ff->fd, (off_t) ff->mmap_length) == -1) { - mail_storage_set_critical(ff->storage, - "ftruncate() failed for flags file " - "%s: %m", ff->path); - return FALSE; - } - - return TRUE; - } - } - - return FALSE; -} - -static int find_first_unused_flag(FlagsFile *ff) -{ - int i; - - for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) { - if (ff->custom_flags[i] == NULL) - return i; - } - - return -1; -} - -static void remove_unused_custom_flags(FlagsFile *ff, MailFlags used_flags) -{ - unsigned int i; - - for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) { - if ((used_flags & (1 << (i + MAIL_CUSTOM_FLAG_1_BIT))) == 0) { - i_free(ff->custom_flags[i]); - ff->custom_flags[i] = NULL; - - flags_file_remove(ff, i); - } - } -} - -static int get_flag_index(FlagsFile *ff, const char *flag, - MailFlags (*get_used_flags)(void *context), - void *context) -{ - int i, first_empty; - - /* check existing flags */ - for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) { - if (ff->custom_flags[i] == NULL) - continue; - - i_assert(ff->custom_flags[i] != '\0'); - if (strcasecmp(ff->custom_flags[i], flag) == 0) - return i; - } - - /* unlock + write lock, don't directly change from read -> write lock - to prevent deadlocking */ - if (!lock_file(ff, F_UNLCK) || !lock_file(ff, F_WRLCK)) - return -1; - - /* new flag, add it. first find the first free flag, note that - unlock+lock might have just changed it. */ - first_empty = find_first_unused_flag(ff); - if (first_empty == -1) { - /* all custom flags are used, see if some of them are unused */ - remove_unused_custom_flags(ff, get_used_flags(context)); - - first_empty = find_first_unused_flag(ff); - if (first_empty == -1) { - /* everything is in use */ - return -1; - } - } - - if (!flags_file_add(ff, first_empty, flag)) - return -1; - - ff->custom_flags[first_empty] = i_strdup(flag); - return first_empty; -} - -int flags_file_fix_custom_flags(FlagsFile *ff, MailFlags *flags, - const char *custom_flags[], - MailFlags (*get_used_flags)(void *context), - void *context) -{ - MailFlags oldflags, flag; - int i, idx; - - if ((*flags & MAIL_CUSTOM_FLAGS_MASK) == 0) - return TRUE; - - if (!lock_file(ff, F_RDLCK)) - return FALSE; - - oldflags = *flags; - *flags &= MAIL_SYSTEM_FLAGS_MASK; - - flag = MAIL_CUSTOM_FLAG_1; - for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++, flag <<= 1) { - if (oldflags & flag) { - i_assert(custom_flags[i] != NULL && - *custom_flags[i] != '\0'); - - idx = get_flag_index(ff, custom_flags[i], - get_used_flags, context); - if (idx == -1) { - mail_storage_set_error(ff->storage, - "Maximum number of different custom " - "flags exceeded"); - (void)lock_file(ff, F_UNLCK); - return FALSE; - } - *flags |= 1 << (idx + MAIL_CUSTOM_FLAG_1_BIT); - } - } - - if (!lock_file(ff, F_UNLCK)) - return FALSE; - - return TRUE; -} - -const char **flags_file_list_get(FlagsFile *ff) -{ - ff->custom_flags_refcount++; - return (const char **) ff->custom_flags; -} - -void flags_file_list_unref(FlagsFile *ff) -{ - i_assert(ff->custom_flags_refcount > 0); - - ff->custom_flags_refcount--; -}
--- a/src/lib-storage/flags-file/flags-file.h Sat Sep 07 22:01:14 2002 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -#ifndef __FLAGS_FILE_H -#define __FLAGS_FILE_H - -#include "mail-storage.h" - -#define FLAGS_FILE_NAME ".customflags" - -typedef struct _FlagsFile FlagsFile; - -FlagsFile *flags_file_open_or_create(MailStorage *storage, const char *path); -void flags_file_destroy(FlagsFile *ff); - -/* Change custom flags so that they reflect the real flag numbers in - the file. get_used_flags is called when all flags are in use to figure - out which of them could be removed. */ -int flags_file_fix_custom_flags(FlagsFile *ff, MailFlags *flags, - const char *custom_flags[], - MailFlags (*get_used_flags)(void *context), - void *context); - -/* Returns a pointer to list of flags. */ -const char **flags_file_list_get(FlagsFile *ff); - -/* Call this after you've done with the flags list above */ -void flags_file_list_unref(FlagsFile *ff); - -#endif
--- a/src/lib-storage/index/index-copy.c Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-storage/index/index-copy.c Sun Sep 08 02:31:56 2002 +0300 @@ -2,6 +2,7 @@ #include "lib.h" #include "iobuffer.h" +#include "mail-custom-flags.h" #include "index-storage.h" #include "index-messageset.h" @@ -48,13 +49,13 @@ if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_SHARED)) return mail_storage_set_index_error(ibox); - cd.custom_flags = flags_file_list_get(ibox->flagsfile); + cd.custom_flags = mail_custom_flags_list_get(ibox->index->custom_flags); cd.dest = destbox; failed = index_messageset_foreach(ibox, messageset, uidset, copy_func, &cd) <= 0; - flags_file_list_unref(ibox->flagsfile); + mail_custom_flags_list_unref(ibox->index->custom_flags); if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_UNLOCK)) return mail_storage_set_index_error(ibox);
--- a/src/lib-storage/index/index-fetch.c Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-storage/index/index-fetch.c Sun Sep 08 02:31:56 2002 +0300 @@ -3,6 +3,7 @@ #include "lib.h" #include "iobuffer.h" #include "temp-string.h" +#include "mail-custom-flags.h" #include "index-storage.h" #include "index-fetch.h" #include "index-messageset.h" @@ -285,7 +286,8 @@ ctx.box = box; ctx.cache = ibox->cache; ctx.index = ibox->index; - ctx.custom_flags = flags_file_list_get(ibox->flagsfile); + ctx.custom_flags = + mail_custom_flags_list_get(ibox->index->custom_flags); ctx.fetch_data = fetch_data; ctx.outbuf = outbuf; @@ -304,7 +306,7 @@ fetch_data->uidset, index_fetch_mail, &ctx); - flags_file_list_unref(ibox->flagsfile); + mail_custom_flags_list_unref(ibox->index->custom_flags); if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_UNLOCK)) return mail_storage_set_index_error(ibox);
--- a/src/lib-storage/index/index-status.c Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-storage/index/index-status.c Sun Sep 08 02:31:56 2002 +0300 @@ -1,6 +1,7 @@ /* Copyright (C) 2002 Timo Sirainen */ #include "lib.h" +#include "mail-custom-flags.h" #include "index-storage.h" static unsigned int get_recent_count(MailIndex *index) @@ -80,15 +81,16 @@ } static void -get_custom_flags(FlagsFile *ff, const char *result[MAIL_CUSTOM_FLAGS_COUNT]) +get_custom_flags(MailCustomFlags *mcf, + const char *result[MAIL_CUSTOM_FLAGS_COUNT]) { const char **flags; int i; - flags = flags_file_list_get(ff); + flags = mail_custom_flags_list_get(mcf); for (i = 0; i < MAIL_CUSTOM_FLAGS_COUNT; i++) result[i] = t_strdup(flags[i]); - flags_file_list_unref(ff); + mail_custom_flags_list_unref(mcf); } int index_storage_get_status(Mailbox *box, MailboxStatusItems items, @@ -117,8 +119,10 @@ if (items & STATUS_RECENT) status->recent = get_recent_count(ibox->index); - if (items & STATUS_CUSTOM_FLAGS) - get_custom_flags(ibox->flagsfile, status->custom_flags); + if (items & STATUS_CUSTOM_FLAGS) { + get_custom_flags(ibox->index->custom_flags, + status->custom_flags); + } /* STATUS sends EXISTS, so we've synced it */ ibox->synced_messages_count = hdr->messages_count;
--- a/src/lib-storage/index/index-storage.c Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-storage/index/index-storage.c Sun Sep 08 02:31:56 2002 +0300 @@ -3,6 +3,7 @@ #include "lib.h" #include "mail-index.h" #include "mail-index-util.h" +#include "mail-custom-flags.h" #include "index-storage.h" IndexMailbox *index_storage_init(MailStorage *storage, Mailbox *box, @@ -10,8 +11,6 @@ int readonly) { IndexMailbox *ibox; - FlagsFile *flagsfile; - const char *path; i_assert(name != NULL); @@ -22,14 +21,6 @@ return NULL; } - /* then flags file */ - path = t_strconcat(index->dir, "/", FLAGS_FILE_NAME, NULL); - flagsfile = flags_file_open_or_create(storage, path); - if (flagsfile == NULL) { - index->free(index); - return NULL; - } - ibox = i_new(IndexMailbox, 1); ibox->box = *box; @@ -38,7 +29,6 @@ ibox->box.readonly = readonly; ibox->index = index; - ibox->flagsfile = flagsfile; ibox->cache = imap_msgcache_alloc(&index_msgcache_iface); return ibox; @@ -48,7 +38,6 @@ { IndexMailbox *ibox = (IndexMailbox *) box; - flags_file_destroy(ibox->flagsfile); imap_msgcache_free(ibox->cache); ibox->index->free(ibox->index); i_free(box->name); @@ -64,26 +53,21 @@ return FALSE; } -static MailFlags get_used_flags(void *context) +int index_mailbox_fix_custom_flags(IndexMailbox *ibox, MailFlags *flags, + const char *custom_flags[]) { - IndexMailbox *ibox = context; - MailIndexRecord *rec; - MailFlags used_flags; - - used_flags = 0; + int ret; - rec = ibox->index->lookup(ibox->index, 1); - while (rec != NULL) { - used_flags |= rec->msg_flags; - rec = ibox->index->next(ibox->index, rec); + ret = mail_custom_flags_fix_list(ibox->index->custom_flags, + flags, custom_flags); + switch (ret) { + case 1: + return TRUE; + case 0: + mail_storage_set_error(ibox->box.storage, "Maximum number of " + "different custom flags exceeded"); + return FALSE; + default: + return mail_storage_set_index_error(ibox); } - - return used_flags; } - -int index_mailbox_fix_custom_flags(IndexMailbox *ibox, MailFlags *flags, - const char *custom_flags[]) -{ - return flags_file_fix_custom_flags(ibox->flagsfile, flags, - custom_flags, get_used_flags, ibox); -}
--- a/src/lib-storage/index/index-storage.h Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-storage/index/index-storage.h Sun Sep 08 02:31:56 2002 +0300 @@ -4,7 +4,6 @@ #include "mail-storage.h" #include "mail-index.h" #include "imap-message-cache.h" -#include "flags-file/flags-file.h" typedef struct _IndexMailbox IndexMailbox; @@ -17,7 +16,6 @@ MailExpungeFunc expunge_func, void *context); MailIndex *index; - FlagsFile *flagsfile; ImapMessageCache *cache; unsigned int synced_messages_count; }; @@ -32,7 +30,7 @@ int mail_storage_set_index_error(IndexMailbox *ibox); int index_mailbox_fix_custom_flags(IndexMailbox *ibox, MailFlags *flags, - const char *custom_flags[]); + const char *custom_flags[]); int index_expunge_seek_first(IndexMailbox *ibox, unsigned int *seq, MailIndexRecord **rec);
--- a/src/lib-storage/index/index-sync.c Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-storage/index/index-sync.c Sun Sep 08 02:31:56 2002 +0300 @@ -3,6 +3,7 @@ #include "lib.h" #include "index-storage.h" #include "mail-modifylog.h" +#include "mail-custom-flags.h" int index_storage_sync(Mailbox *box, unsigned int *messages, int expunge, MailExpungeFunc expunge_func, @@ -33,7 +34,7 @@ if (log == NULL) failed = TRUE; - custom_flags = flags_file_list_get(ibox->flagsfile); + custom_flags = mail_custom_flags_list_get(ibox->index->custom_flags); for (; count > 0; count--, log++) { switch (log->type) { case RECORD_TYPE_EXPUNGE: @@ -59,7 +60,7 @@ break; } } - flags_file_list_unref(ibox->flagsfile); + mail_custom_flags_list_unref(ibox->index->custom_flags); /* mark synced */ failed = !mail_modifylog_mark_synced(ibox->index->modifylog);
--- a/src/lib-storage/index/index-update-flags.c Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-storage/index/index-update-flags.c Sun Sep 08 02:31:56 2002 +0300 @@ -3,11 +3,12 @@ #include "lib.h" #include "index-storage.h" #include "index-messageset.h" +#include "mail-custom-flags.h" typedef struct { Mailbox *box; + MailCustomFlags *custom_flags; MailFlags flags; - FlagsFile *flagsfile; ModifyType modify_type; MailFlagUpdateFunc func; void *context; @@ -42,9 +43,9 @@ if (ctx->func != NULL) { ctx->func(ctx->box, seq, rec->uid, flags, - flags_file_list_get(ctx->flagsfile), + mail_custom_flags_list_get(ctx->custom_flags), ctx->context); - flags_file_list_unref(ctx->flagsfile); + mail_custom_flags_list_unref(ctx->custom_flags); } return TRUE; } @@ -65,14 +66,14 @@ } if (!index_mailbox_fix_custom_flags(ibox, &flags, custom_flags)) - return mail_storage_set_index_error((IndexMailbox *) box); + return FALSE; if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_EXCLUSIVE)) return mail_storage_set_index_error(ibox); ctx.box = box; ctx.flags = flags & ~MAIL_RECENT; /* \Recent can't be changed */ - ctx.flagsfile = ibox->flagsfile; + ctx.custom_flags = ibox->index->custom_flags; ctx.modify_type = modify_type; ctx.func = func; ctx.context = context;
--- a/src/lib-storage/index/maildir/maildir-save.c Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-storage/index/maildir/maildir-save.c Sun Sep 08 02:31:56 2002 +0300 @@ -71,7 +71,7 @@ } if (!index_mailbox_fix_custom_flags(ibox, &flags, custom_flags)) - return mail_storage_set_index_error(ibox); + return FALSE; t_push();
--- a/src/lib-storage/index/mbox/mbox-save.c Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-storage/index/mbox/mbox-save.c Sun Sep 08 02:31:56 2002 +0300 @@ -57,7 +57,7 @@ } if (!index_mailbox_fix_custom_flags(ibox, &flags, custom_flags)) - return mail_storage_set_index_error(ibox); + return FALSE; /* append the data into mbox file */ fd = open(ibox->index->mbox_path, O_RDWR | O_CREAT);
--- a/src/lib-storage/index/mbox/mbox-storage.c Sat Sep 07 22:01:14 2002 +0300 +++ b/src/lib-storage/index/mbox/mbox-storage.c Sun Sep 08 02:31:56 2002 +0300 @@ -3,6 +3,7 @@ #include "lib.h" #include "unlink-directory.h" #include "subscription-file/subscription-file.h" +#include "mail-custom-flags.h" #include "mbox-index.h" #include "mbox-storage.h" @@ -365,14 +366,15 @@ static void mbox_storage_close(Mailbox *box) { IndexMailbox *ibox = (IndexMailbox *) box; + const char **list; if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_EXCLUSIVE)) mail_storage_set_index_error(ibox); else { /* update flags by rewrite mbox file */ - mbox_index_rewrite(ibox->index, - flags_file_list_get(ibox->flagsfile)); - flags_file_list_unref(ibox->flagsfile); + list = mail_custom_flags_list_get(ibox->index->custom_flags); + mbox_index_rewrite(ibox->index, list); + mail_custom_flags_list_unref(ibox->index->custom_flags); (void)ibox->index->set_lock(ibox->index, MAIL_LOCK_UNLOCK); }