uint32_t file_seq, old_offset;
ARRAY_TYPE(uint32_t) ext_offsets;
const uint32_t *offsets;
+ const void *data;
unsigned int i, count;
int fd, ret;
if (cache->file_cache != NULL)
file_cache_set_fd(cache->file_cache, cache->fd);
- if (mail_cache_map(cache, 0, 0) < 0)
+ if (mail_cache_map(cache, 0, 0, &data) < 0)
return -1;
if (mail_cache_header_fields_read(cache) < 0)
return -1;
return list;
}
-static int mail_cache_header_fields_get_offset(struct mail_cache *cache,
- uint32_t *offset_r, bool map)
+static int
+mail_cache_header_fields_get_offset(struct mail_cache *cache,
+ uint32_t *offset_r,
+ const struct mail_cache_header_fields **field_hdr_r)
{
const struct mail_cache_header_fields *field_hdr;
struct mail_cache_header_fields tmp_field_hdr;
+ const void *data;
uint32_t offset = 0, next_offset;
unsigned int next_count = 0;
bool invalidate = FALSE;
if (MAIL_CACHE_IS_UNUSABLE(cache)) {
*offset_r = 0;
+ if (field_hdr_r != NULL)
+ *field_hdr_r = NULL;
return 0;
}
invalidate = TRUE;
if (cache->mmap_base != NULL) {
- if (mail_cache_map(cache, offset,
- sizeof(*field_hdr)) < 0)
- return -1;
- if (offset >= cache->mmap_length) {
+ ret = mail_cache_map(cache, offset, sizeof(*field_hdr),
+ &data);
+ if (ret <= 0) {
+ if (ret < 0)
+ return -1;
mail_cache_set_corrupted(cache,
"header field next_offset points outside file");
return -1;
}
-
- field_hdr = CONST_PTR_OFFSET(cache->data, offset);
+ field_hdr = data;
} else {
/* if we need to follow multiple offsets to get to
the last one, it's faster to just pread() the file
if (next_count > MAIL_CACHE_HEADER_FIELD_CONTINUE_COUNT)
cache->need_compress_file_seq = cache->hdr->file_seq;
- if (map) {
+ if (field_hdr_r != NULL) {
if (cache->file_cache != NULL && invalidate) {
/* if this isn't the first header in file and we hadn't
read this before, we can't trust that the cached
file_cache_invalidate(cache->file_cache, offset,
field_hdr->size);
}
- if (mail_cache_map(cache, offset, field_hdr->size) < 0)
+ ret = mail_cache_map(cache, offset, field_hdr->size, &data);
+ if (ret < 0)
return -1;
+ if (ret == 0) {
+ mail_cache_set_corrupted(cache,
+ "header field size outside file");
+ return -1;
+ }
+ *field_hdr_r = data;
}
-
*offset_r = offset;
return 0;
}
int mail_cache_header_fields_read(struct mail_cache *cache)
{
- const struct mail_cache_header_fields *field_hdr = NULL;
+ const struct mail_cache_header_fields *field_hdr;
struct mail_cache_field field;
const uint32_t *last_used, *sizes;
const uint8_t *types, *decisions;
time_t max_drop_time;
uint32_t offset, i;
- if (mail_cache_header_fields_get_offset(cache, &offset, TRUE) < 0)
+ if (mail_cache_header_fields_get_offset(cache, &offset, &field_hdr) < 0)
return -1;
if (offset == 0) {
return 0;
}
- field_hdr = CONST_PTR_OFFSET(cache->data, offset);
- if (offset + field_hdr->size > cache->mmap_length) {
- mail_cache_set_corrupted(cache,
- "field header points outside file");
- return -1;
- }
-
/* check the fixed size of the header. name[] has to be checked
separately */
if (field_hdr->size < sizeof(*field_hdr) +
return -1;
}
- field_hdr = CONST_PTR_OFFSET(cache->data, offset);
new_fields_count = field_hdr->fields_count;
-
if (new_fields_count != 0) {
cache->file_field_map =
i_realloc(cache->file_field_map,
const struct mail_cache_record **rec_r)
{
const struct mail_cache_record *rec;
+ const void *data;
i_assert(offset != 0);
}
/* we don't know yet how large the record is, so just guess */
- if (mail_cache_map(cache, offset, sizeof(*rec) + CACHE_PREFETCH) < 0)
+ if (mail_cache_map(cache, offset, sizeof(*rec) + CACHE_PREFETCH,
+ &data) < 0)
return -1;
if (offset + sizeof(*rec) > cache->mmap_length) {
mail_cache_set_corrupted(cache, "record points outside file");
return -1;
}
- rec = CACHE_RECORD(cache, offset);
+ rec = data;
if (rec->size < sizeof(*rec)) {
mail_cache_set_corrupted(cache, "invalid record size");
}
if (rec->size > CACHE_PREFETCH) {
/* larger than we guessed. map the rest of the record. */
- if (mail_cache_map(cache, offset, rec->size) < 0)
+ if (mail_cache_map(cache, offset, rec->size, &data) < 0)
return -1;
- rec = CACHE_RECORD(cache, offset);
+ rec = data;
}
if (rec->size > cache->mmap_length ||
int mail_cache_lookup_iter_next(struct mail_cache_lookup_iterate_ctx *ctx,
struct mail_cache_iterate_field *field_r);
-int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size);
+int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size,
+ const void **data_r);
void mail_cache_file_close(struct mail_cache *cache);
int mail_cache_reopen(struct mail_cache *cache);
uint32_t new_offset)
{
const struct mail_cache_record *rec;
+ const void *data;
+ int ret;
i_assert(cache->locked);
records at the same time. we'd rather not lose those additions, so
force the linking order to be new_offset -> old_offset if it isn't
already. */
- if (mail_cache_map(cache, new_offset, sizeof(*rec)) < 0)
- return -1;
- if (new_offset + sizeof(*rec) > cache->mmap_length) {
- mail_cache_set_corrupted(cache,
- "Cache record offset %u points outside file",
- new_offset);
+ ret = mail_cache_map(cache, new_offset, sizeof(*rec), &data);
+ if (ret <= 0) {
+ if (ret == 0) {
+ mail_cache_set_corrupted(cache,
+ "Cache record offset %u points outside file",
+ new_offset);
+ }
return -1;
}
- rec = CACHE_RECORD(cache, new_offset);
+ rec = data;
if (rec->prev_offset == old_offset) {
/* link is already correct */
return 0;
{
struct mail_index_view *view;
const struct mail_index_ext *ext;
+ const void *data;
i_assert(!cache->locked);
mail_cache_init_file_cache(cache);
- if (mail_cache_map(cache, 0, 0) < 0)
+ if (mail_cache_map(cache, 0, 0, &data) < 0)
return -1;
if (mail_cache_header_fields_read(cache) < 0)
return TRUE;
}
-int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size)
+int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size,
+ const void **data_r)
{
+ const void *data;
ssize_t ret;
cache->remap_counter++;
cache->hdr = &cache->hdr_ro_copy;
if (offset == 0)
mail_cache_update_need_compress(cache);
- return 0;
+
+ data = file_cache_get_map(cache->file_cache,
+ &cache->mmap_length);
+ if (offset > cache->mmap_length) {
+ *data_r = NULL;
+ return 0;
+ }
+ *data_r = CONST_PTR_OFFSET(data, offset);
+ return offset + size > cache->mmap_length ? 0 : 1;
}
if (offset < cache->mmap_length &&
size <= cache->mmap_length - offset) {
/* already mapped */
- return 0;
+ *data_r = CONST_PTR_OFFSET(cache->mmap_base, offset);
+ return 1;
}
if (cache->mmap_base != NULL) {
cache->hdr = cache->data;
if (offset == 0)
mail_cache_update_need_compress(cache);
- return 0;
+ if (offset > cache->mmap_length) {
+ *data_r = NULL;
+ return 0;
+ }
+ *data_r = CONST_PTR_OFFSET(cache->mmap_base, offset);
+ return offset + size > cache->mmap_length ? 0 : 1;
}
static int mail_cache_try_open(struct mail_cache *cache)
{
+ const void *data;
+
cache->opened = TRUE;
if (MAIL_INDEX_IS_IN_MEMORY(cache->index))
mail_cache_init_file_cache(cache);
- if (mail_cache_map(cache, 0, sizeof(struct mail_cache_header)) < 0)
+ if (mail_cache_map(cache, 0, sizeof(struct mail_cache_header),
+ &data) < 0)
return -1;
-
return 1;
}
bool nonblock)
{
const struct mail_index_ext *ext;
+ const void *data;
struct mail_index_view *iview;
uint32_t reset_id;
int i, ret;
file_cache_invalidate(cache->file_cache, 0,
sizeof(struct mail_cache_header));
}
- if (mail_cache_map(cache, 0, 0) == 0)
+ if (mail_cache_map(cache, 0, 0, &data) == 0)
cache->hdr_copy = *cache->hdr;
else {
(void)mail_cache_unlock(cache);