[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