Mercurial > dovecot > core-2.2
view src/lib-storage/subscription-file/subscription-file.c @ 903:fd8888f6f037 HEAD
Naming style changes, finally got tired of most of the typedefs. Also the
previous enum -> macro change reverted so that we don't use the highest bit
anymore, that's incompatible with old indexes so they will be rebuilt.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 05 Jan 2003 15:09:51 +0200 |
parents | 5ac361acb316 |
children | 411006be3c66 |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ /* ugly code here - text files are annoying to manage */ #include "lib.h" #include "file-lock.h" #include "mmap-util.h" #include "write-full.h" #include "imap-match.h" #include "mail-storage.h" #include "subscription-file.h" #include <unistd.h> #include <fcntl.h> #define SUBSCRIPTION_FILE_NAME ".subscriptions" static int subsfile_set_syscall_error(struct mail_storage *storage, const char *path, const char *function) { i_assert(function != NULL); mail_storage_set_critical(storage, "%s failed with subscription file %s: %m", function, path); return FALSE; } static int subscription_open(struct mail_storage *storage, int update, const char **path, void **mmap_base, size_t *mmap_length) { int fd; *path = t_strconcat(storage->dir, "/" SUBSCRIPTION_FILE_NAME, NULL); fd = update ? open(*path, O_RDWR | O_CREAT, 0660) : open(*path, O_RDONLY); if (fd == -1) { if (update || errno != ENOENT) { subsfile_set_syscall_error(storage, "open()", *path); return -1; } return -2; } /* FIXME: we should work without locking, rename() would be easiest but .lock would work too */ if (file_wait_lock(fd, update ? F_WRLCK : F_RDLCK) <= 0) { subsfile_set_syscall_error(storage, "file_wait_lock()", *path); (void)close(fd); return -1; } *mmap_base = update ? mmap_rw_file(fd, mmap_length) : mmap_ro_file(fd, mmap_length); if (*mmap_base == MAP_FAILED) { *mmap_base = NULL; subsfile_set_syscall_error(storage, "mmap()", *path); (void)close(fd); return -1; } (void)madvise(*mmap_base, *mmap_length, MADV_SEQUENTIAL); return fd; } static int subscription_append(struct mail_storage *storage, int fd, const char *name, size_t len, int prefix_lf, const char *path) { char *buf; if (lseek(fd, 0, SEEK_END) < 0) return subsfile_set_syscall_error(storage, "lseek()", path); /* @UNSAFE */ buf = t_buffer_get(len+2); buf[0] = '\n'; memcpy(buf+1, name, len); buf[len+1] = '\n'; if (prefix_lf) len += 2; else { buf++; len++; } if (write_full(fd, buf, len) < 0) { subsfile_set_syscall_error(storage, "write_full()", path); return FALSE; } return TRUE; } int subsfile_set_subscribed(struct mail_storage *storage, const char *name, int set) { void *mmap_base; size_t mmap_length; const char *path; char *subscriptions, *end, *p; size_t namelen, afterlen, removelen; int fd, failed, prefix_lf; if (strcasecmp(name, "INBOX") == 0) name = "INBOX"; fd = subscription_open(storage, TRUE, &path, &mmap_base, &mmap_length); if (fd == -1) return FALSE; namelen = strlen(name); subscriptions = mmap_base; if (subscriptions == NULL) p = NULL; else { end = subscriptions + mmap_length; for (p = subscriptions; p != end; p++) { if (*p == *name && p+namelen <= end && strncmp(p, name, namelen) == 0) { /* make sure beginning and end matches too */ if ((p == subscriptions || p[-1] == '\n') && (p+namelen == end || p[namelen] == '\n')) break; } } if (p == end) p = NULL; } failed = FALSE; if (p != NULL && !set) { /* remove it */ afterlen = mmap_length - (size_t) (p - subscriptions); removelen = namelen < afterlen ? namelen+1 : namelen; if (removelen < afterlen) memmove(p, p+removelen, afterlen-removelen); if (ftruncate(fd, (off_t) (mmap_length - removelen)) == -1) { subsfile_set_syscall_error(storage, "ftruncate()", path); failed = TRUE; } } else if (p == NULL && set) { /* append it */ prefix_lf = mmap_length > 0 && subscriptions[mmap_length-1] != '\n'; if (!subscription_append(storage, fd, name, namelen, prefix_lf, path)) failed = TRUE; } if (mmap_base != NULL && munmap(mmap_base, mmap_length) < 0) { subsfile_set_syscall_error(storage, "munmap()", path); failed = TRUE; } if (close(fd) < 0) { subsfile_set_syscall_error(storage, "close()", path); failed = TRUE; } return !failed; } int subsfile_foreach(struct mail_storage *storage, const char *mask, SubsFileForeachFunc func, void *context) { struct imap_match_glob *glob; const char *path, *start, *end, *p, *line; void *mmap_base; size_t mmap_length; int fd, ret; fd = subscription_open(storage, FALSE, &path, &mmap_base, &mmap_length); if (fd < 0) { /* -2 = no subscription file, ignore */ return fd == -1 ? -1 : 1; } glob = imap_match_init(mask, TRUE, storage->hierarchy_sep); start = mmap_base; end = start + mmap_length; ret = 1; while (ret) { t_push(); for (p = start; p != end; p++) { if (*p == '\n') break; } line = t_strdup_until(start, p); if (line != NULL && *line != '\0' && imap_match(glob, line) > 0) ret = func(storage, line, context); t_pop(); if (p == end) break; start = p+1; } if (mmap_base != NULL && munmap(mmap_base, mmap_length) < 0) subsfile_set_syscall_error(storage, "munmap()", path); if (close(fd) < 0) subsfile_set_syscall_error(storage, "close()", path); return ret; }