[dovecot-cvs] dovecot/src/plugins/zlib .cvsignore, NONE,
1.1 Makefile.am, NONE, 1.1 istream-zlib.c, NONE,
1.1 istream-zlib.h, NONE, 1.1 zlib-plugin.c, NONE,
1.1 zlib-plugin.h, NONE, 1.1
cras at dovecot.org
cras at dovecot.org
Sat Dec 31 19:39:18 EET 2005
Update of /var/lib/cvs/dovecot/src/plugins/zlib
In directory talvi:/tmp/cvs-serv19093/src/plugins/zlib
Added Files:
.cvsignore Makefile.am istream-zlib.c istream-zlib.h
zlib-plugin.c zlib-plugin.h
Log Message:
Added zlib plugin
--- NEW FILE: .cvsignore ---
*.la
*.lo
*.o
.deps
.libs
Makefile
Makefile.in
so_locations
--- NEW FILE: Makefile.am ---
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-index \
-I$(top_srcdir)/src/lib-storage \
-I$(top_srcdir)/src/lib-storage/index
imap_moduledir = $(moduledir)/imap
lib01_zlib_plugin_la_LDFLAGS = -module -avoid-version
imap_module_LTLIBRARIES = \
lib01_zlib_plugin.la
lib01_zlib_plugin_la_SOURCES = \
istream-zlib.c \
zlib-plugin.c
noinst_HEADERS = \
istream-zlib.h \
zlib-plugin.h
--- NEW FILE: istream-zlib.c ---
/* Copyright (C) 2005 Timo Sirainen */
#include "lib.h"
#include "istream-internal.h"
#include "istream-zlib.h"
#include <zlib.h>
/* Default maximum buffer size. Seeking backwards is very expensive, so keep
this pretty large */
#define DEFAULT_MAX_BUFFER_SIZE (1024*1024)
#define I_STREAM_MIN_SIZE 4096
struct zlib_istream {
struct _istream istream;
size_t max_buffer_size;
int fd;
gzFile *file;
uoff_t cached_size;
uoff_t seek_offset;
unsigned int marked:1;
};
static void _close(struct _iostream *stream)
{
struct zlib_istream *zstream = (struct zlib_istream *)stream;
if (zstream->file != NULL) {
gzclose(zstream->file);
zstream->file = NULL;
}
}
static void _destroy(struct _iostream *stream __attr_unused__)
{
struct _istream *_stream = (struct _istream *) stream;
p_free(_stream->iostream.pool, _stream->w_buffer);
}
static void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
{
struct zlib_istream *zstream = (struct zlib_istream *)stream;
zstream->max_buffer_size = max_size;
}
static void i_stream_grow_buffer(struct _istream *stream, size_t bytes)
{
struct zlib_istream *zstream = (struct zlib_istream *)stream;
size_t old_size;
old_size = stream->buffer_size;
stream->buffer_size = stream->pos + bytes;
if (stream->buffer_size <= I_STREAM_MIN_SIZE)
stream->buffer_size = I_STREAM_MIN_SIZE;
else {
stream->buffer_size =
pool_get_exp_grown_size(stream->iostream.pool,
old_size, stream->buffer_size);
}
if (zstream->max_buffer_size > 0 &&
stream->buffer_size > zstream->max_buffer_size)
stream->buffer_size = zstream->max_buffer_size;
stream->buffer = stream->w_buffer =
p_realloc(stream->iostream.pool, stream->w_buffer,
old_size, stream->buffer_size);
}
static void i_stream_compress(struct _istream *stream)
{
memmove(stream->w_buffer, stream->w_buffer + stream->skip,
stream->pos - stream->skip);
stream->pos -= stream->skip;
stream->skip = 0;
}
static ssize_t _read(struct _istream *stream)
{
struct zlib_istream *zstream = (struct zlib_istream *)stream;
size_t size;
int ret;
if (stream->istream.closed)
return -1;
stream->istream.stream_errno = 0;
if (stream->pos == stream->buffer_size) {
if (!zstream->marked && stream->skip > 0) {
/* don't try to keep anything cached if we don't
have a seek mark. */
i_stream_compress(stream);
}
if (zstream->max_buffer_size == 0 ||
stream->buffer_size < zstream->max_buffer_size) {
/* buffer is full - grow it */
i_stream_grow_buffer(stream, I_STREAM_MIN_SIZE);
}
if (stream->pos == stream->buffer_size) {
if (stream->skip > 0) {
/* lose our buffer cache */
i_stream_compress(stream);
}
if (stream->pos == stream->buffer_size)
return -2; /* buffer full */
}
}
size = stream->buffer_size - stream->pos;
ret = -1;
i_assert(zstream->seek_offset == stream->istream.v_offset +
(stream->pos - stream->skip));
ret = gzread(zstream->file, stream->w_buffer + stream->pos, size);
if (ret == 0) {
/* EOF */
stream->istream.eof = TRUE;
return -1;
}
if (ret < 0) {
if (errno == EINTR || errno == EAGAIN)
ret = 0;
else {
stream->istream.eof = TRUE;
stream->istream.stream_errno = errno;
return -1;
}
}
zstream->seek_offset += ret;
stream->pos += ret;
i_assert(ret != 0);
return ret;
}
static void _seek(struct _istream *stream, uoff_t v_offset, int mark)
{
struct zlib_istream *zstream = (struct zlib_istream *) stream;
uoff_t start_offset = stream->istream.v_offset - stream->skip;
stream->istream.stream_errno = 0;
if (v_offset < start_offset) {
/* have to seek backwards */
gzseek(zstream->file, v_offset, SEEK_SET);
zstream->seek_offset = v_offset;
stream->skip = stream->pos = 0;
stream->istream.v_offset = v_offset;
} else if (v_offset <= start_offset + stream->pos) {
/* seeking backwards within what's already cached */
stream->skip = v_offset - start_offset;
stream->istream.v_offset = v_offset;
} else {
/* read and cache forward */
do {
size_t avail = stream->pos - stream->skip;
if (stream->istream.v_offset + avail >= v_offset) {
i_stream_skip(&stream->istream,
v_offset -
stream->istream.v_offset);
break;
}
i_stream_skip(&stream->istream, avail);
} while (_read(stream) >= 0);
if (stream->istream.v_offset != v_offset) {
/* some failure, we've broken it */
if (stream->istream.stream_errno != 0) {
i_error("zlib_istream.seek() failed: %s",
strerror(stream->istream.stream_errno));
i_stream_close(&stream->istream);
} else {
/* unexpected EOF. allow it since we may just
want to check if there's anything.. */
i_assert(stream->istream.eof);
}
}
}
if (mark) {
i_stream_compress(stream);
zstream->marked = TRUE;
}
}
static const struct stat *_stat(struct _istream *stream, int exact)
{
struct zlib_istream *zstream = (struct zlib_istream *) stream;
size_t size;
if (fstat(zstream->fd, &stream->statbuf) < 0) {
i_error("zlib_istream.fstat() failed: %m");
return NULL;
}
if (!exact)
return &stream->statbuf;
if (zstream->cached_size == (uoff_t)-1) {
uoff_t old_offset = stream->istream.v_offset;
do {
(void)i_stream_get_data(&stream->istream, &size);
i_stream_skip(&stream->istream, size);
} while (_read(stream) > 0);
zstream->cached_size = stream->istream.v_offset;
i_stream_seek(&stream->istream, old_offset);
}
stream->statbuf.st_size = zstream->cached_size;
return &stream->statbuf;
}
static void _sync(struct _istream *stream)
{
struct zlib_istream *zstream = (struct zlib_istream *) stream;
zstream->cached_size = (uoff_t)-1;
}
struct istream *i_stream_create_zlib(int fd, pool_t pool)
{
struct zlib_istream *zstream;
zstream = p_new(pool, struct zlib_istream, 1);
zstream->fd = fd;
zstream->file = gzdopen(fd, "r");
zstream->cached_size = (uoff_t)-1;
zstream->max_buffer_size = DEFAULT_MAX_BUFFER_SIZE;
zstream->istream.iostream.close = _close;
zstream->istream.iostream.destroy = _destroy;
zstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
zstream->istream.read = _read;
zstream->istream.seek = _seek;
zstream->istream.stat = _stat;
zstream->istream.sync = _sync;
zstream->istream.istream.seekable = TRUE;
return _i_stream_create(&zstream->istream, pool, fd, 0);
}
--- NEW FILE: istream-zlib.h ---
#ifndef __ISTREAM_ZLIB_H
#define __ISTREAM_ZLIB_H
struct istream *i_stream_create_zlib(int fd, pool_t pool);
#endif
--- NEW FILE: zlib-plugin.c ---
/* Copyright (C) 2005 Timo Sirainen */
#include "lib.h"
#include "array.h"
#include "istream-zlib.h"
#include "home-expand.h"
#include "istream.h"
#include "mail-storage-private.h"
#include "index-storage.h"
#include "zlib-plugin.h"
struct zlib_mail_storage {
struct mail_storage_vfuncs super;
};
#define ZLIB_CONTEXT(obj) \
*((void **)array_idx_modifyable(&(obj)->module_contexts, \
zlib_storage_module_id))
/* defined by imap, pop3, lda */
extern void (*hook_mail_storage_created)(struct mail_storage *storage);
static void (*zlib_next_hook_mail_storage_created)
(struct mail_storage *storage);
static unsigned int zlib_storage_module_id = 0;
static int zlib_storage_module_id_set = FALSE;
static const char *
mbox_get_path(struct index_storage *storage, const char *name)
{
if ((storage->storage.flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0 &&
(*name == '/' || *name == '~'))
return home_expand(name);
return t_strconcat(storage->dir, "/", name, NULL);
}
static struct mailbox *
zlib_mailbox_open(struct mail_storage *storage, const char *name,
struct istream *input, enum mailbox_open_flags flags)
{
struct index_storage *istorage = (struct index_storage *)storage;
struct zlib_mail_storage *qstorage = ZLIB_CONTEXT(storage);
struct mailbox *box;
struct istream *zlib_input = NULL;
size_t len = strlen(name);
if (input == NULL && strcmp(storage->name, "mbox") == 0 &&
len > 3 && strcmp(name + len - 3, ".gz") == 0) {
int fd = open(mbox_get_path(istorage, name), O_RDONLY);
if (fd != -1) {
input = zlib_input =
i_stream_create_zlib(fd, default_pool);
}
}
box = qstorage->super.mailbox_open(storage, name, input, flags);
if (zlib_input != NULL)
i_stream_unref(zlib_input);
return box;
}
static void zlib_mail_storage_created(struct mail_storage *storage)
{
struct zlib_mail_storage *qstorage;
if (zlib_next_hook_mail_storage_created != NULL)
zlib_next_hook_mail_storage_created(storage);
qstorage = p_new(storage->pool, struct zlib_mail_storage, 1);
qstorage->super = storage->v;
storage->v.mailbox_open = zlib_mailbox_open;
if (!zlib_storage_module_id_set) {
zlib_storage_module_id = mail_storage_module_id++;
zlib_storage_module_id_set = TRUE;
}
array_idx_set(&storage->module_contexts,
zlib_storage_module_id, &qstorage);
}
void zlib_plugin_init(void)
{
zlib_next_hook_mail_storage_created =
hook_mail_storage_created;
hook_mail_storage_created = zlib_mail_storage_created;
}
void zlib_plugin_deinit(void)
{
hook_mail_storage_created =
zlib_next_hook_mail_storage_created;
}
--- NEW FILE: zlib-plugin.h ---
#ifndef __ZLIB_PLUGIN_H
#define __ZLIB_PLUGIN_H
void zlib_plugin_init(void);
void zlib_plugin_deinit(void);
#endif
More information about the dovecot-cvs
mailing list