Mercurial > dovecot > core-2.2
view src/lib-storage/subscription-file/subscription-file.c @ 29:e9375147c0cb HEAD
Added write_full() which is a simple wrapper around write() meant for
writing into files.
When there's too much deleted data in index files, they're now compressed
when the index is being opened.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 26 Aug 2002 02:46:59 +0300 |
parents | 82b7de533f98 |
children | 4223b9ed0c80 |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ /* ugly code here - text files are annoying to manage */ #include "lib.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 lock_file(int fd, int type) { struct flock fl; /* lock whole file */ fl.l_type = type; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; while (fcntl(fd, F_SETLKW, &fl) == -1) { if (errno != EINTR) return FALSE; } return TRUE; } static int subscription_open(MailStorage *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) { mail_storage_set_critical(storage, "Can't open " "subscription file %s: %m", *path); } return -1; } if (!lock_file(fd, update ? F_WRLCK : F_RDLCK)) { mail_storage_set_critical(storage, "fcntl() failed for " "subscription file %s: %m", *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; mail_storage_set_critical(storage, "mmap() failed for " "subscription file %s: %m", *path); (void)close(fd); return -1; } (void)madvise(*mmap_base, *mmap_length, MADV_SEQUENTIAL); return fd; } static int subscription_append(MailStorage *storage, int fd, const char *name, unsigned int len, int prefix_lf, const char *path) { char *buf; if (lseek(fd, 0, SEEK_END) == -1) { mail_storage_set_critical(storage, "lseek() failed for " "subscription file %s: %m", path); return FALSE; } 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) { mail_storage_set_critical(storage, "write() failed for " "subscription file %s: %m", path); return FALSE; } return TRUE; } int subsfile_set_subscribed(MailStorage *storage, const char *name, int set) { void *mmap_base; size_t mmap_length; const char *path; char *subscriptions, *end, *p; unsigned int 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 - (unsigned int) (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) { mail_storage_set_critical(storage, "ftruncate() " "failed for subscription " "file %s: %m", 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) == -1) { mail_storage_set_critical(storage, "munmap() failed for " "subscription file %s: %m", path); failed = TRUE; } if (close(fd) == -1) { mail_storage_set_critical(storage, "close() failed for " "subscription file %s: %m", path); failed = TRUE; } return !failed; } int subsfile_foreach(MailStorage *storage, const char *mask, SubsFileForeachFunc func, void *context) { const ImapMatchGlob *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 == -1) return -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, NULL) >= 0) ret = func(storage, line, context); t_pop(); if (p == end) break; start = p+1; } (void)close(fd); return ret; }