/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "ostream.h"
#include "nfs-workarounds.h"
#include "read-full.h"
#include "file-dotlock.h"
#include "file-cache.h"
#include "file-set-size.h"
#include "mail-cache-private.h"
#include <stdio.h>
struct mail_cache_copy_context {
bool new_msg;
};
struct mail_cache_compress_lock {
};
static void
const struct mail_cache_iterate_field *field)
{
unsigned char *dest;
unsigned int i, *pos;
if (*pos == 0) {
/* we decided to drop this field */
return;
}
}
static void
const struct mail_cache_iterate_field *field)
{
return;
/* duplicate */
return;
}
if (dec == MAIL_CACHE_DECISION_NO)
return;
} else {
if (dec != MAIL_CACHE_DECISION_YES)
return;
}
}
/* remember the position in case we need to update it */
}
}
{
/* make sure we look up the latest reset_id */
return -1;
}
static void
unsigned int used_fields_count)
{
unsigned int i, j, idx;
/* Make mail_cache_header_fields_get() return the fields in
the same order as we saved them. */
/* reverse mapping */
i_new(unsigned int, used_fields_count);
for (i = j = 0; i < cache->fields_count; i++) {
j++;
}
/* change permanent decisions to temporary decisions.
if they're still permanent they'll get updated later. */
}
i_assert(j == used_fields_count);
}
static int
{
*max_uid_r = 0;
/* get the latest info on fields */
if (mail_cache_header_fields_read(cache) < 0)
return -1;
ctx.field_seen_value = 0;
/* @UNSAFE: drop unused fields and create a field mapping for
used fields */
if (cache->file_fields_count == 0) {
/* creating the initial cache file. add all fields. */
for (i = 0; i < orig_fields_count; i++)
ctx.field_file_map[i] = i;
used_fields_count = i;
} else {
for (i = used_fields_count = 0; i < orig_fields_count; i++) {
/* if the decision isn't forced and this field hasn't
been accessed for a while, drop it */
if ((dec & MAIL_CACHE_DECISION_FORCED) == 0 &&
}
/* drop all fields we don't want */
if ((dec & ~MAIL_CACHE_DECISION_FORCED) ==
}
}
}
/* get sequence of first message which doesn't need its temp fields
removed. */
continue;
}
if (++ctx.field_seen_value == 0) {
}
/* nothing cached */
ext_offset = 0;
} else {
sizeof(cache_rec));
record_count++;
}
}
(void)o_stream_seek(output, 0);
if (o_stream_finish(output) < 0) {
return -1;
}
return -1;
}
}
return 0;
}
static int
struct mail_index_transaction *trans,
{
unsigned int i, count;
&max_uid, &ext_offsets) < 0)
return -1;
return -1;
}
return -1;
}
i_debug("%s: Compressed, file_seq changed %u -> %u, "
}
/* once we're sure that the compression was successful,
update the offsets */
for (i = 0; i < count; i++) {
if (offsets[i] != 0) {
&offsets[i], &old_offset);
}
}
if (*unlock) {
(void)mail_cache_unlock(cache);
}
return 0;
}
{
unsigned int i;
for (i = 0;; i++) {
if (fd == -1) {
return 0;
return -1;
}
i_close_fd(&fd);
if (ret >= 0) {
if (ret == 0)
return 0;
if (cache->need_compress_file_seq == 0) {
/* previously it didn't exist or it
was unusable and was just unlinked */
return 1;
}
return -1;
}
}
}
{
DOTLOCK_CREATE_FLAG_NONBLOCK, dotlock_r) <= 0) {
return -1;
}
return 0;
}
struct mail_index_transaction *trans,
{
const char *temp_path;
const void *data;
/* There are two possible locking situations here:
a) Cache is locked against any modifications.
b) Cache doesn't exist or is unusable. There's no lock.
Because the cache lock itself is unreliable, we'll be using a
separate dotlock to guard against two processes compressing the
cache at the same time. */
return -1;
/* we've locked the cache compression now. if somebody else had just
recreated the cache, reopen the cache and return success. */
if (ret < 0)
return -1;
/* was just compressed, forget this */
cache->need_compress_file_seq = 0;
if (*unlock) {
(void)mail_cache_unlock(cache);
}
}
/* make sure we have mapped it before reading. */
return -1;
}
/* we want to recreate the cache. write it first to a temporary file */
if (fd == -1)
return -1;
i_close_fd(&fd);
return -1;
}
return -1;
if (mail_cache_header_fields_read(cache) < 0)
return -1;
cache->need_compress_file_seq = 0;
return 0;
}
struct mail_index_transaction *trans,
struct mail_cache_compress_lock **lock_r)
{
int ret;
return 0;
}
/* compression isn't very efficient with small read()s */
if (cache->map_with_read) {
cache->mmap_length = 0;
}
/* we're using dotlocking, cache file creation itself creates
the dotlock file we need. */
if (!MAIL_CACHE_IS_UNUSABLE(cache)) {
FALSE);
}
} else {
switch (mail_cache_try_lock(cache)) {
case -1:
/* already locked or some other error */
return -1;
case 0:
/* cache is broken or doesn't exist.
just start creating it. */
break;
default:
/* locking succeeded. */
}
}
if (unlock) {
if (mail_cache_unlock(cache) < 0)
ret = -1;
}
if (ret < 0) {
/* the fields may have been updated in memory already.
reverse those changes by re-reading them from file. */
(void)mail_cache_header_fields_read(cache);
} else {
}
return ret;
}
{
}
{
return cache->need_compress_file_seq != 0 &&
}