dbox-file.c revision ded851166b85350bbfbe8bcf28996c1fc1c9e8be
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2007-2010 Dovecot authors, see the included COPYING file */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen static unsigned int create_count = 0;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return t_strdup_printf("temp.%lu.P%sQ%uM%u.%s",
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid dbox_file_set_syscall_error(struct dbox_file *file, const char *function)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen mail_storage_set_critical(&file->storage->storage,
04870054863757edf048c81dcce3c5e7dec453cdTimo Sirainen "%s failed for file %s: %m",
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid dbox_file_set_corrupted(struct dbox_file *file, const char *reason, ...)
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen mail_storage_set_critical(&file->storage->storage,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "Corrupted dbox file %s (around offset=%"PRIuUOFF_T"): %s",
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen file->cur_path, file->input == NULL ? 0 : file->input->v_offset,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int dbox_file_parse_header(struct dbox_file *file, const char *line)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen unsigned int pos;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen (file->file_version != 1 && file->file_version != DBOX_VERSION)) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen dbox_file_set_corrupted(file, "Invalid dbox version");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen for (tmp = t_strsplit(line, " "); *tmp != NULL; tmp++) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen file->msg_header_size = strtoul(value, NULL, 16);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen dbox_file_set_corrupted(file, "Missing message header size");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int dbox_file_read_header(struct dbox_file *file)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "EOF while reading file header");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ret = dbox_file_parse_header(file, line) < 0 ? 0 : 1;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int dbox_file_open_fd(struct dbox_file *file, bool try_altpath)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* try the primary path first */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen while ((file->fd = open(path, O_RDWR)) == -1) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen mail_storage_set_critical(&file->storage->storage,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (file->alt_path == NULL || alt || !try_altpath) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* not found */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* try the alternative path */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenstatic int dbox_file_open_full(struct dbox_file *file, bool try_altpath,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen file->input = i_stream_create_fd(file->fd, 0, FALSE);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_stream_set_name(file->input, file->cur_path);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_stream_set_init_buffer_size(file->input, DBOX_READ_BLOCK_SIZE);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenint dbox_file_open(struct dbox_file *file, bool *deleted_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return dbox_file_open_full(file, TRUE, deleted_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenint dbox_file_open_primary(struct dbox_file *file, bool *notfound_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen return dbox_file_open_full(file, FALSE, notfound_r);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenint dbox_file_stat(struct dbox_file *file, struct stat *st_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen mail_storage_set_critical(&file->storage->storage,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* try the primary path first */
63110c906fdb5b4e8c870e76fa3f244dac4b043dTimo Sirainen mail_storage_set_critical(&file->storage->storage,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* not found */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* try the alternative path */
e1203014de25c8c3d3975a9f4b4a04616df4bba2Timo Sirainenint dbox_file_header_write(struct dbox_file *file, struct ostream *output)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen str_printfa(hdr, "%u %c%x %c%x\n", DBOX_VERSION,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen (unsigned int)sizeof(struct dbox_message_header),
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen DBOX_HEADER_CREATE_STAMP, (unsigned int)ioloop_time);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen file->msg_header_size = sizeof(struct dbox_message_header);
e1dd1ec5a9d6c857697e7c72844822452bf1e1a0Timo Sirainen return o_stream_send(output, str_data(hdr), str_len(hdr));
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ret = file_try_lock(file->fd, file->cur_path, F_WRLCK,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen mail_storage_set_critical(&file->storage->storage,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen "file_try_lock(%s) failed: %m", file->cur_path);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen i_assert(!file->appending || file->lock == NULL);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenint dbox_file_read_mail_header(struct dbox_file *file, uoff_t *physical_size_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen const unsigned char *data;
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen ret = i_stream_read_data(file->input, &data, &size,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* EOF, broken offset or file truncated */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen dbox_file_set_corrupted(file, "EOF reading msg header "
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen memcpy(&hdr, data, I_MIN(sizeof(hdr), file->msg_header_size));
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen if (memcmp(hdr.magic_pre, DBOX_MAGIC_PRE, sizeof(hdr.magic_pre)) != 0) {
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen /* probably broken offset */
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen dbox_file_set_corrupted(file, "msg header has bad magic value");
e5b723864630e40c9028808ef417dd3d6fbf495bTimo Sirainen dbox_file_set_corrupted(file, "msg header doesn't end with LF");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen *physical_size_r = hex2dec(hdr.message_size_hex,
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainenint dbox_file_get_mail_stream(struct dbox_file *file, uoff_t offset,
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen ret = dbox_file_read_mail_header(file, &size);
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen i_stream_seek(file->input, offset + file->msg_header_size);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen *stream_r = i_stream_create_limit(file->input,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainendbox_file_seek_next_at_metadata(struct dbox_file *file, uoff_t *offset)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if ((ret = dbox_file_metadata_skip_header(file)) <= 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* skip over the actual metadata */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen while ((line = i_stream_read_next_line(file->input)) != NULL) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (*line == DBOX_METADATA_OLDV1_SPACE || *line == '\0') {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* end of metadata */
dd71e3d8d6284a4f80ddf010ee4316f688169b58Timo Sirainenvoid dbox_file_seek_rewind(struct dbox_file *file)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenint dbox_file_seek_next(struct dbox_file *file, uoff_t *offset_r, bool *last_r)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* first mail. we may not have read the file at all yet,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen so set the offset afterwards. */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen offset = file->cur_offset + file->msg_header_size +
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if ((ret = dbox_file_seek_next_at_metadata(file, &offset)) <= 0) {
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainen ret = dbox_file_get_mail_stream(file, offset, NULL);
c3d40f3092af25cad9e807a85eaad4d92aab107bTimo Sirainenstruct dbox_file_append_context *dbox_file_append_init(struct dbox_file *file)
dd71e3d8d6284a4f80ddf010ee4316f688169b58Timo Sirainen ctx = i_new(struct dbox_file_append_context, 1);
dd71e3d8d6284a4f80ddf010ee4316f688169b58Timo Sirainen ctx->output = o_stream_create_fd_file(file->fd, 0, FALSE);
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenint dbox_file_append_commit(struct dbox_file_append_context **_ctx)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenvoid dbox_file_append_rollback(struct dbox_file_append_context **_ctx)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* nothing changed */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen } else if (ctx->first_append_offset == file->file_header_size) {
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* rollbacking everything */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen dbox_file_set_syscall_error(file, "unlink()");
714e2da5096fb52b8845d3c79f9bb26225a606c9Timo Sirainen /* truncating only some mails */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ftruncate(file->fd, ctx->first_append_offset) < 0)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen dbox_file_set_syscall_error(file, "ftruncate()");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenint dbox_file_append_flush(struct dbox_file_append_context *ctx)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen if (ctx->last_flush_offset == ctx->output->offset)
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen dbox_file_set_syscall_error(ctx->file, "write()");
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen if (!ctx->file->storage->storage.set->fsync_disable) {
6882df5fbca4a09cdaa95f54d70bb31b5920528cTimo Sirainen dbox_file_set_syscall_error(ctx->file, "fdatasync()");
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainenint dbox_file_get_append_stream(struct dbox_file_append_context *ctx,
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* file creation had failed */
02a54da28f376dd66d7939d8546a196a0045b486Timo Sirainen /* newly created file, write the file header */
const unsigned char *data;
int ret;
if (ret <= 0) {
const char *line;
int ret;
return ret;
ret = 0;
if (ret == 0)
return ret;
int ret;
if (ret <= 0)
return ret;
const char *const *metadata;
unsigned int i, count;
for (i = 0; i < count; i++) {
return NULL;
bool deleted;
if (ret == 0)
} else if (ret < 0) {
if (ret < 0) {
const char *path;