mail-index-data.c revision d5aa01c4d7cc8b099f47cf011cba850b1759eb2d
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter/* Copyright (C) 2002 Timo Sirainen */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#include "lib.h"
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#include "mmap-util.h"
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#include "write-full.h"
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#include "mail-index.h"
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#include "mail-index-data.h"
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#include "mail-index-util.h"
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#include <stdio.h>
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#include <fcntl.h>
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#define DATA_FILE_POSITION(data, rec) \
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter ((off_t) ((char *) (rec) - (char *) ((data)->mmap_base)))
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter/* Never compress the file if it's smaller than this (50kB) */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#define COMPRESS_MIN_SIZE (1024*50)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter/* Compress the file when deleted space reaches 20% of total size */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter#define COMPRESS_PERCENTAGE 20
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterstruct _MailIndexData {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter MailIndex *index;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter int fd;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter char *filepath;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter void *mmap_base;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter size_t mmap_length;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter unsigned int dirty_mmap:1;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter};
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterstatic int mmap_update(MailIndexData *data, off_t pos, unsigned int size)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (!data->dirty_mmap || (size != 0 && pos+size <= data->mmap_length))
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return TRUE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (data->mmap_base != NULL)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter (void)munmap(data->mmap_base, data->mmap_length);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter data->mmap_base = mmap_rw_file(data->fd, &data->mmap_length);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (data->mmap_base == MAP_FAILED) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter data->mmap_base = NULL;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter index_set_error(data->index, "index data: mmap() failed with "
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter "file %s: %m", data->filepath);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return FALSE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter } else if (data->mmap_length < sizeof(MailIndexDataHeader)) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter INDEX_MARK_CORRUPTED(data->index);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter index_set_error(data->index, "index data: truncated data "
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter "file %s", data->filepath);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return FALSE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter } else {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter data->dirty_mmap = FALSE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return TRUE;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter }
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterint mail_index_data_open(MailIndex *index)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter MailIndexData *data;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter MailIndexDataHeader *hdr;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter const char *path;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter int fd;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter path = t_strconcat(index->filepath, DATA_FILE_PREFIX, NULL);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter fd = open(path, O_RDWR);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (fd == -1) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (errno == ENOENT) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* doesn't exist, rebuild the index */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter INDEX_MARK_CORRUPTED(index);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter }
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter index_set_error(index, "Can't open index data %s: %m", path);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return FALSE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter }
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter data = i_new(MailIndexData, 1);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter data->index = index;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter data->fd = fd;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter data->filepath = i_strdup(path);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter data->dirty_mmap = TRUE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter index->data = data;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (!mmap_update(data, 0, sizeof(MailIndexDataHeader))) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter mail_index_data_free(data);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return FALSE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter }
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* verify that this really is the data file for wanted index */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter hdr = data->mmap_base;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (hdr->indexid != index->indexid) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter INDEX_MARK_CORRUPTED(index);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter index_set_error(index, "IndexID mismatch with file %s", path);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter mail_index_data_free(data);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return FALSE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter }
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return TRUE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterstatic const char *init_data_file(MailIndex *index, int fd,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter const char *temppath)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter MailIndexDataHeader hdr;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter const char *realpath;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* write header */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter memset(&hdr, 0, sizeof(hdr));
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter hdr.indexid = index->indexid;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (write_full(fd, &hdr, sizeof(hdr)) < 0) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter index_set_error(index, "Error writing to temp index data "
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter "%s: %m", temppath);
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter return NULL;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter }
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter /* move temp file into .data file, deleting old one
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter if it already exists */
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter realpath = t_strconcat(index->filepath, DATA_FILE_PREFIX, NULL);
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter if (rename(temppath, realpath) == -1) {
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter index_set_error(index, "rename(%s, %s) failed: %m",
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter temppath, realpath);
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter (void)unlink(temppath);
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter return NULL;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter }
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter return realpath;
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter}
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walterint mail_index_data_create(MailIndex *index)
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter{
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter MailIndexData *data;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter const char *temppath, *realpath;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter int fd;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter fd = mail_index_create_temp_file(index, &temppath);
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter if (fd == -1)
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter return FALSE;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter realpath = init_data_file(index, fd, temppath);
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter if (realpath == NULL) {
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter (void)close(fd);
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter (void)unlink(temppath);
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter return FALSE;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter }
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter data = i_new(MailIndexData, 1);
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter data->index = index;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter data->fd = fd;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter data->filepath = i_strdup(realpath);
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter data->dirty_mmap = TRUE;
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter index->data = data;
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter return TRUE;
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter}
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Waltervoid mail_index_data_free(MailIndexData *data)
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter{
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter data->index->data = NULL;
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter if (data->mmap_base != NULL) {
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter (void)munmap(data->mmap_base, data->mmap_length);
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter data->mmap_base = NULL;
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter }
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter (void)close(data->fd);
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter i_free(data->filepath);
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter i_free(data);
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter}
dff909d473f43a6bd0f0286fa2d279c0ebe945c6Stef Walter
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walterint mail_index_data_reset(MailIndexData *data)
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter{
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter MailIndexDataHeader hdr;
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter if (ftruncate(data->fd, sizeof(MailIndexDataHeader)) == -1) {
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter index_set_error(data->index, "ftruncate() failed for data file "
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter "%s: %m", data->filepath);
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter return FALSE;
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter }
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter memset(&hdr, 0, sizeof(hdr));
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter hdr.indexid = data->index->indexid;
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter hdr.deleted_space = 0;
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter if (lseek(data->fd, 0, SEEK_SET) == -1) {
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter index_set_error(data->index, "lseek() failed for data file "
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter "%s: %m", data->filepath);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return FALSE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter }
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (write_full(data->fd, &hdr, sizeof(hdr)) < 0) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter index_set_error(data->index, "write() failed for data file "
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter "%s: %m", data->filepath);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return FALSE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter }
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return TRUE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter
c2cc119de8eac712c040b3993f41c967ff2278deStef Waltervoid mail_index_data_new_data_notify(MailIndexData *data)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter data->dirty_mmap = TRUE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walteroff_t mail_index_data_append(MailIndexData *data, const void *buffer,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter size_t size)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter off_t pos;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert((size & (MEM_ALIGN_SIZE-1)) == 0);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter pos = lseek(data->fd, 0, SEEK_END);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (pos == -1) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter index_set_error(data->index, "lseek() failed with file %s: %m",
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter data->filepath);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return -1;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter }
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (write_full(data->fd, buffer, size) < 0) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter index_set_error(data->index, "Error appending to file %s: %m",
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter data->filepath);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return -1;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter }
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter mail_index_data_new_data_notify(data);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return pos;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter}
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterint mail_index_data_add_deleted_space(MailIndexData *data,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter unsigned int data_size)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter{
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter MailIndexDataHeader *hdr;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter off_t max_del_space;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(data->index->lock_type == MAIL_LOCK_EXCLUSIVE);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* make sure the whole file is mmaped */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (!mmap_update(data, 0, 0))
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter return FALSE;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter
hdr = data->mmap_base;
hdr->deleted_space += data_size;
/* see if we've reached the max. deleted space in file */
if (data->mmap_length >= COMPRESS_MIN_SIZE) {
max_del_space = data->mmap_length / 100 * COMPRESS_PERCENTAGE;
if (hdr->deleted_space >= max_del_space)
data->index->set_flags |= MAIL_INDEX_FLAG_COMPRESS_DATA;
}
return TRUE;
}
int mail_index_data_sync_file(MailIndexData *data)
{
if (data->mmap_base != NULL) {
if (msync(data->mmap_base, data->mmap_length, MS_SYNC) == -1) {
index_set_error(data->index, "msync() failed for "
"%s: %m", data->filepath);
return FALSE;
}
}
if (fsync(data->fd) == -1) {
index_set_error(data->index, "fsync() failed for %s: %m",
data->filepath);
return FALSE;
}
return TRUE;
}
MailIndexDataRecord *
mail_index_data_lookup(MailIndexData *data, MailIndexRecord *index_rec,
MailField field)
{
MailIndexDataRecord *rec;
off_t pos, max_pos;
if (index_rec->data_position == 0) {
index_reset_error(data->index);
return NULL;
}
if (!mmap_update(data, index_rec->data_position, index_rec->data_size))
return NULL;
max_pos = index_rec->data_position + (off_t)index_rec->data_size;
if (max_pos > (off_t)data->mmap_length) {
INDEX_MARK_CORRUPTED(data->index);
index_set_error(data->index, "Error in data file %s: "
"Given data size larger than file size "
"(%lu > %lu)", data->filepath,
(unsigned long) max_pos,
(unsigned long) data->mmap_length);
return NULL;
}
pos = index_rec->data_position;
do {
if (pos + (off_t)sizeof(MailIndexDataRecord) > max_pos) {
INDEX_MARK_CORRUPTED(data->index);
index_set_error(data->index, "Error in data file %s: "
"Index points outside file "
"(%lu > %lu)", data->filepath,
(unsigned long) pos,
(unsigned long) data->mmap_length);
break;
}
rec = (MailIndexDataRecord *) ((char *) data->mmap_base + pos);
if (pos + (off_t)DATA_RECORD_SIZE(rec) > max_pos) {
INDEX_MARK_CORRUPTED(data->index);
index_set_error(data->index, "Error in data file %s: "
"Field size points outside file "
"(%lu + %u > %lu)", data->filepath,
(unsigned long) pos,
rec->full_field_size,
(unsigned long) data->mmap_length);
break;
}
if (rec->field == field) {
/* match */
return rec;
} else if (rec->field < field) {
/* jump to next record */
pos += DATA_RECORD_SIZE(rec);
} else {
/* the fields are sorted by field type, so it's not
possible the wanted field could come after this. */
break;
}
} while (pos < max_pos);
return NULL;
}
MailIndexDataRecord *
mail_index_data_next(MailIndexData *data, MailIndexRecord *index_rec,
MailIndexDataRecord *rec)
{
off_t pos, max_pos;
if (rec == NULL)
return NULL;
/* get position to next record */
pos = DATA_FILE_POSITION(data, rec) + DATA_RECORD_SIZE(rec);
max_pos = index_rec->data_position + index_rec->data_size;
/* make sure it's within range */
if (pos >= max_pos)
return NULL;
rec = (MailIndexDataRecord *) ((char *) data->mmap_base + pos);
if (pos + (off_t)DATA_RECORD_SIZE(rec) > max_pos) {
INDEX_MARK_CORRUPTED(data->index);
index_set_error(data->index, "Error in data file %s: "
"Field size points outside file "
"(%lu + %u > %lu)", data->filepath,
(unsigned long) pos,
rec->full_field_size,
(unsigned long) data->mmap_length);
return NULL;
}
return rec;
}
int mail_index_data_record_verify(MailIndexData *data, MailIndexDataRecord *rec)
{
int i;
/* make sure the data actually contains \0 */
for (i = rec->full_field_size-1; i >= 0; i--) {
if (rec->data[i] == '\0') {
/* yes, everything ok */
return TRUE;
}
}
INDEX_MARK_CORRUPTED(data->index);
index_set_error(data->index, "Error in data file %s: "
"Missing \\0 with field %u (%lu)",
data->filepath, rec->field,
(unsigned long) DATA_FILE_POSITION(data, rec));
return FALSE;
}
void *mail_index_data_get_mmaped(MailIndexData *data, size_t *size)
{
if (!mmap_update(data, 0, UINT_MAX))
return NULL;
*size = data->mmap_length;
return data->mmap_base;
}