bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "lib.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "ioloop.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "array.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "hex-dec.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "hex-binary.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "hostpid.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "istream.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "ostream.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "file-lock.h"
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen#include "file-set-size.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mkdir-parents.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "fdatasync-path.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "eacces-error.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "str.h"
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen#include "mailbox-list-private.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mdbox-storage.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mdbox-map-private.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mdbox-file.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <stdio.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <unistd.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <ctype.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include <fcntl.h>
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic struct mdbox_file *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmdbox_find_and_move_open_file(struct mdbox_storage *storage, uint32_t file_id)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen struct mdbox_file *const *files;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen files = array_get(&storage->open_files, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++) {
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen if (files[i]->file_id == file_id)
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen return files[i];
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid mdbox_files_free(struct mdbox_storage *storage)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_file *const *files;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen files = array_get(&storage->open_files, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_file_free(&files[i]->file);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_clear(&storage->open_files);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid mdbox_files_sync_input(struct mdbox_storage *storage)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_file *const *files;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen files = array_get(&storage->open_files, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count; i++) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (files[i]->file.input != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_stream_sync(files[i]->file.input);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenmdbox_close_open_files(struct mdbox_storage *storage, unsigned int close_count)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_file *const *files;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen files = array_get(&storage->open_files, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < count;) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (files[i]->file.refcount == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_file_free(&files[i]->file);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_delete(&storage->open_files, i, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (--close_count == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen files = array_get(&storage->open_files, &count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i++;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
20d255b566be852826adf63a0e1916d201b7a619Timo Sirainenstatic void
20d255b566be852826adf63a0e1916d201b7a619Timo Sirainenmdbox_file_init_paths(struct mdbox_file *file, const char *fname, bool alt)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_free(file->file.primary_path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_free(file->file.alt_path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->file.primary_path =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_strdup_printf("%s/%s", file->storage->storage_dir, fname);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (file->storage->alt_storage_dir != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->file.alt_path =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_strdup_printf("%s/%s", file->storage->alt_storage_dir,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen fname);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
20d255b566be852826adf63a0e1916d201b7a619Timo Sirainen file->file.cur_path = !alt ? file->file.primary_path :
20d255b566be852826adf63a0e1916d201b7a619Timo Sirainen file->file.alt_path;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainenstatic int mdbox_file_create(struct mdbox_file *file)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen struct dbox_file *_file = &file->file;
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen bool create_parents;
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen int ret;
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen create_parents = dbox_file_is_in_alt(_file);
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen _file->fd = _file->storage->v.
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen file_create_fd(_file, _file->cur_path, create_parents);
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen if (_file->fd == -1)
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen return -1;
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen if (file->storage->preallocate_space) {
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen ret = file_preallocate(_file->fd,
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen file->storage->set->mdbox_rotate_size);
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen if (ret < 0) {
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen switch (errno) {
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen case ENOSPC:
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen case EDQUOT:
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen /* ignore */
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen break;
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen default:
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen i_error("file_preallocate(%s) failed: %m",
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen _file->cur_path);
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen break;
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen }
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen } else if (ret == 0) {
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen /* not supported by filesystem, disable. */
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen file->storage->preallocate_space = FALSE;
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen }
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen }
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainenstatic struct dbox_file *
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainenmdbox_file_init_full(struct mdbox_storage *storage,
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen uint32_t file_id, bool alt_dir)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_file *file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *fname;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file = file_id == 0 ? NULL :
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mdbox_find_and_move_open_file(storage, file_id);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (file != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->file.refcount++;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return &file->file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen count = array_count(&storage->open_files);
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen if (count > MDBOX_MAX_OPEN_UNUSED_FILES) {
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen mdbox_close_open_files(storage,
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen count - MDBOX_MAX_OPEN_UNUSED_FILES);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file = i_new(struct mdbox_file, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->storage = storage;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->file.storage = &storage->storage;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->file_id = file_id;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen fname = file_id == 0 ? dbox_generate_tmp_filename() :
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen t_strdup_printf(MDBOX_MAIL_FILE_FORMAT, file_id);
20d255b566be852826adf63a0e1916d201b7a619Timo Sirainen mdbox_file_init_paths(file, fname, FALSE);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_file_init(&file->file);
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen if (alt_dir)
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen file->file.cur_path = file->file.alt_path;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (file_id != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_append(&storage->open_files, &file, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else
f6aaada6101dd43cd80fe965ff1ab9bfaf776252Timo Sirainen (void)mdbox_file_create(file);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return &file->file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainenstruct dbox_file *
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainenmdbox_file_init(struct mdbox_storage *storage, uint32_t file_id)
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen{
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen return mdbox_file_init_full(storage, file_id, FALSE);
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen}
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainenstruct dbox_file *
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainenmdbox_file_init_new_alt(struct mdbox_storage *storage)
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen{
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen return mdbox_file_init_full(storage, 0, TRUE);
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen}
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mdbox_file_assign_file_id(struct mdbox_file *file, uint32_t file_id)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
dbc6f14323a634ce39f15dd7fef9ee773551dcf0Timo Sirainen struct stat st;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *old_path;
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen const char *new_dir, *new_fname, *new_path;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(file->file_id == 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(file_id != 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen old_path = file->file.cur_path;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_fname = t_strdup_printf(MDBOX_MAIL_FILE_FORMAT, file_id);
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen new_dir = !dbox_file_is_in_alt(&file->file) ?
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen file->storage->storage_dir : file->storage->alt_storage_dir;
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen new_path = t_strdup_printf("%s/%s", new_dir, new_fname);
dbc6f14323a634ce39f15dd7fef9ee773551dcf0Timo Sirainen
dbc6f14323a634ce39f15dd7fef9ee773551dcf0Timo Sirainen if (stat(new_path, &st) == 0) {
dbc6f14323a634ce39f15dd7fef9ee773551dcf0Timo Sirainen mail_storage_set_critical(&file->file.storage->storage,
dbc6f14323a634ce39f15dd7fef9ee773551dcf0Timo Sirainen "mdbox: %s already exists, rebuilding index", new_path);
dbc6f14323a634ce39f15dd7fef9ee773551dcf0Timo Sirainen mdbox_storage_set_corrupted(file->storage);
dbc6f14323a634ce39f15dd7fef9ee773551dcf0Timo Sirainen return -1;
dbc6f14323a634ce39f15dd7fef9ee773551dcf0Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (rename(old_path, new_path) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_critical(&file->storage->storage.storage,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "rename(%s, %s) failed: %m",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen old_path, new_path);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
20d255b566be852826adf63a0e1916d201b7a619Timo Sirainen mdbox_file_init_paths(file, new_fname,
20d255b566be852826adf63a0e1916d201b7a619Timo Sirainen dbox_file_is_in_alt(&file->file));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->file_id = file_id;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_append(&file->storage->open_files, &file, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainenstatic struct mdbox_file *
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainenmdbox_find_oldest_unused_file(struct mdbox_storage *storage,
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen unsigned int *idx_r)
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen{
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen struct mdbox_file *const *files, *oldest_file = NULL;
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen unsigned int i, count;
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen files = array_get(&storage->open_files, &count);
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen *idx_r = count;
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen for (i = 0; i < count; i++) {
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen if (files[i]->file.refcount == 0) {
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen if (oldest_file == NULL ||
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen files[i]->close_time < oldest_file->close_time) {
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen oldest_file = files[i];
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen *idx_r = i;
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen }
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen }
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen }
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen return oldest_file;
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen}
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainenstatic void mdbox_file_close_timeout(struct mdbox_storage *storage)
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen{
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen struct mdbox_file *oldest;
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen unsigned int i;
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen time_t close_time = ioloop_time - MDBOX_CLOSE_UNUSED_FILES_TIMEOUT_SECS;
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen while ((oldest = mdbox_find_oldest_unused_file(storage, &i)) != NULL) {
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen if (oldest->close_time > close_time)
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen break;
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen array_delete(&storage->open_files, i, 1);
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen dbox_file_free(&oldest->file);
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen }
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen if (oldest == NULL)
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen timeout_remove(&storage->to_close_unused_files);
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen}
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainenstatic void mdbox_file_close_later(struct mdbox_file *mfile)
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen{
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen if (mfile->storage->to_close_unused_files == NULL) {
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen mfile->storage->to_close_unused_files =
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen timeout_add(MDBOX_CLOSE_UNUSED_FILES_TIMEOUT_SECS*1000,
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen mdbox_file_close_timeout, mfile->storage);
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen }
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen}
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid mdbox_file_unrefed(struct dbox_file *file)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_file *mfile = (struct mdbox_file *)file;
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen struct mdbox_file *oldest_file;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* don't cache metadata seeks while file isn't being referenced */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen file->metadata_read_offset = (uoff_t)-1;
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen mfile->close_time = ioloop_time;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mfile->file_id != 0) {
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen count = array_count(&mfile->storage->open_files);
7756f8eeef47c7c9bdbc2434bc24245d89beec9aTimo Sirainen if (count <= MDBOX_MAX_OPEN_UNUSED_FILES) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* we can leave this file open for now */
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen mdbox_file_close_later(mfile);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* close the oldest file with refcount=0 */
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen oldest_file = mdbox_find_oldest_unused_file(mfile->storage, &i);
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen i_assert(oldest_file != NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_delete(&mfile->storage->open_files, i, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (oldest_file != mfile) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_file_free(&oldest_file->file);
04c3ac276103b56185119bcff9a66de7a8bb0e68Timo Sirainen mdbox_file_close_later(mfile);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* have to close ourself */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dbox_file_free(file);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint mdbox_file_create_fd(struct dbox_file *file, const char *path, bool parents)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mdbox_file *mfile = (struct mdbox_file *)file;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen struct mdbox_map *map = mfile->storage->map;
fca7aa88ab19375aba5a8fd9d4100ea885dccb68Timo Sirainen struct mailbox_permissions perm;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mode_t old_mask;
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen const char *p, *dir;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen int fd;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
fca7aa88ab19375aba5a8fd9d4100ea885dccb68Timo Sirainen mailbox_list_get_root_permissions(map->root_list, &perm);
fca7aa88ab19375aba5a8fd9d4100ea885dccb68Timo Sirainen
fca7aa88ab19375aba5a8fd9d4100ea885dccb68Timo Sirainen old_mask = umask(0666 & ~perm.file_create_mode);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen umask(old_mask);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (fd == -1 && errno == ENOENT && parents &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (p = strrchr(path, '/')) != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dir = t_strdup_until(path, p);
be110f0a3888a24282f06820ec0b5068d2b8f906Timo Sirainen if (mailbox_list_mkdir_root(map->root_list, dir,
be110f0a3888a24282f06820ec0b5068d2b8f906Timo Sirainen path != file->alt_path ?
be110f0a3888a24282f06820ec0b5068d2b8f906Timo Sirainen MAILBOX_LIST_PATH_TYPE_DIR :
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen MAILBOX_LIST_PATH_TYPE_ALT_DIR) < 0) {
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen mail_storage_copy_list_error(&file->storage->storage,
94f84d1c3f786d1b92dd2a1507f83a2dad887c56Timo Sirainen map->root_list);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* try again */
fca7aa88ab19375aba5a8fd9d4100ea885dccb68Timo Sirainen old_mask = umask(0666 & ~perm.file_create_mode);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen umask(old_mask);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (fd == -1) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_critical(&file->storage->storage,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "open(%s, O_CREAT) failed: %m", path);
fca7aa88ab19375aba5a8fd9d4100ea885dccb68Timo Sirainen } else if (perm.file_create_gid == (gid_t)-1) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* no group change */
fca7aa88ab19375aba5a8fd9d4100ea885dccb68Timo Sirainen } else if (fchown(fd, (uid_t)-1, perm.file_create_gid) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (errno == EPERM) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_critical(&file->storage->storage, "%s",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen eperm_error_get_chgrp("fchown", path,
fca7aa88ab19375aba5a8fd9d4100ea885dccb68Timo Sirainen perm.file_create_gid,
fca7aa88ab19375aba5a8fd9d4100ea885dccb68Timo Sirainen perm.file_create_gid_origin));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_storage_set_critical(&file->storage->storage,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "fchown(%s, -1, %ld) failed: %m",
fca7aa88ab19375aba5a8fd9d4100ea885dccb68Timo Sirainen path, (long)perm.file_create_gid);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* continue anyway */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return fd;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}