Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-storage/index/dbox/dbox-file.c @ 6162:896cc473c1f0 HEAD
Renamed i_stream_create_file() to i_stream_create_fd().
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 02 Aug 2007 18:27:46 +0300 |
parents | 6c0bfc35af03 |
children | 5f66277bbe40 |
line wrap: on
line source
/* Copyright (C) 2005-2006 Timo Sirainen */ #include "lib.h" #include "array.h" #include "bsearch-insert-pos.h" #include "hex-dec.h" #include "istream.h" #include "ostream.h" #include "read-full.h" #include "dbox-storage.h" #include "dbox-file.h" int dbox_file_lookup_offset(struct dbox_mailbox *mbox, struct mail_index_view *view, uint32_t seq, uint32_t *file_seq_r, uoff_t *offset_r) { const void *data1, *data2; int ret; ret = mail_index_lookup_ext(view, seq, mbox->dbox_file_ext_idx, &data1); ret = ret <= 0 ? ret : mail_index_lookup_ext(view, seq, mbox->dbox_offset_ext_idx, &data2); if (ret <= 0) { if (ret < 0) mail_storage_set_index_error(&mbox->ibox); return ret; } if (data1 == NULL || data2 == NULL) { *file_seq_r = 0; return 1; } /* success */ *file_seq_r = *((const uint32_t *)data1); *offset_r = *((const uint64_t *)data2); return 1; } void dbox_file_close(struct dbox_file *file) { if (array_is_created(&file->file_idx_keywords)) { array_free(&file->idx_file_keywords); array_free(&file->file_idx_keywords); } if (file->input != NULL) i_stream_destroy(&file->input); if (file->fd != -1) { if (close(file->fd) < 0) i_error("close(dbox) failed: %m"); } i_free(file->seeked_keywords); i_free(file->path); i_free(file); } static int dbox_file_read_mail_header(struct dbox_mailbox *mbox, struct dbox_file *file, uoff_t offset) { const struct dbox_mail_header *hdr; const unsigned char *data; size_t size; /* read the header */ i_stream_seek(file->input, offset); (void)i_stream_read_data(file->input, &data, &size, file->mail_header_size-1); if (size < file->mail_header_size) { if (file->input->stream_errno == 0) return 0; errno = file->input->stream_errno; mail_storage_set_critical(&mbox->storage->storage, "read(%s) failed: %m", file->path); return -1; } memcpy(&file->seeked_mail_header, data, sizeof(file->seeked_mail_header)); /* @UNSAFE */ memcpy(file->seeked_keywords, data + sizeof(file->seeked_mail_header), file->keyword_count); file->seeked_offset = offset; /* parse the header */ hdr = &file->seeked_mail_header; file->seeked_mail_size = hex2dec(hdr->mail_size_hex, sizeof(hdr->mail_size_hex)); file->seeked_uid = hex2dec(hdr->uid_hex, sizeof(hdr->uid_hex)); if (memcmp(hdr->magic, DBOX_MAIL_HEADER_MAGIC, sizeof(hdr->magic)) != 0) { mail_storage_set_critical(&mbox->storage->storage, "Corrupted mail header at %"PRIuUOFF_T " in dbox file %s", offset, file->path); return -1; } return 1; } int dbox_file_seek(struct dbox_mailbox *mbox, uint32_t file_seq, uoff_t offset, bool ignore_zero_uid) { int ret; if (mbox->file != NULL && mbox->file->file_seq != file_seq) { dbox_file_close(mbox->file); mbox->file = NULL; } if (mbox->file == NULL) { mbox->file = i_new(struct dbox_file, 1); mbox->file->file_seq = file_seq; mbox->file->fd = -1; mbox->file->path = i_strdup_printf("%s/"DBOX_MAIL_FILE_FORMAT, mbox->path, file_seq); } if (mbox->file->fd == -1) { mbox->file->fd = open(mbox->file->path, O_RDWR); if (mbox->file->fd == -1) { if (errno == ENOENT) return 0; mail_storage_set_critical(&mbox->storage->storage, "open(%s) failed: %m", mbox->file->path); return -1; } mbox->file->input = i_stream_create_fd(mbox->file->fd, 65536, FALSE); if (dbox_file_read_header(mbox, mbox->file) < 0) return -1; } else { /* make sure we're not caching outdated data */ i_stream_sync(mbox->file->input); } if (offset == 0) offset = mbox->file->header_size; if ((ret = dbox_file_read_mail_header(mbox, mbox->file, offset)) <= 0) return ret; if (mbox->file->seeked_mail_size == 0 || (mbox->file->seeked_uid == 0 && !ignore_zero_uid)) { /* could be legitimately just not written yet. we're at EOF. */ return 0; } return 1; } int dbox_file_seek_next_nonexpunged(struct dbox_mailbox *mbox) { const struct dbox_mail_header *hdr; uoff_t offset; int ret; for (;;) { offset = mbox->file->seeked_offset + mbox->file->mail_header_size + mbox->file->seeked_mail_size; ret = dbox_file_seek(mbox, mbox->file->file_seq, offset, FALSE); if (ret <= 0) return ret; hdr = &mbox->file->seeked_mail_header; if (hdr->expunged != '1') { /* non-expunged mail found */ break; } } return 1; } void dbox_file_header_init(struct dbox_file_header *hdr) { uint16_t base_header_size = sizeof(*hdr); uint32_t header_size = base_header_size + DBOX_KEYWORD_NAMES_RESERVED_SPACE; uint32_t append_offset = header_size; uint16_t keyword_count = DBOX_KEYWORD_COUNT; uint16_t mail_header_size = sizeof(struct dbox_mail_header) + keyword_count; uint32_t create_time = ioloop_time; memset(hdr, '0', sizeof(*hdr)); DEC2HEX(hdr->base_header_size_hex, base_header_size); DEC2HEX(hdr->header_size_hex, header_size); DEC2HEX(hdr->append_offset_hex, append_offset); DEC2HEX(hdr->create_time_hex, create_time); DEC2HEX(hdr->mail_header_size_hex, mail_header_size); DEC2HEX(hdr->keyword_list_offset_hex, base_header_size); DEC2HEX(hdr->keyword_count_hex, keyword_count); } int dbox_file_header_parse(struct dbox_mailbox *mbox, struct dbox_file *file, const struct dbox_file_header *hdr) { file->hdr = *hdr; file->base_header_size = hex2dec(hdr->base_header_size_hex, sizeof(hdr->base_header_size_hex)); file->header_size = hex2dec(hdr->header_size_hex, sizeof(hdr->header_size_hex)); file->append_offset = hex2dec(hdr->append_offset_hex, sizeof(hdr->append_offset_hex)); file->create_time = hex2dec(hdr->create_time_hex, sizeof(hdr->create_time_hex)); file->mail_header_size = hex2dec(hdr->mail_header_size_hex, sizeof(hdr->mail_header_size_hex)); file->mail_header_align = hex2dec(hdr->mail_header_align_hex, sizeof(hdr->mail_header_align_hex)); file->keyword_count = hex2dec(hdr->keyword_count_hex, sizeof(hdr->keyword_count_hex)); file->keyword_list_offset = hex2dec(hdr->keyword_list_offset_hex, sizeof(hdr->keyword_list_offset_hex)); if (file->base_header_size == 0 || file->header_size < file->base_header_size || file->append_offset < file->header_size || file->keyword_list_offset < file->base_header_size || file->mail_header_size < sizeof(struct dbox_mail_header) || file->keyword_count > file->mail_header_size - sizeof(struct dbox_mail_header)) { mail_storage_set_critical(&mbox->storage->storage, "dbox %s: broken file header", file->path); return -1; } i_free(file->seeked_keywords); file->seeked_keywords = file->keyword_count == 0 ? NULL : i_malloc(file->keyword_count); return 0; } int dbox_file_read_header(struct dbox_mailbox *mbox, struct dbox_file *file) { struct dbox_file_header hdr; const unsigned char *data; size_t size; /* read the file header */ i_stream_seek(file->input, 0); (void)i_stream_read_data(file->input, &data, &size, sizeof(hdr)-1); if (size < sizeof(hdr)) { if (file->input->stream_errno != 0) { errno = file->input->stream_errno; mail_storage_set_critical(&mbox->storage->storage, "read(%s) failed: %m", file->path); return -1; } mail_storage_set_critical(&mbox->storage->storage, "dbox %s: unexpected end of file", file->path); return -1; } memcpy(&hdr, data, sizeof(hdr)); /* parse the header */ if (dbox_file_header_parse(mbox, file, &hdr) < 0) return -1; /* keywords may not be up to date anymore */ if (array_is_created(&file->idx_file_keywords)) { array_free(&file->idx_file_keywords); array_free(&file->file_idx_keywords); } return 0; } int dbox_file_write_header(struct dbox_mailbox *mbox, struct dbox_file *file) { struct dbox_file_header hdr; char buf[1024]; int ret; dbox_file_header_init(&hdr); ret = dbox_file_header_parse(mbox, file, &hdr); i_assert(ret == 0); /* write header + LF to mark end-of-keywords list */ if (o_stream_send(file->output, &hdr, sizeof(hdr)) < 0 || o_stream_send_str(file->output, "\n") < 0) { mail_storage_set_critical(&mbox->storage->storage, "write(%s) failed: %m", file->path); return -1; } /* fill the rest of the header with spaces */ memset(buf, ' ', sizeof(buf)); while (file->output->offset < file->header_size) { unsigned int size = I_MIN(sizeof(buf), file->header_size - file->output->offset); if (o_stream_send(file->output, buf, size) < 0) { mail_storage_set_critical(&mbox->storage->storage, "write(%s) failed: %m", file->path); return -1; } } return 0; }